diff options
Diffstat (limited to 'drivers/net')
467 files changed, 63901 insertions, 29794 deletions
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 5ba4bab6d43..7d15e7c6bca 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -17,7 +17,7 @@ Annapolis MD 21403 Fixed (again!) the missing interrupt locking on TX/RX shifting. - Alan Cox <Alan.Cox@linux.org> + Alan Cox <alan@lxorguk.ukuu.org.uk> Removed calls to init_etherdev since they are no longer needed, and cleaned up modularization just a bit. The driver still allows only @@ -29,16 +29,16 @@ the board. Now getting 150K/second FTP with a 3c501 card. Still playing with a TX-TX optimisation to see if we can touch 180-200K/second as seems theoretically maximum. - 19950402 Alan Cox <Alan.Cox@linux.org> + 19950402 Alan Cox <alan@lxorguk.ukuu.org.uk> Cleaned up for 2.3.x because we broke SMP now. - 20000208 Alan Cox <alan@redhat.com> + 20000208 Alan Cox <alan@lxorguk.ukuu.org.uk> Check up pass for 2.5. Nothing significant changed - 20021009 Alan Cox <alan@redhat.com> + 20021009 Alan Cox <alan@lxorguk.ukuu.org.uk> Fixed zero fill corner case - 20030104 Alan Cox <alan@redhat.com> + 20030104 Alan Cox <alan@lxorguk.ukuu.org.uk> For the avoidance of doubt the "preferred form" of this code is one which @@ -104,7 +104,7 @@ static const char version[] = - DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@redhat.com).\n"; + DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@lxorguk.ukuu.org.uk).\n"; /* * Braindamage remaining: diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index fdfb2b2cb73..a424869707a 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -130,12 +130,12 @@ static const char filename[] = __FILE__; static const char timeout_msg[] = "*** timeout at %s:%s (line %d) ***\n"; #define TIMEOUT_MSG(lineno) \ - printk(timeout_msg, filename,__FUNCTION__,(lineno)) + printk(timeout_msg, filename,__func__,(lineno)) static const char invalid_pcb_msg[] = "*** invalid pcb length %d at %s:%s (line %d) ***\n"; #define INVALID_PCB_MSG(len) \ - printk(invalid_pcb_msg, (len),filename,__FUNCTION__,__LINE__) + printk(invalid_pcb_msg, (len),filename,__func__,__LINE__) static char search_msg[] __initdata = KERN_INFO "%s: Looking for 3c505 adapter at address %#x..."; diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index b9d097c9f6b..3a7bc524af3 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -40,7 +40,7 @@ v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb v1.15 1/31/98 Faster recovery for Tx errors. -djb v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb - v1.18 12Mar2001 Andrew Morton <andrewm@uow.edu.au> + v1.18 12Mar2001 Andrew Morton - Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz) - Reviewed against 1.18 from scyld.com v1.18a 17Nov2001 Jeff Garzik <jgarzik@pobox.com> diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index e4e3241628d..a0f8b6e2d0a 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -18,7 +18,7 @@ 2001/11/17 - Added ethtool support (jgarzik) - 2002/10/28 - Locking updates for 2.5 (alan@redhat.com) + 2002/10/28 - Locking updates for 2.5 (alan@lxorguk.ukuu.org.uk) */ diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 6011d6fabef..85fa40a0a66 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -127,7 +127,6 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered mu (CP)->tx_tail - (CP)->tx_head - 1) #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -#define RX_OFFSET 2 #define CP_INTERNAL_PHY 32 /* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ @@ -552,14 +551,14 @@ rx_status_loop: printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n", dev->name, rx_tail, status, len); - buflen = cp->rx_buf_sz + RX_OFFSET; - new_skb = dev_alloc_skb (buflen); + buflen = cp->rx_buf_sz + NET_IP_ALIGN; + new_skb = netdev_alloc_skb(dev, buflen); if (!new_skb) { dev->stats.rx_dropped++; goto rx_next; } - skb_reserve(new_skb, RX_OFFSET); + skb_reserve(new_skb, NET_IP_ALIGN); dma_unmap_single(&cp->pdev->dev, mapping, buflen, PCI_DMA_FROMDEVICE); @@ -1051,19 +1050,20 @@ static void cp_init_hw (struct cp_private *cp) cpw8_f(Cfg9346, Cfg9346_Lock); } -static int cp_refill_rx (struct cp_private *cp) +static int cp_refill_rx(struct cp_private *cp) { + struct net_device *dev = cp->dev; unsigned i; for (i = 0; i < CP_RX_RING_SIZE; i++) { struct sk_buff *skb; dma_addr_t mapping; - skb = dev_alloc_skb(cp->rx_buf_sz + RX_OFFSET); + skb = netdev_alloc_skb(dev, cp->rx_buf_sz + NET_IP_ALIGN); if (!skb) goto err_out; - skb_reserve(skb, RX_OFFSET); + skb_reserve(skb, NET_IP_ALIGN); mapping = dma_map_single(&cp->pdev->dev, skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 8a5b0d293f7..0daf8c15e38 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -309,7 +309,7 @@ enum RTL8139_registers { Cfg9346 = 0x50, Config0 = 0x51, Config1 = 0x52, - FlashReg = 0x54, + TimerInt = 0x54, MediaStatus = 0x58, Config3 = 0x59, Config4 = 0x5A, /* absent on RTL-8139A */ @@ -325,6 +325,7 @@ enum RTL8139_registers { FIFOTMS = 0x70, /* FIFO Control and test. */ CSCR = 0x74, /* Chip Status and Configuration Register. */ PARA78 = 0x78, + FlashReg = 0xD4, /* Communication with Flash ROM, four bytes. */ PARA7c = 0x7c, /* Magic transceiver parameter register. */ Config5 = 0xD8, /* absent on RTL-8139A */ }; @@ -1722,13 +1723,18 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) } spin_lock_irqsave(&tp->lock, flags); + /* + * Writing to TxStatus triggers a DMA transfer of the data + * copied to tp->tx_buf[entry] above. Use a memory barrier + * to make sure that the device sees the updated data. + */ + wmb(); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | max(len, (unsigned int)ETH_ZLEN)); dev->trans_start = jiffies; tp->cur_tx++; - wmb(); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); @@ -2009,9 +2015,9 @@ no_early_rx: /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ - skb = dev_alloc_skb (pkt_size + 2); + skb = netdev_alloc_skb(dev, pkt_size + NET_IP_ALIGN); if (likely(skb)) { - skb_reserve (skb, 2); /* 16 byte align the IP fields. */ + skb_reserve (skb, NET_IP_ALIGN); /* 16 byte align the IP fields. */ #if RX_BUF_IDX == 3 wrap_copy(skb, rx_ring, ring_offset+4, pkt_size); #else diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4a11296a951..ad301ace608 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1386,7 +1386,8 @@ config FORCEDETH_NAPI config CS89x0 tristate "CS89x0 support" - depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X) + depends on NET_ETHERNET && (ISA || EISA || MACH_IXDP2351 \ + || ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS) ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the @@ -1397,6 +1398,11 @@ config CS89x0 To compile this driver as a module, choose M here. The module will be called cs89x0. +config CS89x0_NONISA_IRQ + def_bool y + depends on CS89x0 != n + depends on MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS + config TC35815 tristate "TOSHIBA TC35815 Ethernet support" depends on NET_PCI && PCI && MIPS @@ -1813,7 +1819,7 @@ config FEC2 config FEC_MPC52xx tristate "MPC52xx FEC driver" - depends on PPC_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC + depends on PPC_MPC52xx && PPC_BESTCOMM_FEC select CRC32 select PHYLIB ---help--- @@ -1840,6 +1846,17 @@ config NE_H8300 Say Y here if you want to use the NE2000 compatible controller on the Renesas H8/300 processor. +config ATL2 + tristate "Atheros L2 Fast Ethernet support" + depends on PCI + select CRC32 + select MII + help + This driver supports the Atheros L2 fast ethernet adapter. + + To compile this driver as a module, choose M here. The module + will be called atl2. + source "drivers/net/fs_enet/Kconfig" endif # NET_ETHERNET @@ -1927,15 +1944,6 @@ config E1000 To compile this driver as a module, choose M here. The module will be called e1000. -config E1000_DISABLE_PACKET_SPLIT - bool "Disable Packet Split for PCI express adapters" - depends on E1000 - help - Say Y here if you want to use the legacy receive path for PCI express - hardware. - - If in doubt, say N. - config E1000E tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" depends on PCI && (!SPARC32 || BROKEN) @@ -2046,6 +2054,7 @@ config R8169 tristate "Realtek 8169 gigabit ethernet support" depends on PCI select CRC32 + select MII ---help--- Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter. @@ -2262,7 +2271,7 @@ config UGETH_TX_ON_DEMAND config MV643XX_ETH tristate "Marvell Discovery (643XX) and Orion ethernet support" depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION - select MII + select PHYLIB help This driver supports the gigabit ethernet MACs in the Marvell Discovery PPC/MIPS chipset family (MV643XX) and @@ -2281,12 +2290,13 @@ config QLA3XXX will be called qla3xxx. config ATL1 - tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + tristate "Atheros/Attansic L1 Gigabit Ethernet support" + depends on PCI select CRC32 select MII help - This driver supports the Attansic L1 gigabit ethernet adapter. + This driver supports the Atheros/Attansic L1 gigabit ethernet + adapter. To compile this driver as a module, choose M here. The module will be called atl1. @@ -2302,6 +2312,18 @@ config ATL1E To compile this driver as a module, choose M here. The module will be called atl1e. +config JME + tristate "JMicron(R) PCI-Express Gigabit Ethernet support" + depends on PCI + select CRC32 + select MII + ---help--- + This driver supports the PCI-Express gigabit ethernet adapters + based on JMicron JMC250 chipset. + + To compile this driver as a module, choose M here. The module + will be called jme. + endif # NETDEV_1000 # @@ -2377,6 +2399,13 @@ config EHEA To compile the driver as a module, choose M here. The module will be called ehea. +config ENIC + tristate "Cisco 10G Ethernet NIC support" + depends on PCI && INET + select INET_LRO + help + This enables the support for the Cisco 10G Ethernet card. + config IXGBE tristate "Intel(R) 10GbE PCI Express adapters support" depends on PCI && INET @@ -2396,6 +2425,11 @@ config IXGBE To compile this driver as a module, choose M here. The module will be called ixgbe. +config IXGBE_DCA + bool + default y + depends on IXGBE && DCA && !(IXGBE=y && DCA=m) + config IXGB tristate "Intel(R) PRO/10GbE support" depends on PCI @@ -2443,6 +2477,11 @@ config MYRI10GE To compile this driver as a module, choose M here. The module will be called myri10ge. +config MYRI10GE_DCA + bool + default y + depends on MYRI10GE && DCA && !(MYRI10GE=y && DCA=m) + config NETXEN_NIC tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC" depends on PCI @@ -2496,6 +2535,15 @@ config BNX2X To compile this driver as a module, choose M here: the module will be called bnx2x. This is recommended. +config QLGE + tristate "QLogic QLGE 10Gb Ethernet Driver Support" + depends on PCI + help + This driver supports QLogic ISP8XXX 10Gb Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called qlge. + source "drivers/net/sfc/Kconfig" endif # NETDEV_10000 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 7629c901721..fa2510b2e60 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -15,9 +15,12 @@ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_CAN) += can/ obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_ATL1) += atlx/ +obj-$(CONFIG_ATL2) += atlx/ obj-$(CONFIG_ATL1E) += atl1e/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o obj-$(CONFIG_TEHUTI) += tehuti.o +obj-$(CONFIG_ENIC) += enic/ +obj-$(CONFIG_JME) += jme.o gianfar_driver-objs := gianfar.o \ gianfar_ethtool.o \ @@ -111,7 +114,7 @@ obj-$(CONFIG_EL2) += 3c503.o 8390p.o obj-$(CONFIG_NE2000) += ne.o 8390p.o obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o obj-$(CONFIG_HPLAN) += hp.o 8390p.o -obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o +obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o obj-$(CONFIG_ULTRAMCA) += smc-mca.o 8390.o obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o @@ -128,6 +131,7 @@ obj-$(CONFIG_AX88796) += ax88796.o obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o obj-$(CONFIG_QLA3XXX) += qla3xxx.o +obj-$(CONFIG_QLGE) += qlge/ obj-$(CONFIG_PPP) += ppp_generic.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index a0b4c851607..735fc947640 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -4,7 +4,7 @@ * - Jay Schulist <jschlst@samba.org> * * With more than a little help from; - * - Alan Cox <Alan.Cox@linux.org> + * - Alan Cox <alan@lxorguk.ukuu.org.uk> * * Derived from: * - skeleton.c: A network driver outline for linux. diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index bdc4c0bb56d..a5b07691e46 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -442,24 +442,24 @@ static int arcnet_open(struct net_device *dev) BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse " "DOS networking programs!\n"); - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); if (ASTATUS() & RESETflag) { - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); ACOMMAND(CFLAGScmd | RESETclear); } - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); /* make sure we're ready to receive IRQ's. */ AINTMASK(0); udelay(1); /* give it time to set the mask before * we reset it again. (may not even be * necessary) */ - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); lp->intmask = NORXflag | RECONflag; AINTMASK(lp->intmask); - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); netif_start_queue(dev); @@ -670,14 +670,14 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) freeskb = 0; } - BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS()); + BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__func__,ASTATUS()); /* make sure we didn't ignore a TX IRQ while we were in here */ AINTMASK(0); - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); lp->intmask |= TXFREEflag|EXCNAKflag; AINTMASK(lp->intmask); - BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS()); + BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__func__,ASTATUS()); spin_unlock_irqrestore(&lp->lock, flags); if (freeskb) { @@ -798,7 +798,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) diagstatus = (status >> 8) & 0xFF; BUGMSG(D_DEBUG, "%s: %d: %s: status=%x\n", - __FILE__,__LINE__,__FUNCTION__,status); + __FILE__,__LINE__,__func__,status); didsomething = 0; /* diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 8b51313b130..70124a944e7 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -238,15 +238,15 @@ static int com20020_reset(struct net_device *dev, int really_reset) u_char inbyte; BUGMSG(D_DEBUG, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n", - __FILE__,__LINE__,__FUNCTION__,dev,lp,dev->name); + __FILE__,__LINE__,__func__,dev,lp,dev->name); BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2); /* power-up defaults */ SETCONF; - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); if (really_reset) { /* reset the card */ @@ -254,22 +254,22 @@ static int com20020_reset(struct net_device *dev, int really_reset) mdelay(RESETtime * 2); /* COM20020 seems to be slower sometimes */ } /* clear flags & end reset */ - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); /* verify that the ARCnet signature byte is present */ - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); com20020_copy_from_card(dev, 0, 0, &inbyte, 1); - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); if (inbyte != TESTvalue) { - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); return 1; } /* enable extended (512-byte) packets */ ACOMMAND(CONFIGcmd | EXTconf); - BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__); /* done! return success. */ return 0; diff --git a/drivers/net/atl1e/atl1e_hw.c b/drivers/net/atl1e/atl1e_hw.c index 949e75358bf..8cbc1b59bd6 100644 --- a/drivers/net/atl1e/atl1e_hw.c +++ b/drivers/net/atl1e/atl1e_hw.c @@ -397,7 +397,7 @@ static int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw) */ int atl1e_phy_commit(struct atl1e_hw *hw) { - struct atl1e_adapter *adapter = (struct atl1e_adapter *)hw->adapter; + struct atl1e_adapter *adapter = hw->adapter; struct pci_dev *pdev = adapter->pdev; int ret_val; u16 phy_data; @@ -431,7 +431,7 @@ int atl1e_phy_commit(struct atl1e_hw *hw) int atl1e_phy_init(struct atl1e_hw *hw) { - struct atl1e_adapter *adapter = (struct atl1e_adapter *)hw->adapter; + struct atl1e_adapter *adapter = hw->adapter; struct pci_dev *pdev = adapter->pdev; s32 ret_val; u16 phy_val; @@ -525,7 +525,7 @@ int atl1e_phy_init(struct atl1e_hw *hw) */ int atl1e_reset_hw(struct atl1e_hw *hw) { - struct atl1e_adapter *adapter = (struct atl1e_adapter *)hw->adapter; + struct atl1e_adapter *adapter = hw->adapter; struct pci_dev *pdev = adapter->pdev; u32 idle_status_data = 0; diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 7685b995ff9..9b603528143 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -2390,9 +2390,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev, } /* Init GPHY as early as possible due to power saving issue */ - spin_lock(&adapter->mdio_lock); atl1e_phy_init(&adapter->hw); - spin_unlock(&adapter->mdio_lock); /* reset the controller to * put the device in a known good starting state */ err = atl1e_reset_hw(&adapter->hw); diff --git a/drivers/net/atlx/Makefile b/drivers/net/atlx/Makefile index ca45553a040..e4f6022ca55 100644 --- a/drivers/net/atlx/Makefile +++ b/drivers/net/atlx/Makefile @@ -1 +1,3 @@ obj-$(CONFIG_ATL1) += atl1.o +obj-$(CONFIG_ATL2) += atl2.o + diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index e23ce77712f..3cf59a7f5a1 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -24,16 +24,12 @@ * file called COPYING. * * Contact Information: - * Xiong Huang <xiong_huang@attansic.com> - * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei, - * Xinzhu 302, TAIWAN, REPUBLIC OF CHINA - * + * Xiong Huang <xiong.huang@atheros.com> + * Jie Yang <jie.yang@atheros.com> * Chris Snook <csnook@redhat.com> * Jay Cliburn <jcliburn@gmail.com> * - * This version is adapted from the Attansic reference driver for - * inclusion in the Linux kernel. It is currently under heavy development. - * A very incomplete list of things that need to be dealt with: + * This version is adapted from the Attansic reference driver. * * TODO: * Add more ethtool functions. @@ -2109,7 +2105,6 @@ static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring) static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, struct tx_packet_desc *ptpd) { - /* spinlock held */ u8 hdr_len, ip_off; u32 real_len; int err; @@ -2196,7 +2191,6 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb, static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, struct tx_packet_desc *ptpd) { - /* spinlock held */ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; struct atl1_buffer *buffer_info; u16 buf_len = skb->len; @@ -2303,7 +2297,6 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, static void atl1_tx_queue(struct atl1_adapter *adapter, u16 count, struct tx_packet_desc *ptpd) { - /* spinlock held */ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; struct atl1_buffer *buffer_info; struct tx_packet_desc *tpd; @@ -2361,7 +2354,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct tx_packet_desc *ptpd; u16 frag_size; u16 vlan_tag; - unsigned long flags; unsigned int nr_frags = 0; unsigned int mss = 0; unsigned int f; @@ -2399,18 +2391,9 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } } - if (!spin_trylock_irqsave(&adapter->lock, flags)) { - /* Can't get lock - tell upper layer to requeue */ - if (netif_msg_tx_queued(adapter)) - dev_printk(KERN_DEBUG, &adapter->pdev->dev, - "tx locked\n"); - return NETDEV_TX_LOCKED; - } - if (atl1_tpd_avail(&adapter->tpd_ring) < count) { /* not enough descriptors */ netif_stop_queue(netdev); - spin_unlock_irqrestore(&adapter->lock, flags); if (netif_msg_tx_queued(adapter)) dev_printk(KERN_DEBUG, &adapter->pdev->dev, "tx busy\n"); @@ -2432,7 +2415,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tso = atl1_tso(adapter, skb, ptpd); if (tso < 0) { - spin_unlock_irqrestore(&adapter->lock, flags); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -2440,7 +2422,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (!tso) { ret_val = atl1_tx_csum(adapter, skb, ptpd); if (ret_val < 0) { - spin_unlock_irqrestore(&adapter->lock, flags); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -2449,7 +2430,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1_tx_map(adapter, skb, ptpd); atl1_tx_queue(adapter, count, ptpd); atl1_update_mailbox(adapter); - spin_unlock_irqrestore(&adapter->lock, flags); + mmiowb(); netdev->trans_start = jiffies; return NETDEV_TX_OK; } @@ -2642,6 +2623,7 @@ static void atl1_down(struct atl1_adapter *adapter) { struct net_device *netdev = adapter->netdev; + netif_stop_queue(netdev); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_config_timer); adapter->phy_timer_pending = false; @@ -2655,7 +2637,6 @@ static void atl1_down(struct atl1_adapter *adapter) adapter->link_speed = SPEED_0; adapter->link_duplex = -1; netif_carrier_off(netdev); - netif_stop_queue(netdev); atl1_clean_tx_ring(adapter); atl1_clean_rx_ring(adapter); @@ -2724,6 +2705,8 @@ static int atl1_open(struct net_device *netdev) struct atl1_adapter *adapter = netdev_priv(netdev); int err; + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = atl1_setup_ring_resources(adapter); if (err) @@ -3022,7 +3005,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev, netdev->features = NETIF_F_HW_CSUM; netdev->features |= NETIF_F_SG; netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); - netdev->features |= NETIF_F_LLTX; /* * patch for some L1 of old version, diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c new file mode 100644 index 00000000000..f5bdc92c1a6 --- /dev/null +++ b/drivers/net/atlx/atl2.c @@ -0,0 +1,3119 @@ +/* + * Copyright(c) 2006 - 2007 Atheros Corporation. All rights reserved. + * Copyright(c) 2007 - 2008 Chris Snook <csnook@redhat.com> + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * 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; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <asm/atomic.h> +#include <linux/crc32.h> +#include <linux/dma-mapping.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/hardirq.h> +#include <linux/if_vlan.h> +#include <linux/in.h> +#include <linux/interrupt.h> +#include <linux/ip.h> +#include <linux/irqflags.h> +#include <linux/irqreturn.h> +#include <linux/mii.h> +#include <linux/net.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/pm.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/tcp.h> +#include <linux/timer.h> +#include <linux/types.h> +#include <linux/workqueue.h> + +#include "atl2.h" + +#define ATL2_DRV_VERSION "2.2.3" + +static char atl2_driver_name[] = "atl2"; +static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver"; +static char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation."; +static char atl2_driver_version[] = ATL2_DRV_VERSION; + +MODULE_AUTHOR("Atheros Corporation <xiong.huang@atheros.com>, Chris Snook <csnook@redhat.com>"); +MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(ATL2_DRV_VERSION); + +/* + * atl2_pci_tbl - PCI Device ID Table + */ +static struct pci_device_id atl2_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2)}, + /* required last entry */ + {0,} +}; +MODULE_DEVICE_TABLE(pci, atl2_pci_tbl); + +static void atl2_set_ethtool_ops(struct net_device *netdev); + +static void atl2_check_options(struct atl2_adapter *adapter); + +/* + * atl2_sw_init - Initialize general software structures (struct atl2_adapter) + * @adapter: board private structure to initialize + * + * atl2_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + */ +static int __devinit atl2_sw_init(struct atl2_adapter *adapter) +{ + struct atl2_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + + /* PCI config space info */ + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_id = pdev->subsystem_device; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); + + adapter->wol = 0; + adapter->ict = 50000; /* ~100ms */ + adapter->link_speed = SPEED_0; /* hardware init */ + adapter->link_duplex = FULL_DUPLEX; + + hw->phy_configured = false; + hw->preamble_len = 7; + hw->ipgt = 0x60; + hw->min_ifg = 0x50; + hw->ipgr1 = 0x40; + hw->ipgr2 = 0x60; + hw->retry_buf = 2; + hw->max_retry = 0xf; + hw->lcol = 0x37; + hw->jam_ipg = 7; + hw->fc_rxd_hi = 0; + hw->fc_rxd_lo = 0; + hw->max_frame_size = adapter->netdev->mtu; + + spin_lock_init(&adapter->stats_lock); + + set_bit(__ATL2_DOWN, &adapter->flags); + + return 0; +} + +/* + * atl2_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + */ +static void atl2_set_multi(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + struct dev_mc_list *mc_ptr; + u32 rctl; + u32 hash_value; + + /* Check for Promiscuous and All Multicast modes */ + rctl = ATL2_READ_REG(hw, REG_MAC_CTRL); + + if (netdev->flags & IFF_PROMISC) { + rctl |= MAC_CTRL_PROMIS_EN; + } else if (netdev->flags & IFF_ALLMULTI) { + rctl |= MAC_CTRL_MC_ALL_EN; + rctl &= ~MAC_CTRL_PROMIS_EN; + } else + rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN); + + ATL2_WRITE_REG(hw, REG_MAC_CTRL, rctl); + + /* clear the old settings from the multicast hash table */ + ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); + ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); + + /* comoute mc addresses' hash value ,and put it into hash table */ + for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + hash_value = atl2_hash_mc_addr(hw, mc_ptr->dmi_addr); + atl2_hash_set(hw, hash_value); + } +} + +static void init_ring_ptrs(struct atl2_adapter *adapter) +{ + /* Read / Write Ptr Initialize: */ + adapter->txd_write_ptr = 0; + atomic_set(&adapter->txd_read_ptr, 0); + + adapter->rxd_read_ptr = 0; + adapter->rxd_write_ptr = 0; + + atomic_set(&adapter->txs_write_ptr, 0); + adapter->txs_next_clear = 0; +} + +/* + * atl2_configure - Configure Transmit&Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Tx /Rx unit of the MAC after a reset. + */ +static int atl2_configure(struct atl2_adapter *adapter) +{ + struct atl2_hw *hw = &adapter->hw; + u32 value; + + /* clear interrupt status */ + ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0xffffffff); + + /* set MAC Address */ + value = (((u32)hw->mac_addr[2]) << 24) | + (((u32)hw->mac_addr[3]) << 16) | + (((u32)hw->mac_addr[4]) << 8) | + (((u32)hw->mac_addr[5])); + ATL2_WRITE_REG(hw, REG_MAC_STA_ADDR, value); + value = (((u32)hw->mac_addr[0]) << 8) | + (((u32)hw->mac_addr[1])); + ATL2_WRITE_REG(hw, (REG_MAC_STA_ADDR+4), value); + + /* HI base address */ + ATL2_WRITE_REG(hw, REG_DESC_BASE_ADDR_HI, + (u32)((adapter->ring_dma & 0xffffffff00000000ULL) >> 32)); + + /* LO base address */ + ATL2_WRITE_REG(hw, REG_TXD_BASE_ADDR_LO, + (u32)(adapter->txd_dma & 0x00000000ffffffffULL)); + ATL2_WRITE_REG(hw, REG_TXS_BASE_ADDR_LO, + (u32)(adapter->txs_dma & 0x00000000ffffffffULL)); + ATL2_WRITE_REG(hw, REG_RXD_BASE_ADDR_LO, + (u32)(adapter->rxd_dma & 0x00000000ffffffffULL)); + + /* element count */ + ATL2_WRITE_REGW(hw, REG_TXD_MEM_SIZE, (u16)(adapter->txd_ring_size/4)); + ATL2_WRITE_REGW(hw, REG_TXS_MEM_SIZE, (u16)adapter->txs_ring_size); + ATL2_WRITE_REGW(hw, REG_RXD_BUF_NUM, (u16)adapter->rxd_ring_size); + + /* config Internal SRAM */ +/* + ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_tx_end); + ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_rx_end); +*/ + + /* config IPG/IFG */ + value = (((u32)hw->ipgt & MAC_IPG_IFG_IPGT_MASK) << + MAC_IPG_IFG_IPGT_SHIFT) | + (((u32)hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) << + MAC_IPG_IFG_MIFG_SHIFT) | + (((u32)hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) << + MAC_IPG_IFG_IPGR1_SHIFT)| + (((u32)hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) << + MAC_IPG_IFG_IPGR2_SHIFT); + ATL2_WRITE_REG(hw, REG_MAC_IPG_IFG, value); + + /* config Half-Duplex Control */ + value = ((u32)hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) | + (((u32)hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK) << + MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) | + MAC_HALF_DUPLX_CTRL_EXC_DEF_EN | + (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) | + (((u32)hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) << + MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT); + ATL2_WRITE_REG(hw, REG_MAC_HALF_DUPLX_CTRL, value); + + /* set Interrupt Moderator Timer */ + ATL2_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, adapter->imt); + ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_ITIMER_EN); + + /* set Interrupt Clear Timer */ + ATL2_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, adapter->ict); + + /* set MTU */ + ATL2_WRITE_REG(hw, REG_MTU, adapter->netdev->mtu + + ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE); + + /* 1590 */ + ATL2_WRITE_REG(hw, REG_TX_CUT_THRESH, 0x177); + + /* flow control */ + ATL2_WRITE_REGW(hw, REG_PAUSE_ON_TH, hw->fc_rxd_hi); + ATL2_WRITE_REGW(hw, REG_PAUSE_OFF_TH, hw->fc_rxd_lo); + + /* Init mailbox */ + ATL2_WRITE_REGW(hw, REG_MB_TXD_WR_IDX, (u16)adapter->txd_write_ptr); + ATL2_WRITE_REGW(hw, REG_MB_RXD_RD_IDX, (u16)adapter->rxd_read_ptr); + + /* enable DMA read/write */ + ATL2_WRITE_REGB(hw, REG_DMAR, DMAR_EN); + ATL2_WRITE_REGB(hw, REG_DMAW, DMAW_EN); + + value = ATL2_READ_REG(&adapter->hw, REG_ISR); + if ((value & ISR_PHY_LINKDOWN) != 0) + value = 1; /* config failed */ + else + value = 0; + + /* clear all interrupt status */ + ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0x3fffffff); + ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0); + return value; +} + +/* + * atl2_setup_ring_resources - allocate Tx / RX descriptor resources + * @adapter: board private structure + * + * Return 0 on success, negative on failure + */ +static s32 atl2_setup_ring_resources(struct atl2_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + int size; + u8 offset = 0; + + /* real ring DMA buffer */ + adapter->ring_size = size = + adapter->txd_ring_size * 1 + 7 + /* dword align */ + adapter->txs_ring_size * 4 + 7 + /* dword align */ + adapter->rxd_ring_size * 1536 + 127; /* 128bytes align */ + + adapter->ring_vir_addr = pci_alloc_consistent(pdev, size, + &adapter->ring_dma); + if (!adapter->ring_vir_addr) + return -ENOMEM; + memset(adapter->ring_vir_addr, 0, adapter->ring_size); + + /* Init TXD Ring */ + adapter->txd_dma = adapter->ring_dma ; + offset = (adapter->txd_dma & 0x7) ? (8 - (adapter->txd_dma & 0x7)) : 0; + adapter->txd_dma += offset; + adapter->txd_ring = (struct tx_pkt_header *) (adapter->ring_vir_addr + + offset); + + /* Init TXS Ring */ + adapter->txs_dma = adapter->txd_dma + adapter->txd_ring_size; + offset = (adapter->txs_dma & 0x7) ? (8 - (adapter->txs_dma & 0x7)) : 0; + adapter->txs_dma += offset; + adapter->txs_ring = (struct tx_pkt_status *) + (((u8 *)adapter->txd_ring) + (adapter->txd_ring_size + offset)); + + /* Init RXD Ring */ + adapter->rxd_dma = adapter->txs_dma + adapter->txs_ring_size * 4; + offset = (adapter->rxd_dma & 127) ? + (128 - (adapter->rxd_dma & 127)) : 0; + if (offset > 7) + offset -= 8; + else + offset += (128 - 8); + + adapter->rxd_dma += offset; + adapter->rxd_ring = (struct rx_desc *) (((u8 *)adapter->txs_ring) + + (adapter->txs_ring_size * 4 + offset)); + +/* + * Read / Write Ptr Initialize: + * init_ring_ptrs(adapter); + */ + return 0; +} + +/* + * atl2_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + */ +static inline void atl2_irq_enable(struct atl2_adapter *adapter) +{ + ATL2_WRITE_REG(&adapter->hw, REG_IMR, IMR_NORMAL_MASK); + ATL2_WRITE_FLUSH(&adapter->hw); +} + +/* + * atl2_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + */ +static inline void atl2_irq_disable(struct atl2_adapter *adapter) +{ + ATL2_WRITE_REG(&adapter->hw, REG_IMR, 0); + ATL2_WRITE_FLUSH(&adapter->hw); + synchronize_irq(adapter->pdev->irq); +} + +#ifdef NETIF_F_HW_VLAN_TX +static void atl2_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + u32 ctrl; + + atl2_irq_disable(adapter); + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL); + ctrl |= MAC_CTRL_RMV_VLAN; + ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl); + } else { + /* disable VLAN tag insert/strip */ + ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_RMV_VLAN; + ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl); + } + + atl2_irq_enable(adapter); +} + +static void atl2_restore_vlan(struct atl2_adapter *adapter) +{ + atl2_vlan_rx_register(adapter->netdev, adapter->vlgrp); +} +#endif + +static void atl2_intr_rx(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct rx_desc *rxd; + struct sk_buff *skb; + + do { + rxd = adapter->rxd_ring+adapter->rxd_write_ptr; + if (!rxd->status.update) + break; /* end of tx */ + + /* clear this flag at once */ + rxd->status.update = 0; + + if (rxd->status.ok && rxd->status.pkt_size >= 60) { + int rx_size = (int)(rxd->status.pkt_size - 4); + /* alloc new buffer */ + skb = netdev_alloc_skb(netdev, rx_size + NET_IP_ALIGN); + if (NULL == skb) { + printk(KERN_WARNING + "%s: Mem squeeze, deferring packet.\n", + netdev->name); + /* + * Check that some rx space is free. If not, + * free one and mark stats->rx_dropped++. + */ + adapter->net_stats.rx_dropped++; + break; + } + skb_reserve(skb, NET_IP_ALIGN); + skb->dev = netdev; + memcpy(skb->data, rxd->packet, rx_size); + skb_put(skb, rx_size); + skb->protocol = eth_type_trans(skb, netdev); +#ifdef NETIF_F_HW_VLAN_TX + if (adapter->vlgrp && (rxd->status.vlan)) { + u16 vlan_tag = (rxd->status.vtag>>4) | + ((rxd->status.vtag&7) << 13) | + ((rxd->status.vtag&8) << 9); + vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag); + } else +#endif + netif_rx(skb); + adapter->net_stats.rx_bytes += rx_size; + adapter->net_stats.rx_packets++; + netdev->last_rx = jiffies; + } else { + adapter->net_stats.rx_errors++; + + if (rxd->status.ok && rxd->status.pkt_size <= 60) + adapter->net_stats.rx_length_errors++; + if (rxd->status.mcast) + adapter->net_stats.multicast++; + if (rxd->status.crc) + adapter->net_stats.rx_crc_errors++; + if (rxd->status.align) + adapter->net_stats.rx_frame_errors++; + } + + /* advance write ptr */ + if (++adapter->rxd_write_ptr == adapter->rxd_ring_size) + adapter->rxd_write_ptr = 0; + } while (1); + + /* update mailbox? */ + adapter->rxd_read_ptr = adapter->rxd_write_ptr; + ATL2_WRITE_REGW(&adapter->hw, REG_MB_RXD_RD_IDX, adapter->rxd_read_ptr); +} + +static void atl2_intr_tx(struct atl2_adapter *adapter) +{ + u32 txd_read_ptr; + u32 txs_write_ptr; + struct tx_pkt_status *txs; + struct tx_pkt_header *txph; + int free_hole = 0; + + do { + txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr); + txs = adapter->txs_ring + txs_write_ptr; + if (!txs->update) + break; /* tx stop here */ + + free_hole = 1; + txs->update = 0; + + if (++txs_write_ptr == adapter->txs_ring_size) + txs_write_ptr = 0; + atomic_set(&adapter->txs_write_ptr, (int)txs_write_ptr); + + txd_read_ptr = (u32) atomic_read(&adapter->txd_read_ptr); + txph = (struct tx_pkt_header *) + (((u8 *)adapter->txd_ring) + txd_read_ptr); + + if (txph->pkt_size != txs->pkt_size) { + struct tx_pkt_status *old_txs = txs; + printk(KERN_WARNING + "%s: txs packet size not consistent with txd" + " txd_:0x%08x, txs_:0x%08x!\n", + adapter->netdev->name, + *(u32 *)txph, *(u32 *)txs); + printk(KERN_WARNING + "txd read ptr: 0x%x\n", + txd_read_ptr); + txs = adapter->txs_ring + txs_write_ptr; + printk(KERN_WARNING + "txs-behind:0x%08x\n", + *(u32 *)txs); + if (txs_write_ptr < 2) { + txs = adapter->txs_ring + + (adapter->txs_ring_size + + txs_write_ptr - 2); + } else { + txs = adapter->txs_ring + (txs_write_ptr - 2); + } + printk(KERN_WARNING + "txs-before:0x%08x\n", + *(u32 *)txs); + txs = old_txs; + } + + /* 4for TPH */ + txd_read_ptr += (((u32)(txph->pkt_size) + 7) & ~3); + if (txd_read_ptr >= adapter->txd_ring_size) + txd_read_ptr -= adapter->txd_ring_size; + + atomic_set(&adapter->txd_read_ptr, (int)txd_read_ptr); + + /* tx statistics: */ + if (txs->ok) { + adapter->net_stats.tx_bytes += txs->pkt_size; + adapter->net_stats.tx_packets++; + } + else + adapter->net_stats.tx_errors++; + + if (txs->defer) + adapter->net_stats.collisions++; + if (txs->abort_col) + adapter->net_stats.tx_aborted_errors++; + if (txs->late_col) + adapter->net_stats.tx_window_errors++; + if (txs->underun) + adapter->net_stats.tx_fifo_errors++; + } while (1); + + if (free_hole) { + if (netif_queue_stopped(adapter->netdev) && + netif_carrier_ok(adapter->netdev)) + netif_wake_queue(adapter->netdev); + } +} + +static void atl2_check_for_link(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 phy_data = 0; + + spin_lock(&adapter->stats_lock); + atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + spin_unlock(&adapter->stats_lock); + + /* notify upper layer link down ASAP */ + if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + printk(KERN_INFO "%s: %s NIC Link is Down\n", + atl2_driver_name, netdev->name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + schedule_work(&adapter->link_chg_task); +} + +static inline void atl2_clear_phy_int(struct atl2_adapter *adapter) +{ + u16 phy_data; + spin_lock(&adapter->stats_lock); + atl2_read_phy_reg(&adapter->hw, 19, &phy_data); + spin_unlock(&adapter->stats_lock); +} + +/* + * atl2_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + */ +static irqreturn_t atl2_intr(int irq, void *data) +{ + struct atl2_adapter *adapter = netdev_priv(data); + struct atl2_hw *hw = &adapter->hw; + u32 status; + + status = ATL2_READ_REG(hw, REG_ISR); + if (0 == status) + return IRQ_NONE; + + /* link event */ + if (status & ISR_PHY) + atl2_clear_phy_int(adapter); + + /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ + ATL2_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT); + + /* check if PCIE PHY Link down */ + if (status & ISR_PHY_LINKDOWN) { + if (netif_running(adapter->netdev)) { /* reset MAC */ + ATL2_WRITE_REG(hw, REG_ISR, 0); + ATL2_WRITE_REG(hw, REG_IMR, 0); + ATL2_WRITE_FLUSH(hw); + schedule_work(&adapter->reset_task); + return IRQ_HANDLED; + } + } + + /* check if DMA read/write error? */ + if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { + ATL2_WRITE_REG(hw, REG_ISR, 0); + ATL2_WRITE_REG(hw, REG_IMR, 0); + ATL2_WRITE_FLUSH(hw); + schedule_work(&adapter->reset_task); + return IRQ_HANDLED; + } + + /* link event */ + if (status & (ISR_PHY | ISR_MANUAL)) { + adapter->net_stats.tx_carrier_errors++; + atl2_check_for_link(adapter); + } + + /* transmit event */ + if (status & ISR_TX_EVENT) + atl2_intr_tx(adapter); + + /* rx exception */ + if (status & ISR_RX_EVENT) + atl2_intr_rx(adapter); + + /* re-enable Interrupt */ + ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0); + return IRQ_HANDLED; +} + +static int atl2_request_irq(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int flags, err = 0; + + flags = IRQF_SHARED; +#ifdef CONFIG_PCI_MSI + adapter->have_msi = true; + err = pci_enable_msi(adapter->pdev); + if (err) + adapter->have_msi = false; + + if (adapter->have_msi) + flags &= ~IRQF_SHARED; +#endif + + return request_irq(adapter->pdev->irq, &atl2_intr, flags, netdev->name, + netdev); +} + +/* + * atl2_free_ring_resources - Free Tx / RX descriptor Resources + * @adapter: board private structure + * + * Free all transmit software resources + */ +static void atl2_free_ring_resources(struct atl2_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + pci_free_consistent(pdev, adapter->ring_size, adapter->ring_vir_addr, + adapter->ring_dma); +} + +/* + * atl2_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + */ +static int atl2_open(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + int err; + u32 val; + + /* disallow open during test */ + if (test_bit(__ATL2_TESTING, &adapter->flags)) + return -EBUSY; + + /* allocate transmit descriptors */ + err = atl2_setup_ring_resources(adapter); + if (err) + return err; + + err = atl2_init_hw(&adapter->hw); + if (err) { + err = -EIO; + goto err_init_hw; + } + + /* hardware has been reset, we need to reload some things */ + atl2_set_multi(netdev); + init_ring_ptrs(adapter); + +#ifdef NETIF_F_HW_VLAN_TX + atl2_restore_vlan(adapter); +#endif + + if (atl2_configure(adapter)) { + err = -EIO; + goto err_config; + } + + err = atl2_request_irq(adapter); + if (err) + goto err_req_irq; + + clear_bit(__ATL2_DOWN, &adapter->flags); + + mod_timer(&adapter->watchdog_timer, jiffies + 4*HZ); + + val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); + ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, + val | MASTER_CTRL_MANUAL_INT); + + atl2_irq_enable(adapter); + + return 0; + +err_init_hw: +err_req_irq: +err_config: + atl2_free_ring_resources(adapter); + atl2_reset_hw(&adapter->hw); + + return err; +} + +static void atl2_down(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + /* signal that we're down so the interrupt handler does not + * reschedule our watchdog timer */ + set_bit(__ATL2_DOWN, &adapter->flags); + + netif_tx_disable(netdev); + + /* reset MAC to disable all RX/TX */ + atl2_reset_hw(&adapter->hw); + msleep(1); + + atl2_irq_disable(adapter); + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_config_timer); + clear_bit(0, &adapter->cfg_phy); + + netif_carrier_off(netdev); + adapter->link_speed = SPEED_0; + adapter->link_duplex = -1; +} + +static void atl2_free_irq(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + free_irq(adapter->pdev->irq, netdev); + +#ifdef CONFIG_PCI_MSI + if (adapter->have_msi) + pci_disable_msi(adapter->pdev); +#endif +} + +/* + * atl2_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + */ +static int atl2_close(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags)); + + atl2_down(adapter); + atl2_free_irq(adapter); + atl2_free_ring_resources(adapter); + + return 0; +} + +static inline int TxsFreeUnit(struct atl2_adapter *adapter) +{ + u32 txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr); + + return (adapter->txs_next_clear >= txs_write_ptr) ? + (int) (adapter->txs_ring_size - adapter->txs_next_clear + + txs_write_ptr - 1) : + (int) (txs_write_ptr - adapter->txs_next_clear - 1); +} + +static inline int TxdFreeBytes(struct atl2_adapter *adapter) +{ + u32 txd_read_ptr = (u32)atomic_read(&adapter->txd_read_ptr); + + return (adapter->txd_write_ptr >= txd_read_ptr) ? + (int) (adapter->txd_ring_size - adapter->txd_write_ptr + + txd_read_ptr - 1) : + (int) (txd_read_ptr - adapter->txd_write_ptr - 1); +} + +static int atl2_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct tx_pkt_header *txph; + u32 offset, copy_len; + int txs_unused; + int txbuf_unused; + + if (test_bit(__ATL2_DOWN, &adapter->flags)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (unlikely(skb->len <= 0)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + txs_unused = TxsFreeUnit(adapter); + txbuf_unused = TxdFreeBytes(adapter); + + if (skb->len + sizeof(struct tx_pkt_header) + 4 > txbuf_unused || + txs_unused < 1) { + /* not enough resources */ + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; + } + + offset = adapter->txd_write_ptr; + + txph = (struct tx_pkt_header *) (((u8 *)adapter->txd_ring) + offset); + + *(u32 *)txph = 0; + txph->pkt_size = skb->len; + + offset += 4; + if (offset >= adapter->txd_ring_size) + offset -= adapter->txd_ring_size; + copy_len = adapter->txd_ring_size - offset; + if (copy_len >= skb->len) { + memcpy(((u8 *)adapter->txd_ring) + offset, skb->data, skb->len); + offset += ((u32)(skb->len + 3) & ~3); + } else { + memcpy(((u8 *)adapter->txd_ring)+offset, skb->data, copy_len); + memcpy((u8 *)adapter->txd_ring, skb->data+copy_len, + skb->len-copy_len); + offset = ((u32)(skb->len-copy_len + 3) & ~3); + } +#ifdef NETIF_F_HW_VLAN_TX + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + u16 vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = (vlan_tag << 4) | + (vlan_tag >> 13) | + ((vlan_tag >> 9) & 0x8); + txph->ins_vlan = 1; + txph->vlan = vlan_tag; + } +#endif + if (offset >= adapter->txd_ring_size) + offset -= adapter->txd_ring_size; + adapter->txd_write_ptr = offset; + + /* clear txs before send */ + adapter->txs_ring[adapter->txs_next_clear].update = 0; + if (++adapter->txs_next_clear == adapter->txs_ring_size) + adapter->txs_next_clear = 0; + + ATL2_WRITE_REGW(&adapter->hw, REG_MB_TXD_WR_IDX, + (adapter->txd_write_ptr >> 2)); + + mmiowb(); + netdev->trans_start = jiffies; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +/* + * atl2_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + */ +static struct net_device_stats *atl2_get_stats(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + return &adapter->net_stats; +} + +/* + * atl2_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + */ +static int atl2_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + + if ((new_mtu < 40) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) + return -EINVAL; + + /* set MTU */ + if (hw->max_frame_size != new_mtu) { + netdev->mtu = new_mtu; + ATL2_WRITE_REG(hw, REG_MTU, new_mtu + ENET_HEADER_SIZE + + VLAN_SIZE + ETHERNET_FCS_SIZE); + } + + return 0; +} + +/* + * atl2_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + */ +static int atl2_set_mac(struct net_device *netdev, void *p) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + if (netif_running(netdev)) + return -EBUSY; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); + + atl2_set_mac_addr(&adapter->hw); + + return 0; +} + +/* + * atl2_mii_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct mii_ioctl_data *data = if_mii(ifr); + unsigned long flags; + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = 0; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + spin_lock_irqsave(&adapter->stats_lock, flags); + if (atl2_read_phy_reg(&adapter->hw, + data->reg_num & 0x1F, &data->val_out)) { + spin_unlock_irqrestore(&adapter->stats_lock, flags); + return -EIO; + } + spin_unlock_irqrestore(&adapter->stats_lock, flags); + break; + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (data->reg_num & ~(0x1F)) + return -EFAULT; + spin_lock_irqsave(&adapter->stats_lock, flags); + if (atl2_write_phy_reg(&adapter->hw, data->reg_num, + data->val_in)) { + spin_unlock_irqrestore(&adapter->stats_lock, flags); + return -EIO; + } + spin_unlock_irqrestore(&adapter->stats_lock, flags); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* + * atl2_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl2_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return atl2_mii_ioctl(netdev, ifr, cmd); +#ifdef ETHTOOL_OPS_COMPAT + case SIOCETHTOOL: + return ethtool_ioctl(ifr); +#endif + default: + return -EOPNOTSUPP; + } +} + +/* + * atl2_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + */ +static void atl2_tx_timeout(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->reset_task); +} + +/* + * atl2_watchdog - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl2_watchdog(unsigned long data) +{ + struct atl2_adapter *adapter = (struct atl2_adapter *) data; + u32 drop_rxd, drop_rxs; + unsigned long flags; + + if (!test_bit(__ATL2_DOWN, &adapter->flags)) { + spin_lock_irqsave(&adapter->stats_lock, flags); + drop_rxd = ATL2_READ_REG(&adapter->hw, REG_STS_RXD_OV); + drop_rxs = ATL2_READ_REG(&adapter->hw, REG_STS_RXS_OV); + adapter->net_stats.rx_over_errors += (drop_rxd+drop_rxs); + spin_unlock_irqrestore(&adapter->stats_lock, flags); + + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, jiffies + 4 * HZ); + } +} + +/* + * atl2_phy_config - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl2_phy_config(unsigned long data) +{ + struct atl2_adapter *adapter = (struct atl2_adapter *) data; + struct atl2_hw *hw = &adapter->hw; + unsigned long flags; + + spin_lock_irqsave(&adapter->stats_lock, flags); + atl2_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); + atl2_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN | + MII_CR_RESTART_AUTO_NEG); + spin_unlock_irqrestore(&adapter->stats_lock, flags); + clear_bit(0, &adapter->cfg_phy); +} + +static int atl2_up(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int err = 0; + u32 val; + + /* hardware has been reset, we need to reload some things */ + + err = atl2_init_hw(&adapter->hw); + if (err) { + err = -EIO; + return err; + } + + atl2_set_multi(netdev); + init_ring_ptrs(adapter); + +#ifdef NETIF_F_HW_VLAN_TX + atl2_restore_vlan(adapter); +#endif + + if (atl2_configure(adapter)) { + err = -EIO; + goto err_up; + } + + clear_bit(__ATL2_DOWN, &adapter->flags); + + val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); + ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, val | + MASTER_CTRL_MANUAL_INT); + + atl2_irq_enable(adapter); + +err_up: + return err; +} + +static void atl2_reinit_locked(struct atl2_adapter *adapter) +{ + WARN_ON(in_interrupt()); + while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags)) + msleep(1); + atl2_down(adapter); + atl2_up(adapter); + clear_bit(__ATL2_RESETTING, &adapter->flags); +} + +static void atl2_reset_task(struct work_struct *work) +{ + struct atl2_adapter *adapter; + adapter = container_of(work, struct atl2_adapter, reset_task); + + atl2_reinit_locked(adapter); +} + +static void atl2_setup_mac_ctrl(struct atl2_adapter *adapter) +{ + u32 value; + struct atl2_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + + /* Config MAC CTRL Register */ + value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY; + + /* duplex */ + if (FULL_DUPLEX == adapter->link_duplex) + value |= MAC_CTRL_DUPLX; + + /* flow control */ + value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); + + /* PAD & CRC */ + value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); + + /* preamble length */ + value |= (((u32)adapter->hw.preamble_len & MAC_CTRL_PRMLEN_MASK) << + MAC_CTRL_PRMLEN_SHIFT); + + /* vlan */ + if (adapter->vlgrp) + value |= MAC_CTRL_RMV_VLAN; + + /* filter mode */ + value |= MAC_CTRL_BC_EN; + if (netdev->flags & IFF_PROMISC) + value |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) + value |= MAC_CTRL_MC_ALL_EN; + + /* half retry buffer */ + value |= (((u32)(adapter->hw.retry_buf & + MAC_CTRL_HALF_LEFT_BUF_MASK)) << MAC_CTRL_HALF_LEFT_BUF_SHIFT); + + ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); +} + +static int atl2_check_link(struct atl2_adapter *adapter) +{ + struct atl2_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + int ret_val; + u16 speed, duplex, phy_data; + int reconfig = 0; + + /* MII_BMSR must read twise */ + atl2_read_phy_reg(hw, MII_BMSR, &phy_data); + atl2_read_phy_reg(hw, MII_BMSR, &phy_data); + if (!(phy_data&BMSR_LSTATUS)) { /* link down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + u32 value; + /* disable rx */ + value = ATL2_READ_REG(hw, REG_MAC_CTRL); + value &= ~MAC_CTRL_RX_EN; + ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + return 0; + } + + /* Link Up */ + ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) + return ret_val; + switch (hw->MediaType) { + case MEDIA_TYPE_100M_FULL: + if (speed != SPEED_100 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_HALF: + if (speed != SPEED_100 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_FULL: + if (speed != SPEED_10 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_HALF: + if (speed != SPEED_10 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + } + /* link result is our setting */ + if (reconfig == 0) { + if (adapter->link_speed != speed || + adapter->link_duplex != duplex) { + adapter->link_speed = speed; + adapter->link_duplex = duplex; + atl2_setup_mac_ctrl(adapter); + printk(KERN_INFO "%s: %s NIC Link is Up<%d Mbps %s>\n", + atl2_driver_name, netdev->name, + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full Duplex" : "Half Duplex"); + } + + if (!netif_carrier_ok(netdev)) { /* Link down -> Up */ + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } + return 0; + } + + /* change original link status */ + if (netif_carrier_ok(netdev)) { + u32 value; + /* disable rx */ + value = ATL2_READ_REG(hw, REG_MAC_CTRL); + value &= ~MAC_CTRL_RX_EN; + ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); + + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + + /* auto-neg, insert timer to re-config phy + * (if interval smaller than 5 seconds, something strange) */ + if (!test_bit(__ATL2_DOWN, &adapter->flags)) { + if (!test_and_set_bit(0, &adapter->cfg_phy)) + mod_timer(&adapter->phy_config_timer, jiffies + 5 * HZ); + } + + return 0; +} + +/* + * atl2_link_chg_task - deal with link change event Out of interrupt context + * @netdev: network interface device structure + */ +static void atl2_link_chg_task(struct work_struct *work) +{ + struct atl2_adapter *adapter; + unsigned long flags; + + adapter = container_of(work, struct atl2_adapter, link_chg_task); + + spin_lock_irqsave(&adapter->stats_lock, flags); + atl2_check_link(adapter); + spin_unlock_irqrestore(&adapter->stats_lock, flags); +} + +static void atl2_setup_pcicmd(struct pci_dev *pdev) +{ + u16 cmd; + + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + + if (cmd & PCI_COMMAND_INTX_DISABLE) + cmd &= ~PCI_COMMAND_INTX_DISABLE; + if (cmd & PCI_COMMAND_IO) + cmd &= ~PCI_COMMAND_IO; + if (0 == (cmd & PCI_COMMAND_MEMORY)) + cmd |= PCI_COMMAND_MEMORY; + if (0 == (cmd & PCI_COMMAND_MASTER)) + cmd |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + /* + * some motherboards BIOS(PXE/EFI) driver may set PME + * while they transfer control to OS (Windows/Linux) + * so we should clear this bit before NIC work normally + */ + pci_write_config_dword(pdev, REG_PM_CTRLSTAT, 0); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void atl2_poll_controller(struct net_device *netdev) +{ + disable_irq(netdev->irq); + atl2_intr(netdev->irq, netdev); + enable_irq(netdev->irq); +} +#endif + +/* + * atl2_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in atl2_pci_tbl + * + * Returns 0 on success, negative on failure + * + * atl2_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + */ +static int __devinit atl2_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct atl2_adapter *adapter; + static int cards_found; + unsigned long mmio_start; + int mmio_len; + int err; + + cards_found = 0; + + err = pci_enable_device(pdev); + if (err) + return err; + + /* + * atl2 is a shared-high-32-bit device, so we're stuck with 32-bit DMA + * until the kernel has the proper infrastructure to support 64-bit DMA + * on these devices. + */ + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) && + pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR "atl2: No usable DMA configuration, aborting\n"); + goto err_dma; + } + + /* Mark all PCI regions associated with PCI device + * pdev as being reserved by owner atl2_driver_name */ + err = pci_request_regions(pdev, atl2_driver_name); + if (err) + goto err_pci_reg; + + /* Enables bus-mastering on the device and calls + * pcibios_set_master to do the needed arch specific settings */ + pci_set_master(pdev); + + err = -ENOMEM; + netdev = alloc_etherdev(sizeof(struct atl2_adapter)); + if (!netdev) + goto err_alloc_etherdev; + + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->hw.back = adapter; + + mmio_start = pci_resource_start(pdev, 0x0); + mmio_len = pci_resource_len(pdev, 0x0); + + adapter->hw.mem_rang = (u32)mmio_len; + adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); + if (!adapter->hw.hw_addr) { + err = -EIO; + goto err_ioremap; + } + + atl2_setup_pcicmd(pdev); + + netdev->open = &atl2_open; + netdev->stop = &atl2_close; + netdev->hard_start_xmit = &atl2_xmit_frame; + netdev->get_stats = &atl2_get_stats; + netdev->set_multicast_list = &atl2_set_multi; + netdev->set_mac_address = &atl2_set_mac; + netdev->change_mtu = &atl2_change_mtu; + netdev->do_ioctl = &atl2_ioctl; + atl2_set_ethtool_ops(netdev); + +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = atl2_poll_controller; +#endif +#ifdef HAVE_TX_TIMEOUT + netdev->tx_timeout = &atl2_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; +#endif +#ifdef NETIF_F_HW_VLAN_TX + netdev->vlan_rx_register = atl2_vlan_rx_register; +#endif + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len; + adapter->bd_number = cards_found; + adapter->pci_using_64 = false; + + /* setup the private structure */ + err = atl2_sw_init(adapter); + if (err) + goto err_sw_init; + + err = -EIO; + +#ifdef NETIF_F_HW_VLAN_TX + 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); + + /* reset the controller to + * put the device in a known good starting state */ + + if (atl2_reset_hw(&adapter->hw)) { + err = -EIO; + goto err_reset; + } + + /* copy the MAC address out of the EEPROM */ + atl2_read_mac_addr(&adapter->hw); + memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); +/* FIXME: do we still need this? */ +#ifdef ETHTOOL_GPERMADDR + memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->perm_addr)) { +#else + if (!is_valid_ether_addr(netdev->dev_addr)) { +#endif + err = -EIO; + goto err_eeprom; + } + + atl2_check_options(adapter); + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &atl2_watchdog; + adapter->watchdog_timer.data = (unsigned long) adapter; + + init_timer(&adapter->phy_config_timer); + adapter->phy_config_timer.function = &atl2_phy_config; + adapter->phy_config_timer.data = (unsigned long) adapter; + + INIT_WORK(&adapter->reset_task, atl2_reset_task); + INIT_WORK(&adapter->link_chg_task, atl2_link_chg_task); + + strcpy(netdev->name, "eth%d"); /* ?? */ + err = register_netdev(netdev); + if (err) + goto err_register; + + /* assume we have no link for now */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + cards_found++; + + return 0; + +err_reset: +err_register: +err_sw_init: +err_eeprom: + iounmap(adapter->hw.hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/* + * atl2_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * atl2_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + */ +/* FIXME: write the original MAC address back in case it was changed from a + * BIOS-set value, as in atl1 -- CHS */ +static void __devexit atl2_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl2_adapter *adapter = netdev_priv(netdev); + + /* flush_scheduled work may reschedule our watchdog task, so + * explicitly disable watchdog tasks from being rescheduled */ + set_bit(__ATL2_DOWN, &adapter->flags); + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_config_timer); + + flush_scheduled_work(); + + unregister_netdev(netdev); + + atl2_force_ps(&adapter->hw); + + iounmap(adapter->hw.hw_addr); + pci_release_regions(pdev); + + free_netdev(netdev); + + pci_disable_device(pdev); +} + +static int atl2_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + u16 speed, duplex; + u32 ctrl = 0; + u32 wufc = adapter->wol; + +#ifdef CONFIG_PM + int retval = 0; +#endif + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags)); + atl2_down(adapter); + } + +#ifdef CONFIG_PM + retval = pci_save_state(pdev); + if (retval) + return retval; +#endif + + atl2_read_phy_reg(hw, MII_BMSR, (u16 *)&ctrl); + atl2_read_phy_reg(hw, MII_BMSR, (u16 *)&ctrl); + if (ctrl & BMSR_LSTATUS) + wufc &= ~ATLX_WUFC_LNKC; + + if (0 != (ctrl & BMSR_LSTATUS) && 0 != wufc) { + u32 ret_val; + /* get current link speed & duplex */ + ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) { + printk(KERN_DEBUG + "%s: get speed&duplex error while suspend\n", + atl2_driver_name); + goto wol_dis; + } + + ctrl = 0; + + /* turn on magic packet wol */ + if (wufc & ATLX_WUFC_MAG) + ctrl |= (WOL_MAGIC_EN | WOL_MAGIC_PME_EN); + + /* ignore Link Chg event when Link is up */ + ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl); + + /* Config MAC CTRL Register */ + ctrl = MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY; + if (FULL_DUPLEX == adapter->link_duplex) + ctrl |= MAC_CTRL_DUPLX; + ctrl |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); + ctrl |= (((u32)adapter->hw.preamble_len & + MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); + ctrl |= (((u32)(adapter->hw.retry_buf & + MAC_CTRL_HALF_LEFT_BUF_MASK)) << + MAC_CTRL_HALF_LEFT_BUF_SHIFT); + if (wufc & ATLX_WUFC_MAG) { + /* magic packet maybe Broadcast&multicast&Unicast */ + ctrl |= MAC_CTRL_BC_EN; + } + + ATL2_WRITE_REG(hw, REG_MAC_CTRL, ctrl); + + /* pcie patch */ + ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); + ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; + ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); + ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); + ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; + ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); + + pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); + goto suspend_exit; + } + + if (0 == (ctrl&BMSR_LSTATUS) && 0 != (wufc&ATLX_WUFC_LNKC)) { + /* link is down, so only LINK CHG WOL event enable */ + ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); + ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl); + ATL2_WRITE_REG(hw, REG_MAC_CTRL, 0); + + /* pcie patch */ + ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); + ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; + ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); + ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); + ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; + ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); + + hw->phy_configured = false; /* re-init PHY when resume */ + + pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); + + goto suspend_exit; + } + +wol_dis: + /* WOL disabled */ + ATL2_WRITE_REG(hw, REG_WOL_CTRL, 0); + + /* pcie patch */ + ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); + ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; + ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); + ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); + ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; + ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); + + atl2_force_ps(hw); + hw->phy_configured = false; /* re-init PHY when resume */ + + pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + +suspend_exit: + if (netif_running(netdev)) + atl2_free_irq(adapter); + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +#ifdef CONFIG_PM +static int atl2_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl2_adapter *adapter = netdev_priv(netdev); + u32 err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR + "atl2: Cannot enable PCI device from suspend\n"); + return err; + } + + pci_set_master(pdev); + + ATL2_READ_REG(&adapter->hw, REG_WOL_CTRL); /* clear WOL status */ + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + ATL2_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); + + err = atl2_request_irq(adapter); + if (netif_running(netdev) && err) + return err; + + atl2_reset_hw(&adapter->hw); + + if (netif_running(netdev)) + atl2_up(adapter); + + netif_device_attach(netdev); + + return 0; +} +#endif + +static void atl2_shutdown(struct pci_dev *pdev) +{ + atl2_suspend(pdev, PMSG_SUSPEND); +} + +static struct pci_driver atl2_driver = { + .name = atl2_driver_name, + .id_table = atl2_pci_tbl, + .probe = atl2_probe, + .remove = __devexit_p(atl2_remove), + /* Power Managment Hooks */ + .suspend = atl2_suspend, +#ifdef CONFIG_PM + .resume = atl2_resume, +#endif + .shutdown = atl2_shutdown, +}; + +/* + * atl2_init_module - Driver Registration Routine + * + * atl2_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + */ +static int __init atl2_init_module(void) +{ + printk(KERN_INFO "%s - version %s\n", atl2_driver_string, + atl2_driver_version); + printk(KERN_INFO "%s\n", atl2_copyright); + return pci_register_driver(&atl2_driver); +} +module_init(atl2_init_module); + +/* + * atl2_exit_module - Driver Exit Cleanup Routine + * + * atl2_exit_module is called just before the driver is removed + * from memory. + */ +static void __exit atl2_exit_module(void) +{ + pci_unregister_driver(&atl2_driver); +} +module_exit(atl2_exit_module); + +static void atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value) +{ + struct atl2_adapter *adapter = hw->back; + pci_read_config_word(adapter->pdev, reg, value); +} + +static void atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value) +{ + struct atl2_adapter *adapter = hw->back; + pci_write_config_word(adapter->pdev, reg, *value); +} + +static int atl2_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP); + ecmd->advertising = ADVERTISED_TP; + + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->advertising |= hw->autoneg_advertised; + + ecmd->port = PORT_TP; + ecmd->phy_address = 0; + ecmd->transceiver = XCVR_INTERNAL; + + if (adapter->link_speed != SPEED_0) { + ecmd->speed = adapter->link_speed; + if (adapter->link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = AUTONEG_ENABLE; + return 0; +} + +static int atl2_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + + while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags)) + msleep(1); + + if (ecmd->autoneg == AUTONEG_ENABLE) { +#define MY_ADV_MASK (ADVERTISE_10_HALF | \ + ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF| \ + ADVERTISE_100_FULL) + + if ((ecmd->advertising & MY_ADV_MASK) == MY_ADV_MASK) { + hw->MediaType = MEDIA_TYPE_AUTO_SENSOR; + hw->autoneg_advertised = MY_ADV_MASK; + } else if ((ecmd->advertising & MY_ADV_MASK) == + ADVERTISE_100_FULL) { + hw->MediaType = MEDIA_TYPE_100M_FULL; + hw->autoneg_advertised = ADVERTISE_100_FULL; + } else if ((ecmd->advertising & MY_ADV_MASK) == + ADVERTISE_100_HALF) { + hw->MediaType = MEDIA_TYPE_100M_HALF; + hw->autoneg_advertised = ADVERTISE_100_HALF; + } else if ((ecmd->advertising & MY_ADV_MASK) == + ADVERTISE_10_FULL) { + hw->MediaType = MEDIA_TYPE_10M_FULL; + hw->autoneg_advertised = ADVERTISE_10_FULL; + } else if ((ecmd->advertising & MY_ADV_MASK) == + ADVERTISE_10_HALF) { + hw->MediaType = MEDIA_TYPE_10M_HALF; + hw->autoneg_advertised = ADVERTISE_10_HALF; + } else { + clear_bit(__ATL2_RESETTING, &adapter->flags); + return -EINVAL; + } + ecmd->advertising = hw->autoneg_advertised | + ADVERTISED_TP | ADVERTISED_Autoneg; + } else { + clear_bit(__ATL2_RESETTING, &adapter->flags); + return -EINVAL; + } + + /* reset the link */ + if (netif_running(adapter->netdev)) { + atl2_down(adapter); + atl2_up(adapter); + } else + atl2_reset_hw(&adapter->hw); + + clear_bit(__ATL2_RESETTING, &adapter->flags); + 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; +} + +/* + * It's sane for this to be empty, but we might want to take advantage of this. + */ +static void atl2_set_msglevel(struct net_device *netdev, u32 data) +{ +} + +static int atl2_get_regs_len(struct net_device *netdev) +{ +#define ATL2_REGS_LEN 42 + return sizeof(u32) * ATL2_REGS_LEN; +} + +static void atl2_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + u32 *regs_buff = p; + u16 phy_data; + + memset(p, 0, sizeof(u32) * ATL2_REGS_LEN); + + regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; + + regs_buff[0] = ATL2_READ_REG(hw, REG_VPD_CAP); + regs_buff[1] = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); + regs_buff[2] = ATL2_READ_REG(hw, REG_SPI_FLASH_CONFIG); + regs_buff[3] = ATL2_READ_REG(hw, REG_TWSI_CTRL); + regs_buff[4] = ATL2_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL); + regs_buff[5] = ATL2_READ_REG(hw, REG_MASTER_CTRL); + regs_buff[6] = ATL2_READ_REG(hw, REG_MANUAL_TIMER_INIT); + regs_buff[7] = ATL2_READ_REG(hw, REG_IRQ_MODU_TIMER_INIT); + regs_buff[8] = ATL2_READ_REG(hw, REG_PHY_ENABLE); + regs_buff[9] = ATL2_READ_REG(hw, REG_CMBDISDMA_TIMER); + regs_buff[10] = ATL2_READ_REG(hw, REG_IDLE_STATUS); + regs_buff[11] = ATL2_READ_REG(hw, REG_MDIO_CTRL); + regs_buff[12] = ATL2_READ_REG(hw, REG_SERDES_LOCK); + regs_buff[13] = ATL2_READ_REG(hw, REG_MAC_CTRL); + regs_buff[14] = ATL2_READ_REG(hw, REG_MAC_IPG_IFG); + regs_buff[15] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR); + regs_buff[16] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR+4); + regs_buff[17] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE); + regs_buff[18] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE+4); + regs_buff[19] = ATL2_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL); + regs_buff[20] = ATL2_READ_REG(hw, REG_MTU); + regs_buff[21] = ATL2_READ_REG(hw, REG_WOL_CTRL); + regs_buff[22] = ATL2_READ_REG(hw, REG_SRAM_TXRAM_END); + regs_buff[23] = ATL2_READ_REG(hw, REG_DESC_BASE_ADDR_HI); + regs_buff[24] = ATL2_READ_REG(hw, REG_TXD_BASE_ADDR_LO); + regs_buff[25] = ATL2_READ_REG(hw, REG_TXD_MEM_SIZE); + regs_buff[26] = ATL2_READ_REG(hw, REG_TXS_BASE_ADDR_LO); + regs_buff[27] = ATL2_READ_REG(hw, REG_TXS_MEM_SIZE); + regs_buff[28] = ATL2_READ_REG(hw, REG_RXD_BASE_ADDR_LO); + regs_buff[29] = ATL2_READ_REG(hw, REG_RXD_BUF_NUM); + regs_buff[30] = ATL2_READ_REG(hw, REG_DMAR); + regs_buff[31] = ATL2_READ_REG(hw, REG_TX_CUT_THRESH); + regs_buff[32] = ATL2_READ_REG(hw, REG_DMAW); + regs_buff[33] = ATL2_READ_REG(hw, REG_PAUSE_ON_TH); + regs_buff[34] = ATL2_READ_REG(hw, REG_PAUSE_OFF_TH); + regs_buff[35] = ATL2_READ_REG(hw, REG_MB_TXD_WR_IDX); + regs_buff[36] = ATL2_READ_REG(hw, REG_MB_RXD_RD_IDX); + regs_buff[38] = ATL2_READ_REG(hw, REG_ISR); + regs_buff[39] = ATL2_READ_REG(hw, REG_IMR); + + atl2_read_phy_reg(hw, MII_BMCR, &phy_data); + regs_buff[40] = (u32)phy_data; + atl2_read_phy_reg(hw, MII_BMSR, &phy_data); + regs_buff[41] = (u32)phy_data; +} + +static int atl2_get_eeprom_len(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + if (!atl2_check_eeprom_exist(&adapter->hw)) + return 512; + else + return 0; +} + +static int atl2_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + u32 *eeprom_buff; + int first_dword, last_dword; + int ret_val = 0; + int i; + + if (eeprom->len == 0) + return -EINVAL; + + if (atl2_check_eeprom_exist(hw)) + return -EINVAL; + + eeprom->magic = hw->vendor_id | (hw->device_id << 16); + + first_dword = eeprom->offset >> 2; + last_dword = (eeprom->offset + eeprom->len - 1) >> 2; + + eeprom_buff = kmalloc(sizeof(u32) * (last_dword - first_dword + 1), + GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + for (i = first_dword; i < last_dword; i++) { + if (!atl2_read_eeprom(hw, i*4, &(eeprom_buff[i-first_dword]))) + return -EIO; + } + + memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3), + eeprom->len); + kfree(eeprom_buff); + + return ret_val; +} + +static int atl2_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + u32 *eeprom_buff; + u32 *ptr; + int max_len, first_dword, last_dword, ret_val = 0; + int i; + + if (eeprom->len == 0) + return -EOPNOTSUPP; + + if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) + return -EFAULT; + + max_len = 512; + + first_dword = eeprom->offset >> 2; + last_dword = (eeprom->offset + eeprom->len - 1) >> 2; + eeprom_buff = kmalloc(max_len, GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + ptr = (u32 *)eeprom_buff; + + if (eeprom->offset & 3) { + /* need read/modify/write of first changed EEPROM word */ + /* only the second byte of the word is being modified */ + if (!atl2_read_eeprom(hw, first_dword*4, &(eeprom_buff[0]))) + return -EIO; + ptr++; + } + if (((eeprom->offset + eeprom->len) & 3)) { + /* + * need read/modify/write of last changed EEPROM word + * only the first byte of the word is being modified + */ + if (!atl2_read_eeprom(hw, last_dword * 4, + &(eeprom_buff[last_dword - first_dword]))) + return -EIO; + } + + /* Device's eeprom is always little-endian, word addressable */ + memcpy(ptr, bytes, eeprom->len); + + for (i = 0; i < last_dword - first_dword + 1; i++) { + if (!atl2_write_eeprom(hw, ((first_dword+i)*4), eeprom_buff[i])) + return -EIO; + } + + kfree(eeprom_buff); + return ret_val; +} + +static void atl2_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + strncpy(drvinfo->driver, atl2_driver_name, 32); + strncpy(drvinfo->version, atl2_driver_version, 32); + strncpy(drvinfo->fw_version, "L2", 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + drvinfo->n_stats = 0; + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = atl2_get_regs_len(netdev); + drvinfo->eedump_len = atl2_get_eeprom_len(netdev); +} + +static void atl2_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + if (adapter->wol & ATLX_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & ATLX_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & ATLX_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & ATLX_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + if (adapter->wol & ATLX_WUFC_LNKC) + wol->wolopts |= WAKE_PHY; +} + +static int atl2_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + + if (wol->wolopts & (WAKE_MCAST|WAKE_BCAST|WAKE_MCAST)) + return -EOPNOTSUPP; + + /* these settings will always override what we currently have */ + adapter->wol = 0; + + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= ATLX_WUFC_MAG; + if (wol->wolopts & WAKE_PHY) + adapter->wol |= ATLX_WUFC_LNKC; + + return 0; +} + +static int atl2_nway_reset(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + if (netif_running(netdev)) + atl2_reinit_locked(adapter); + return 0; +} + +static struct ethtool_ops atl2_ethtool_ops = { + .get_settings = atl2_get_settings, + .set_settings = atl2_set_settings, + .get_drvinfo = atl2_get_drvinfo, + .get_regs_len = atl2_get_regs_len, + .get_regs = atl2_get_regs, + .get_wol = atl2_get_wol, + .set_wol = atl2_set_wol, + .get_msglevel = atl2_get_msglevel, + .set_msglevel = atl2_set_msglevel, + .nway_reset = atl2_nway_reset, + .get_link = ethtool_op_get_link, + .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) +{ + SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops); +} + +#define LBYTESWAP(a) ((((a) & 0x00ff00ff) << 8) | \ + (((a) & 0xff00ff00) >> 8)) +#define LONGSWAP(a) ((LBYTESWAP(a) << 16) | (LBYTESWAP(a) >> 16)) +#define SHORTSWAP(a) (((a) << 8) | ((a) >> 8)) + +/* + * Reset the transmit and receive units; mask and clear all interrupts. + * + * hw - Struct containing variables accessed by shared code + * return : 0 or idle status (if error) + */ +static s32 atl2_reset_hw(struct atl2_hw *hw) +{ + u32 icr; + u16 pci_cfg_cmd_word; + int i; + + /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ + atl2_read_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word); + if ((pci_cfg_cmd_word & + (CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER)) != + (CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER)) { + pci_cfg_cmd_word |= + (CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER); + atl2_write_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word); + } + + /* Clear Interrupt mask to stop board from generating + * interrupts & Clear any pending interrupt events + */ + /* FIXME */ + /* ATL2_WRITE_REG(hw, REG_IMR, 0); */ + /* ATL2_WRITE_REG(hw, REG_ISR, 0xffffffff); */ + + /* Issue Soft Reset to the MAC. This will reset the chip's + * transmit, receive, DMA. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST); + wmb(); + msleep(1); /* delay about 1ms */ + + /* Wait at least 10ms for All module to be Idle */ + for (i = 0; i < 10; i++) { + icr = ATL2_READ_REG(hw, REG_IDLE_STATUS); + if (!icr) + break; + msleep(1); /* delay 1 ms */ + cpu_relax(); + } + + if (icr) + return icr; + + return 0; +} + +#define CUSTOM_SPI_CS_SETUP 2 +#define CUSTOM_SPI_CLK_HI 2 +#define CUSTOM_SPI_CLK_LO 2 +#define CUSTOM_SPI_CS_HOLD 2 +#define CUSTOM_SPI_CS_HI 3 + +static struct atl2_spi_flash_dev flash_table[] = +{ +/* MFR WRSR READ PROGRAM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */ +{"Atmel", 0x0, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62 }, +{"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60 }, +{"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7 }, +}; + +static bool atl2_spi_read(struct atl2_hw *hw, u32 addr, u32 *buf) +{ + int i; + u32 value; + + ATL2_WRITE_REG(hw, REG_SPI_DATA, 0); + ATL2_WRITE_REG(hw, REG_SPI_ADDR, addr); + + value = SPI_FLASH_CTRL_WAIT_READY | + (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) << + SPI_FLASH_CTRL_CS_SETUP_SHIFT | + (CUSTOM_SPI_CLK_HI & SPI_FLASH_CTRL_CLK_HI_MASK) << + SPI_FLASH_CTRL_CLK_HI_SHIFT | + (CUSTOM_SPI_CLK_LO & SPI_FLASH_CTRL_CLK_LO_MASK) << + SPI_FLASH_CTRL_CLK_LO_SHIFT | + (CUSTOM_SPI_CS_HOLD & SPI_FLASH_CTRL_CS_HOLD_MASK) << + SPI_FLASH_CTRL_CS_HOLD_SHIFT | + (CUSTOM_SPI_CS_HI & SPI_FLASH_CTRL_CS_HI_MASK) << + SPI_FLASH_CTRL_CS_HI_SHIFT | + (0x1 & SPI_FLASH_CTRL_INS_MASK) << SPI_FLASH_CTRL_INS_SHIFT; + + ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); + + value |= SPI_FLASH_CTRL_START; + + ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); + + for (i = 0; i < 10; i++) { + msleep(1); + value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); + if (!(value & SPI_FLASH_CTRL_START)) + break; + } + + if (value & SPI_FLASH_CTRL_START) + return false; + + *buf = ATL2_READ_REG(hw, REG_SPI_DATA); + + return true; +} + +/* + * get_permanent_address + * return 0 if get valid mac address, + */ +static int get_permanent_address(struct atl2_hw *hw) +{ + u32 Addr[2]; + u32 i, Control; + u16 Register; + u8 EthAddr[NODE_ADDRESS_SIZE]; + bool KeyValid; + + if (is_valid_ether_addr(hw->perm_mac_addr)) + return 0; + + Addr[0] = 0; + Addr[1] = 0; + + if (!atl2_check_eeprom_exist(hw)) { /* eeprom exists */ + Register = 0; + KeyValid = false; + + /* Read out all EEPROM content */ + i = 0; + while (1) { + if (atl2_read_eeprom(hw, i + 0x100, &Control)) { + if (KeyValid) { + if (Register == REG_MAC_STA_ADDR) + Addr[0] = Control; + else if (Register == + (REG_MAC_STA_ADDR + 4)) + Addr[1] = Control; + KeyValid = false; + } else if ((Control & 0xff) == 0x5A) { + KeyValid = true; + Register = (u16) (Control >> 16); + } else { + /* assume data end while encount an invalid KEYWORD */ + break; + } + } else { + break; /* read error */ + } + i += 4; + } + + *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); + *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]); + + if (is_valid_ether_addr(EthAddr)) { + memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); + return 0; + } + return 1; + } + + /* see if SPI flash exists? */ + Addr[0] = 0; + Addr[1] = 0; + Register = 0; + KeyValid = false; + i = 0; + while (1) { + if (atl2_spi_read(hw, i + 0x1f000, &Control)) { + if (KeyValid) { + if (Register == REG_MAC_STA_ADDR) + Addr[0] = Control; + else if (Register == (REG_MAC_STA_ADDR + 4)) + Addr[1] = Control; + KeyValid = false; + } else if ((Control & 0xff) == 0x5A) { + KeyValid = true; + Register = (u16) (Control >> 16); + } else { + break; /* data end */ + } + } else { + break; /* read error */ + } + i += 4; + } + + *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); + *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *)&Addr[1]); + if (is_valid_ether_addr(EthAddr)) { + memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); + return 0; + } + /* maybe MAC-address is from BIOS */ + Addr[0] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR); + Addr[1] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR + 4); + *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); + *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]); + + if (is_valid_ether_addr(EthAddr)) { + memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); + return 0; + } + + return 1; +} + +/* + * Reads the adapter's MAC address from the EEPROM + * + * hw - Struct containing variables accessed by shared code + */ +static s32 atl2_read_mac_addr(struct atl2_hw *hw) +{ + u16 i; + + if (get_permanent_address(hw)) { + /* for test */ + /* FIXME: shouldn't we use random_ether_addr() here? */ + hw->perm_mac_addr[0] = 0x00; + hw->perm_mac_addr[1] = 0x13; + hw->perm_mac_addr[2] = 0x74; + hw->perm_mac_addr[3] = 0x00; + hw->perm_mac_addr[4] = 0x5c; + hw->perm_mac_addr[5] = 0x38; + } + + for (i = 0; i < NODE_ADDRESS_SIZE; i++) + hw->mac_addr[i] = hw->perm_mac_addr[i]; + + return 0; +} + +/* + * Hashes an address to determine its location in the multicast table + * + * hw - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + * + * atl2_hash_mc_addr + * purpose + * set hash value for a multicast address + * hash calcu processing : + * 1. calcu 32bit CRC for multicast address + * 2. reverse crc with MSB to LSB + */ +static u32 atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr) +{ + u32 crc32, value; + int i; + + value = 0; + crc32 = ether_crc_le(6, mc_addr); + + for (i = 0; i < 32; i++) + value |= (((crc32 >> i) & 1) << (31 - i)); + + return value; +} + +/* + * Sets the bit in the multicast table corresponding to the hash value. + * + * hw - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + */ +static void atl2_hash_set(struct atl2_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg; + u32 mta; + + /* The HASH Table is a register array of 2 32-bit registers. + * It is treated like an array of 64 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 31) & 0x1; + hash_bit = (hash_value >> 26) & 0x1F; + + mta = ATL2_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg); + + mta |= (1 << hash_bit); + + ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta); +} + +/* + * atl2_init_pcie - init PCIE module + */ +static void atl2_init_pcie(struct atl2_hw *hw) +{ + u32 value; + value = LTSSM_TEST_MODE_DEF; + ATL2_WRITE_REG(hw, REG_LTSSM_TEST_MODE, value); + + value = PCIE_DLL_TX_CTRL1_DEF; + ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, value); +} + +static void atl2_init_flash_opcode(struct atl2_hw *hw) +{ + if (hw->flash_vendor >= ARRAY_SIZE(flash_table)) + hw->flash_vendor = 0; /* ATMEL */ + + /* Init OP table */ + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_PROGRAM, + flash_table[hw->flash_vendor].cmdPROGRAM); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_SC_ERASE, + flash_table[hw->flash_vendor].cmdSECTOR_ERASE); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_CHIP_ERASE, + flash_table[hw->flash_vendor].cmdCHIP_ERASE); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDID, + flash_table[hw->flash_vendor].cmdRDID); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WREN, + flash_table[hw->flash_vendor].cmdWREN); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDSR, + flash_table[hw->flash_vendor].cmdRDSR); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WRSR, + flash_table[hw->flash_vendor].cmdWRSR); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_READ, + flash_table[hw->flash_vendor].cmdREAD); +} + +/******************************************************************** +* Performs basic configuration of the adapter. +* +* hw - Struct containing variables accessed by shared code +* Assumes that the controller has previously been reset and is in a +* post-reset uninitialized state. Initializes multicast table, +* and Calls routines to setup link +* Leaves the transmit and receive units disabled and uninitialized. +********************************************************************/ +static s32 atl2_init_hw(struct atl2_hw *hw) +{ + u32 ret_val = 0; + + atl2_init_pcie(hw); + + /* Zero out the Multicast HASH table */ + /* clear the old settings from the multicast hash table */ + ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); + ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); + + atl2_init_flash_opcode(hw); + + ret_val = atl2_phy_init(hw); + + return ret_val; +} + +/* + * Detects the current speed and duplex settings of the hardware. + * + * hw - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + */ +static s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed, + u16 *duplex) +{ + s32 ret_val; + u16 phy_data; + + /* Read PHY Specific Status Register (17) */ + ret_val = atl2_read_phy_reg(hw, MII_ATLX_PSSR, &phy_data); + if (ret_val) + return ret_val; + + if (!(phy_data & MII_ATLX_PSSR_SPD_DPLX_RESOLVED)) + return ATLX_ERR_PHY_RES; + + switch (phy_data & MII_ATLX_PSSR_SPEED) { + case MII_ATLX_PSSR_100MBS: + *speed = SPEED_100; + break; + case MII_ATLX_PSSR_10MBS: + *speed = SPEED_10; + break; + default: + return ATLX_ERR_PHY_SPEED; + break; + } + + if (phy_data & MII_ATLX_PSSR_DPLX) + *duplex = FULL_DUPLEX; + else + *duplex = HALF_DUPLEX; + + return 0; +} + +/* + * Reads the value from a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to read + */ +static s32 atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data) +{ + u32 val; + int i; + + val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | + MDIO_START | + MDIO_SUP_PREAMBLE | + MDIO_RW | + MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; + ATL2_WRITE_REG(hw, REG_MDIO_CTRL, val); + + wmb(); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ATL2_READ_REG(hw, REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + wmb(); + } + if (!(val & (MDIO_START | MDIO_BUSY))) { + *phy_data = (u16)val; + return 0; + } + + return ATLX_ERR_PHY; +} + +/* + * Writes a value to a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to write + * data - data to write to the PHY + */ +static s32 atl2_write_phy_reg(struct atl2_hw *hw, u32 reg_addr, u16 phy_data) +{ + int i; + u32 val; + + val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | + (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | + MDIO_SUP_PREAMBLE | + MDIO_START | + MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; + ATL2_WRITE_REG(hw, REG_MDIO_CTRL, val); + + wmb(); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ATL2_READ_REG(hw, REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + + wmb(); + } + + if (!(val & (MDIO_START | MDIO_BUSY))) + return 0; + + return ATLX_ERR_PHY; +} + +/* + * Configures PHY autoneg and flow control advertisement settings + * + * hw - Struct containing variables accessed by shared code + */ +static s32 atl2_phy_setup_autoneg_adv(struct atl2_hw *hw) +{ + s32 ret_val; + s16 mii_autoneg_adv_reg; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK; + + /* Need to parse autoneg_advertised and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). */ + mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK; + + /* Need to parse MediaType and setup the + * appropriate PHY registers. */ + switch (hw->MediaType) { + case MEDIA_TYPE_AUTO_SENSOR: + mii_autoneg_adv_reg |= + (MII_AR_10T_HD_CAPS | + MII_AR_10T_FD_CAPS | + MII_AR_100TX_HD_CAPS| + MII_AR_100TX_FD_CAPS); + hw->autoneg_advertised = + ADVERTISE_10_HALF | + ADVERTISE_10_FULL | + ADVERTISE_100_HALF| + ADVERTISE_100_FULL; + break; + case MEDIA_TYPE_100M_FULL: + mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS; + hw->autoneg_advertised = ADVERTISE_100_FULL; + break; + case MEDIA_TYPE_100M_HALF: + mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS; + hw->autoneg_advertised = ADVERTISE_100_HALF; + break; + case MEDIA_TYPE_10M_FULL: + mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS; + hw->autoneg_advertised = ADVERTISE_10_FULL; + break; + default: + mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS; + hw->autoneg_advertised = ADVERTISE_10_HALF; + break; + } + + /* flow control fixed to enable all */ + mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE); + + hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; + + ret_val = atl2_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg); + + if (ret_val) + return ret_val; + + return 0; +} + +/* + * Resets the PHY and make all config validate + * + * hw - Struct containing variables accessed by shared code + * + * Sets bit 15 and 12 of the MII Control regiser (for F001 bug) + */ +static s32 atl2_phy_commit(struct atl2_hw *hw) +{ + s32 ret_val; + u16 phy_data; + + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG; + ret_val = atl2_write_phy_reg(hw, MII_BMCR, phy_data); + if (ret_val) { + u32 val; + int i; + /* pcie serdes link may be down ! */ + for (i = 0; i < 25; i++) { + msleep(1); + val = ATL2_READ_REG(hw, REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if (0 != (val & (MDIO_START | MDIO_BUSY))) { + printk(KERN_ERR "atl2: PCIe link down for at least 25ms !\n"); + return ret_val; + } + } + return 0; +} + +static s32 atl2_phy_init(struct atl2_hw *hw) +{ + s32 ret_val; + u16 phy_val; + + if (hw->phy_configured) + return 0; + + /* Enable PHY */ + ATL2_WRITE_REGW(hw, REG_PHY_ENABLE, 1); + ATL2_WRITE_FLUSH(hw); + msleep(1); + + /* check if the PHY is in powersaving mode */ + atl2_write_phy_reg(hw, MII_DBG_ADDR, 0); + atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val); + + /* 024E / 124E 0r 0274 / 1274 ? */ + if (phy_val & 0x1000) { + phy_val &= ~0x1000; + atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val); + } + + msleep(1); + + /*Enable PHY LinkChange Interrupt */ + ret_val = atl2_write_phy_reg(hw, 18, 0xC00); + if (ret_val) + return ret_val; + + /* setup AutoNeg parameters */ + ret_val = atl2_phy_setup_autoneg_adv(hw); + if (ret_val) + return ret_val; + + /* SW.Reset & En-Auto-Neg to restart Auto-Neg */ + ret_val = atl2_phy_commit(hw); + if (ret_val) + return ret_val; + + hw->phy_configured = true; + + return ret_val; +} + +static void atl2_set_mac_addr(struct atl2_hw *hw) +{ + u32 value; + /* 00-0B-6A-F6-00-DC + * 0: 6AF600DC 1: 000B + * low dword */ + value = (((u32)hw->mac_addr[2]) << 24) | + (((u32)hw->mac_addr[3]) << 16) | + (((u32)hw->mac_addr[4]) << 8) | + (((u32)hw->mac_addr[5])); + ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value); + /* hight dword */ + value = (((u32)hw->mac_addr[0]) << 8) | + (((u32)hw->mac_addr[1])); + ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value); +} + +/* + * check_eeprom_exist + * return 0 if eeprom exist + */ +static int atl2_check_eeprom_exist(struct atl2_hw *hw) +{ + u32 value; + + value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); + if (value & SPI_FLASH_CTRL_EN_VPD) { + value &= ~SPI_FLASH_CTRL_EN_VPD; + ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); + } + value = ATL2_READ_REGW(hw, REG_PCIE_CAP_LIST); + return ((value & 0xFF00) == 0x6C00) ? 0 : 1; +} + +/* FIXME: This doesn't look right. -- CHS */ +static bool atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value) +{ + return true; +} + +static bool atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue) +{ + int i; + u32 Control; + + if (Offset & 0x3) + return false; /* address do not align */ + + ATL2_WRITE_REG(hw, REG_VPD_DATA, 0); + Control = (Offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT; + ATL2_WRITE_REG(hw, REG_VPD_CAP, Control); + + for (i = 0; i < 10; i++) { + msleep(2); + Control = ATL2_READ_REG(hw, REG_VPD_CAP); + if (Control & VPD_CAP_VPD_FLAG) + break; + } + + if (Control & VPD_CAP_VPD_FLAG) { + *pValue = ATL2_READ_REG(hw, REG_VPD_DATA); + return true; + } + return false; /* timeout */ +} + +static void atl2_force_ps(struct atl2_hw *hw) +{ + u16 phy_val; + + atl2_write_phy_reg(hw, MII_DBG_ADDR, 0); + atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val); + atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val | 0x1000); + + atl2_write_phy_reg(hw, MII_DBG_ADDR, 2); + atl2_write_phy_reg(hw, MII_DBG_DATA, 0x3000); + atl2_write_phy_reg(hw, MII_DBG_ADDR, 3); + atl2_write_phy_reg(hw, MII_DBG_DATA, 0); +} + +/* This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ +#define ATL2_MAX_NIC 4 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +/* All parameters are treated the same, as an integer array of values. + * This macro just reduces the need to repeat the same declaration code + * over and over (plus this helps to avoid typo bugs). + */ +#define ATL2_PARAM_INIT {[0 ... ATL2_MAX_NIC] = OPTION_UNSET} +#ifndef module_param_array +/* Module Parameters are always initialized to -1, so that the driver + * can tell the difference between no user specified value or the + * user asking for the default value. + * The true default values are loaded in when atl2_check_options is called. + * + * This is a GCC extension to ANSI C. + * See the item "Labeled Elements in Initializers" in the section + * "Extensions to the C Language Family" of the GCC documentation. + */ + +#define ATL2_PARAM(X, desc) \ + static const int __devinitdata X[ATL2_MAX_NIC + 1] = ATL2_PARAM_INIT; \ + MODULE_PARM(X, "1-" __MODULE_STRING(ATL2_MAX_NIC) "i"); \ + MODULE_PARM_DESC(X, desc); +#else +#define ATL2_PARAM(X, desc) \ + static int __devinitdata X[ATL2_MAX_NIC+1] = ATL2_PARAM_INIT; \ + static int num_##X = 0; \ + module_param_array_named(X, X, int, &num_##X, 0); \ + MODULE_PARM_DESC(X, desc); +#endif + +/* + * Transmit Memory Size + * Valid Range: 64-2048 + * Default Value: 128 + */ +#define ATL2_MIN_TX_MEMSIZE 4 /* 4KB */ +#define ATL2_MAX_TX_MEMSIZE 64 /* 64KB */ +#define ATL2_DEFAULT_TX_MEMSIZE 8 /* 8KB */ +ATL2_PARAM(TxMemSize, "Bytes of Transmit Memory"); + +/* + * Receive Memory Block Count + * Valid Range: 16-512 + * Default Value: 128 + */ +#define ATL2_MIN_RXD_COUNT 16 +#define ATL2_MAX_RXD_COUNT 512 +#define ATL2_DEFAULT_RXD_COUNT 64 +ATL2_PARAM(RxMemBlock, "Number of receive memory block"); + +/* + * User Specified MediaType Override + * + * Valid Range: 0-5 + * - 0 - auto-negotiate at all supported speeds + * - 1 - only link at 1000Mbps Full Duplex + * - 2 - only link at 100Mbps Full Duplex + * - 3 - only link at 100Mbps Half Duplex + * - 4 - only link at 10Mbps Full Duplex + * - 5 - only link at 10Mbps Half Duplex + * Default Value: 0 + */ +ATL2_PARAM(MediaType, "MediaType Select"); + +/* + * Interrupt Moderate Timer in units of 2048 ns (~2 us) + * Valid Range: 10-65535 + * Default Value: 45000(90ms) + */ +#define INT_MOD_DEFAULT_CNT 100 /* 200us */ +#define INT_MOD_MAX_CNT 65000 +#define INT_MOD_MIN_CNT 50 +ATL2_PARAM(IntModTimer, "Interrupt Moderator Timer"); + +/* + * FlashVendor + * Valid Range: 0-2 + * 0 - Atmel + * 1 - SST + * 2 - ST + */ +ATL2_PARAM(FlashVendor, "SPI Flash Vendor"); + +#define AUTONEG_ADV_DEFAULT 0x2F +#define AUTONEG_ADV_MASK 0x2F +#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL + +#define FLASH_VENDOR_DEFAULT 0 +#define FLASH_VENDOR_MIN 0 +#define FLASH_VENDOR_MAX 2 + +struct atl2_option { + enum { enable_option, range_option, list_option } type; + char *name; + char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct atl2_opt_list { int i; char *str; } *p; + } l; + } arg; +}; + +static int __devinit atl2_validate_option(int *value, struct atl2_option *opt) +{ + int i; + struct atl2_opt_list *ent; + + if (*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + printk(KERN_INFO "%s Enabled\n", opt->name); + return 0; + break; + case OPTION_DISABLED: + printk(KERN_INFO "%s Disabled\n", opt->name); + return 0; + break; + } + break; + case range_option: + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + printk(KERN_INFO "%s set to %i\n", opt->name, *value); + return 0; + } + break; + case list_option: + for (i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if (*value == ent->i) { + if (ent->str[0] != '\0') + printk(KERN_INFO "%s\n", ent->str); + return 0; + } + } + break; + default: + BUG(); + } + + printk(KERN_INFO "Invalid %s specified (%i) %s\n", + opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +/* + * atl2_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line parameters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + */ +static void __devinit atl2_check_options(struct atl2_adapter *adapter) +{ + int val; + struct atl2_option opt; + int bd = adapter->bd_number; + if (bd >= ATL2_MAX_NIC) { + printk(KERN_NOTICE "Warning: no configuration for board #%i\n", + bd); + printk(KERN_NOTICE "Using defaults for all values\n"); +#ifndef module_param_array + bd = ATL2_MAX_NIC; +#endif + } + + /* Bytes of Transmit Memory */ + opt.type = range_option; + opt.name = "Bytes of Transmit Memory"; + opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_TX_MEMSIZE); + opt.def = ATL2_DEFAULT_TX_MEMSIZE; + opt.arg.r.min = ATL2_MIN_TX_MEMSIZE; + opt.arg.r.max = ATL2_MAX_TX_MEMSIZE; +#ifdef module_param_array + if (num_TxMemSize > bd) { +#endif + val = TxMemSize[bd]; + atl2_validate_option(&val, &opt); + adapter->txd_ring_size = ((u32) val) * 1024; +#ifdef module_param_array + } else + adapter->txd_ring_size = ((u32)opt.def) * 1024; +#endif + /* txs ring size: */ + adapter->txs_ring_size = adapter->txd_ring_size / 128; + if (adapter->txs_ring_size > 160) + adapter->txs_ring_size = 160; + + /* Receive Memory Block Count */ + opt.type = range_option; + opt.name = "Number of receive memory block"; + opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_RXD_COUNT); + opt.def = ATL2_DEFAULT_RXD_COUNT; + opt.arg.r.min = ATL2_MIN_RXD_COUNT; + opt.arg.r.max = ATL2_MAX_RXD_COUNT; +#ifdef module_param_array + if (num_RxMemBlock > bd) { +#endif + val = RxMemBlock[bd]; + atl2_validate_option(&val, &opt); + adapter->rxd_ring_size = (u32)val; + /* FIXME */ + /* ((u16)val)&~1; */ /* even number */ +#ifdef module_param_array + } else + adapter->rxd_ring_size = (u32)opt.def; +#endif + /* init RXD Flow control value */ + adapter->hw.fc_rxd_hi = (adapter->rxd_ring_size / 8) * 7; + adapter->hw.fc_rxd_lo = (ATL2_MIN_RXD_COUNT / 8) > + (adapter->rxd_ring_size / 12) ? (ATL2_MIN_RXD_COUNT / 8) : + (adapter->rxd_ring_size / 12); + + /* Interrupt Moderate Timer */ + opt.type = range_option; + opt.name = "Interrupt Moderate Timer"; + opt.err = "using default of " __MODULE_STRING(INT_MOD_DEFAULT_CNT); + opt.def = INT_MOD_DEFAULT_CNT; + opt.arg.r.min = INT_MOD_MIN_CNT; + opt.arg.r.max = INT_MOD_MAX_CNT; +#ifdef module_param_array + if (num_IntModTimer > bd) { +#endif + val = IntModTimer[bd]; + atl2_validate_option(&val, &opt); + adapter->imt = (u16) val; +#ifdef module_param_array + } else + adapter->imt = (u16)(opt.def); +#endif + /* Flash Vendor */ + opt.type = range_option; + opt.name = "SPI Flash Vendor"; + opt.err = "using default of " __MODULE_STRING(FLASH_VENDOR_DEFAULT); + opt.def = FLASH_VENDOR_DEFAULT; + opt.arg.r.min = FLASH_VENDOR_MIN; + opt.arg.r.max = FLASH_VENDOR_MAX; +#ifdef module_param_array + if (num_FlashVendor > bd) { +#endif + val = FlashVendor[bd]; + atl2_validate_option(&val, &opt); + adapter->hw.flash_vendor = (u8) val; +#ifdef module_param_array + } else + adapter->hw.flash_vendor = (u8)(opt.def); +#endif + /* MediaType */ + opt.type = range_option; + opt.name = "Speed/Duplex Selection"; + opt.err = "using default of " __MODULE_STRING(MEDIA_TYPE_AUTO_SENSOR); + opt.def = MEDIA_TYPE_AUTO_SENSOR; + opt.arg.r.min = MEDIA_TYPE_AUTO_SENSOR; + opt.arg.r.max = MEDIA_TYPE_10M_HALF; +#ifdef module_param_array + if (num_MediaType > bd) { +#endif + val = MediaType[bd]; + atl2_validate_option(&val, &opt); + adapter->hw.MediaType = (u16) val; +#ifdef module_param_array + } else + adapter->hw.MediaType = (u16)(opt.def); +#endif +} diff --git a/drivers/net/atlx/atl2.h b/drivers/net/atlx/atl2.h new file mode 100644 index 00000000000..09974df76b1 --- /dev/null +++ b/drivers/net/atlx/atl2.h @@ -0,0 +1,529 @@ +/* atl2.h -- atl2 driver definitions + * + * Copyright(c) 2007 Atheros Corporation. All rights reserved. + * Copyright(c) 2006 xiong huang <xiong.huang@atheros.com> + * Copyright(c) 2007 Chris Snook <csnook@redhat.com> + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * 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; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _ATL2_H_ +#define _ATL2_H_ + +#include <asm/atomic.h> +#include <linux/netdevice.h> + +#ifndef _ATL2_HW_H_ +#define _ATL2_HW_H_ + +#ifndef _ATL2_OSDEP_H_ +#define _ATL2_OSDEP_H_ + +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/if_ether.h> + +#include "atlx.h" + +#ifdef ETHTOOL_OPS_COMPAT +extern int ethtool_ioctl(struct ifreq *ifr); +#endif + +#define PCI_COMMAND_REGISTER PCI_COMMAND +#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE +#define ETH_ADDR_LEN ETH_ALEN + +#define ATL2_WRITE_REG(a, reg, value) (iowrite32((value), \ + ((a)->hw_addr + (reg)))) + +#define ATL2_WRITE_FLUSH(a) (ioread32((a)->hw_addr)) + +#define ATL2_READ_REG(a, reg) (ioread32((a)->hw_addr + (reg))) + +#define ATL2_WRITE_REGB(a, reg, value) (iowrite8((value), \ + ((a)->hw_addr + (reg)))) + +#define ATL2_READ_REGB(a, reg) (ioread8((a)->hw_addr + (reg))) + +#define ATL2_WRITE_REGW(a, reg, value) (iowrite16((value), \ + ((a)->hw_addr + (reg)))) + +#define ATL2_READ_REGW(a, reg) (ioread16((a)->hw_addr + (reg))) + +#define ATL2_WRITE_REG_ARRAY(a, reg, offset, value) \ + (iowrite32((value), (((a)->hw_addr + (reg)) + ((offset) << 2)))) + +#define ATL2_READ_REG_ARRAY(a, reg, offset) \ + (ioread32(((a)->hw_addr + (reg)) + ((offset) << 2))) + +#endif /* _ATL2_OSDEP_H_ */ + +struct atl2_adapter; +struct atl2_hw; + +/* function prototype */ +static s32 atl2_reset_hw(struct atl2_hw *hw); +static s32 atl2_read_mac_addr(struct atl2_hw *hw); +static s32 atl2_init_hw(struct atl2_hw *hw); +static s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed, + u16 *duplex); +static u32 atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr); +static void atl2_hash_set(struct atl2_hw *hw, u32 hash_value); +static s32 atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data); +static s32 atl2_write_phy_reg(struct atl2_hw *hw, u32 reg_addr, u16 phy_data); +static void atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value); +static void atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value); +static void atl2_set_mac_addr(struct atl2_hw *hw); +static bool atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue); +static bool atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value); +static s32 atl2_phy_init(struct atl2_hw *hw); +static int atl2_check_eeprom_exist(struct atl2_hw *hw); +static void atl2_force_ps(struct atl2_hw *hw); + +/* register definition */ + +/* Block IDLE Status Register */ +#define IDLE_STATUS_RXMAC 1 /* 1: RXMAC is non-IDLE */ +#define IDLE_STATUS_TXMAC 2 /* 1: TXMAC is non-IDLE */ +#define IDLE_STATUS_DMAR 8 /* 1: DMAR is non-IDLE */ +#define IDLE_STATUS_DMAW 4 /* 1: DMAW is non-IDLE */ + +/* MDIO Control Register */ +#define MDIO_WAIT_TIMES 10 + +/* MAC Control Register */ +#define MAC_CTRL_DBG_TX_BKPRESURE 0x100000 /* 1: TX max backoff */ +#define MAC_CTRL_MACLP_CLK_PHY 0x8000000 /* 1: 25MHz from phy */ +#define MAC_CTRL_HALF_LEFT_BUF_SHIFT 28 +#define MAC_CTRL_HALF_LEFT_BUF_MASK 0xF /* MAC retry buf x32B */ + +/* Internal SRAM Partition Register */ +#define REG_SRAM_TXRAM_END 0x1500 /* Internal tail address of TXRAM + * default: 2byte*1024 */ +#define REG_SRAM_RXRAM_END 0x1502 /* Internal tail address of RXRAM + * default: 2byte*1024 */ + +/* Descriptor Control register */ +#define REG_TXD_BASE_ADDR_LO 0x1544 /* The base address of the Transmit + * Data Mem low 32-bit(dword align) */ +#define REG_TXD_MEM_SIZE 0x1548 /* Transmit Data Memory size(by + * double word , max 256KB) */ +#define REG_TXS_BASE_ADDR_LO 0x154C /* The base address of the Transmit + * Status Memory low 32-bit(dword word + * align) */ +#define REG_TXS_MEM_SIZE 0x1550 /* double word unit, max 4*2047 + * bytes. */ +#define REG_RXD_BASE_ADDR_LO 0x1554 /* The base address of the Transmit + * Status Memory low 32-bit(unit 8 + * bytes) */ +#define REG_RXD_BUF_NUM 0x1558 /* Receive Data & Status Memory buffer + * number (unit 1536bytes, max + * 1536*2047) */ + +/* DMAR Control Register */ +#define REG_DMAR 0x1580 +#define DMAR_EN 0x1 /* 1: Enable DMAR */ + +/* TX Cur-Through (early tx threshold) Control Register */ +#define REG_TX_CUT_THRESH 0x1590 /* TxMac begin transmit packet + * threshold(unit word) */ + +/* DMAW Control Register */ +#define REG_DMAW 0x15A0 +#define DMAW_EN 0x1 + +/* Flow control register */ +#define REG_PAUSE_ON_TH 0x15A8 /* RXD high watermark of overflow + * threshold configuration register */ +#define REG_PAUSE_OFF_TH 0x15AA /* RXD lower watermark of overflow + * threshold configuration register */ + +/* Mailbox Register */ +#define REG_MB_TXD_WR_IDX 0x15f0 /* double word align */ +#define REG_MB_RXD_RD_IDX 0x15F4 /* RXD Read index (unit: 1536byets) */ + +/* Interrupt Status Register */ +#define ISR_TIMER 1 /* Interrupt when Timer counts down to zero */ +#define ISR_MANUAL 2 /* Software manual interrupt, for debug. Set + * when SW_MAN_INT_EN is set in Table 51 + * Selene Master Control Register + * (Offset 0x1400). */ +#define ISR_RXF_OV 4 /* RXF overflow interrupt */ +#define ISR_TXF_UR 8 /* TXF underrun interrupt */ +#define ISR_TXS_OV 0x10 /* Internal transmit status buffer full + * interrupt */ +#define ISR_RXS_OV 0x20 /* Internal receive status buffer full + * interrupt */ +#define ISR_LINK_CHG 0x40 /* Link Status Change Interrupt */ +#define ISR_HOST_TXD_UR 0x80 +#define ISR_HOST_RXD_OV 0x100 /* Host rx data memory full , one pulse */ +#define ISR_DMAR_TO_RST 0x200 /* DMAR op timeout interrupt. SW should + * do Reset */ +#define ISR_DMAW_TO_RST 0x400 +#define ISR_PHY 0x800 /* phy interrupt */ +#define ISR_TS_UPDATE 0x10000 /* interrupt after new tx pkt status written + * to host */ +#define ISR_RS_UPDATE 0x20000 /* interrupt ater new rx pkt status written + * to host. */ +#define ISR_TX_EARLY 0x40000 /* interrupt when txmac begin transmit one + * packet */ + +#define ISR_TX_EVENT (ISR_TXF_UR | ISR_TXS_OV | ISR_HOST_TXD_UR |\ + ISR_TS_UPDATE | ISR_TX_EARLY) +#define ISR_RX_EVENT (ISR_RXF_OV | ISR_RXS_OV | ISR_HOST_RXD_OV |\ + ISR_RS_UPDATE) + +#define IMR_NORMAL_MASK (\ + /*ISR_LINK_CHG |*/\ + ISR_MANUAL |\ + ISR_DMAR_TO_RST |\ + ISR_DMAW_TO_RST |\ + ISR_PHY |\ + ISR_PHY_LINKDOWN |\ + ISR_TS_UPDATE |\ + ISR_RS_UPDATE) + +/* Receive MAC Statistics Registers */ +#define REG_STS_RX_PAUSE 0x1700 /* Num pause packets received */ +#define REG_STS_RXD_OV 0x1704 /* Num frames dropped due to RX + * FIFO overflow */ +#define REG_STS_RXS_OV 0x1708 /* Num frames dropped due to RX + * Status Buffer Overflow */ +#define REG_STS_RX_FILTER 0x170C /* Num packets dropped due to + * address filtering */ + +/* MII definitions */ + +/* PHY Common Register */ +#define MII_SMARTSPEED 0x14 +#define MII_DBG_ADDR 0x1D +#define MII_DBG_DATA 0x1E + +/* PCI Command Register Bit Definitions */ +#define PCI_REG_COMMAND 0x04 +#define CMD_IO_SPACE 0x0001 +#define CMD_MEMORY_SPACE 0x0002 +#define CMD_BUS_MASTER 0x0004 + +#define MEDIA_TYPE_100M_FULL 1 +#define MEDIA_TYPE_100M_HALF 2 +#define MEDIA_TYPE_10M_FULL 3 +#define MEDIA_TYPE_10M_HALF 4 + +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x000F /* Everything */ + +/* The size (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */ +#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */ +#define ETHERNET_FCS_SIZE 4 +#define MAX_JUMBO_FRAME_SIZE 0x2000 +#define VLAN_SIZE 4 + +struct tx_pkt_header { + unsigned pkt_size:11; + unsigned:4; /* reserved */ + unsigned ins_vlan:1; /* txmac should insert vlan */ + unsigned short vlan; /* vlan tag */ +}; +/* FIXME: replace above bitfields with MASK/SHIFT defines below */ +#define TX_PKT_HEADER_SIZE_MASK 0x7FF +#define TX_PKT_HEADER_SIZE_SHIFT 0 +#define TX_PKT_HEADER_INS_VLAN_MASK 0x1 +#define TX_PKT_HEADER_INS_VLAN_SHIFT 15 +#define TX_PKT_HEADER_VLAN_TAG_MASK 0xFFFF +#define TX_PKT_HEADER_VLAN_TAG_SHIFT 16 + +struct tx_pkt_status { + unsigned pkt_size:11; + unsigned:5; /* reserved */ + unsigned ok:1; /* current packet transmitted without error */ + unsigned bcast:1; /* broadcast packet */ + unsigned mcast:1; /* multicast packet */ + unsigned pause:1; /* transmiited a pause frame */ + unsigned ctrl:1; + unsigned defer:1; /* current packet is xmitted with defer */ + unsigned exc_defer:1; + unsigned single_col:1; + unsigned multi_col:1; + unsigned late_col:1; + unsigned abort_col:1; + unsigned underun:1; /* current packet is aborted + * due to txram underrun */ + unsigned:3; /* reserved */ + unsigned update:1; /* always 1'b1 in tx_status_buf */ +}; +/* FIXME: replace above bitfields with MASK/SHIFT defines below */ +#define TX_PKT_STATUS_SIZE_MASK 0x7FF +#define TX_PKT_STATUS_SIZE_SHIFT 0 +#define TX_PKT_STATUS_OK_MASK 0x1 +#define TX_PKT_STATUS_OK_SHIFT 16 +#define TX_PKT_STATUS_BCAST_MASK 0x1 +#define TX_PKT_STATUS_BCAST_SHIFT 17 +#define TX_PKT_STATUS_MCAST_MASK 0x1 +#define TX_PKT_STATUS_MCAST_SHIFT 18 +#define TX_PKT_STATUS_PAUSE_MASK 0x1 +#define TX_PKT_STATUS_PAUSE_SHIFT 19 +#define TX_PKT_STATUS_CTRL_MASK 0x1 +#define TX_PKT_STATUS_CTRL_SHIFT 20 +#define TX_PKT_STATUS_DEFER_MASK 0x1 +#define TX_PKT_STATUS_DEFER_SHIFT 21 +#define TX_PKT_STATUS_EXC_DEFER_MASK 0x1 +#define TX_PKT_STATUS_EXC_DEFER_SHIFT 22 +#define TX_PKT_STATUS_SINGLE_COL_MASK 0x1 +#define TX_PKT_STATUS_SINGLE_COL_SHIFT 23 +#define TX_PKT_STATUS_MULTI_COL_MASK 0x1 +#define TX_PKT_STATUS_MULTI_COL_SHIFT 24 +#define TX_PKT_STATUS_LATE_COL_MASK 0x1 +#define TX_PKT_STATUS_LATE_COL_SHIFT 25 +#define TX_PKT_STATUS_ABORT_COL_MASK 0x1 +#define TX_PKT_STATUS_ABORT_COL_SHIFT 26 +#define TX_PKT_STATUS_UNDERRUN_MASK 0x1 +#define TX_PKT_STATUS_UNDERRUN_SHIFT 27 +#define TX_PKT_STATUS_UPDATE_MASK 0x1 +#define TX_PKT_STATUS_UPDATE_SHIFT 31 + +struct rx_pkt_status { + unsigned pkt_size:11; /* packet size, max 2047 bytes */ + unsigned:5; /* reserved */ + unsigned ok:1; /* current packet received ok without error */ + unsigned bcast:1; /* current packet is broadcast */ + unsigned mcast:1; /* current packet is multicast */ + unsigned pause:1; + unsigned ctrl:1; + unsigned crc:1; /* received a packet with crc error */ + unsigned code:1; /* received a packet with code error */ + unsigned runt:1; /* received a packet less than 64 bytes + * with good crc */ + unsigned frag:1; /* received a packet less than 64 bytes + * with bad crc */ + unsigned trunc:1; /* current frame truncated due to rxram full */ + unsigned align:1; /* this packet is alignment error */ + unsigned vlan:1; /* this packet has vlan */ + unsigned:3; /* reserved */ + unsigned update:1; + unsigned short vtag; /* vlan tag */ + unsigned:16; +}; +/* FIXME: replace above bitfields with MASK/SHIFT defines below */ +#define RX_PKT_STATUS_SIZE_MASK 0x7FF +#define RX_PKT_STATUS_SIZE_SHIFT 0 +#define RX_PKT_STATUS_OK_MASK 0x1 +#define RX_PKT_STATUS_OK_SHIFT 16 +#define RX_PKT_STATUS_BCAST_MASK 0x1 +#define RX_PKT_STATUS_BCAST_SHIFT 17 +#define RX_PKT_STATUS_MCAST_MASK 0x1 +#define RX_PKT_STATUS_MCAST_SHIFT 18 +#define RX_PKT_STATUS_PAUSE_MASK 0x1 +#define RX_PKT_STATUS_PAUSE_SHIFT 19 +#define RX_PKT_STATUS_CTRL_MASK 0x1 +#define RX_PKT_STATUS_CTRL_SHIFT 20 +#define RX_PKT_STATUS_CRC_MASK 0x1 +#define RX_PKT_STATUS_CRC_SHIFT 21 +#define RX_PKT_STATUS_CODE_MASK 0x1 +#define RX_PKT_STATUS_CODE_SHIFT 22 +#define RX_PKT_STATUS_RUNT_MASK 0x1 +#define RX_PKT_STATUS_RUNT_SHIFT 23 +#define RX_PKT_STATUS_FRAG_MASK 0x1 +#define RX_PKT_STATUS_FRAG_SHIFT 24 +#define RX_PKT_STATUS_TRUNK_MASK 0x1 +#define RX_PKT_STATUS_TRUNK_SHIFT 25 +#define RX_PKT_STATUS_ALIGN_MASK 0x1 +#define RX_PKT_STATUS_ALIGN_SHIFT 26 +#define RX_PKT_STATUS_VLAN_MASK 0x1 +#define RX_PKT_STATUS_VLAN_SHIFT 27 +#define RX_PKT_STATUS_UPDATE_MASK 0x1 +#define RX_PKT_STATUS_UPDATE_SHIFT 31 +#define RX_PKT_STATUS_VLAN_TAG_MASK 0xFFFF +#define RX_PKT_STATUS_VLAN_TAG_SHIFT 32 + +struct rx_desc { + struct rx_pkt_status status; + unsigned char packet[1536-sizeof(struct rx_pkt_status)]; +}; + +enum atl2_speed_duplex { + atl2_10_half = 0, + atl2_10_full = 1, + atl2_100_half = 2, + atl2_100_full = 3 +}; + +struct atl2_spi_flash_dev { + const char *manu_name; /* manufacturer id */ + /* op-code */ + u8 cmdWRSR; + u8 cmdREAD; + u8 cmdPROGRAM; + u8 cmdWREN; + u8 cmdWRDI; + u8 cmdRDSR; + u8 cmdRDID; + u8 cmdSECTOR_ERASE; + u8 cmdCHIP_ERASE; +}; + +/* Structure containing variables used by the shared code (atl2_hw.c) */ +struct atl2_hw { + u8 __iomem *hw_addr; + void *back; + + u8 preamble_len; + u8 max_retry; /* Retransmission maximum, afterwards the + * packet will be discarded. */ + u8 jam_ipg; /* IPG to start JAM for collision based flow + * control in half-duplex mode. In unit of + * 8-bit time. */ + u8 ipgt; /* Desired back to back inter-packet gap. The + * default is 96-bit time. */ + u8 min_ifg; /* Minimum number of IFG to enforce in between + * RX frames. Frame gap below such IFP is + * dropped. */ + u8 ipgr1; /* 64bit Carrier-Sense window */ + u8 ipgr2; /* 96-bit IPG window */ + u8 retry_buf; /* When half-duplex mode, should hold some + * bytes for mac retry . (8*4bytes unit) */ + + u16 fc_rxd_hi; + u16 fc_rxd_lo; + u16 lcol; /* Collision Window */ + u16 max_frame_size; + + u16 MediaType; + u16 autoneg_advertised; + u16 pci_cmd_word; + + u16 mii_autoneg_adv_reg; + + u32 mem_rang; + u32 txcw; + u32 mc_filter_type; + u32 num_mc_addrs; + u32 collision_delta; + u32 tx_packet_delta; + u16 phy_spd_default; + + u16 device_id; + u16 vendor_id; + u16 subsystem_id; + u16 subsystem_vendor_id; + u8 revision_id; + + /* spi flash */ + u8 flash_vendor; + + u8 dma_fairness; + u8 mac_addr[NODE_ADDRESS_SIZE]; + u8 perm_mac_addr[NODE_ADDRESS_SIZE]; + + /* FIXME */ + /* bool phy_preamble_sup; */ + bool phy_configured; +}; + +#endif /* _ATL2_HW_H_ */ + +struct atl2_ring_header { + /* pointer to the descriptor ring memory */ + void *desc; + /* physical adress of the descriptor ring */ + dma_addr_t dma; + /* length of descriptor ring in bytes */ + unsigned int size; +}; + +/* board specific private data structure */ +struct atl2_adapter { + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; +#ifdef NETIF_F_HW_VLAN_TX + struct vlan_group *vlgrp; +#endif + u32 wol; + u16 link_speed; + u16 link_duplex; + + spinlock_t stats_lock; + + struct work_struct reset_task; + struct work_struct link_chg_task; + struct timer_list watchdog_timer; + struct timer_list phy_config_timer; + + unsigned long cfg_phy; + bool mac_disabled; + + /* All Descriptor memory */ + dma_addr_t ring_dma; + void *ring_vir_addr; + int ring_size; + + struct tx_pkt_header *txd_ring; + dma_addr_t txd_dma; + + struct tx_pkt_status *txs_ring; + dma_addr_t txs_dma; + + struct rx_desc *rxd_ring; + dma_addr_t rxd_dma; + + u32 txd_ring_size; /* bytes per unit */ + u32 txs_ring_size; /* dwords per unit */ + u32 rxd_ring_size; /* 1536 bytes per unit */ + + /* read /write ptr: */ + /* host */ + u32 txd_write_ptr; + u32 txs_next_clear; + u32 rxd_read_ptr; + + /* nic */ + atomic_t txd_read_ptr; + atomic_t txs_write_ptr; + u32 rxd_write_ptr; + + /* Interrupt Moderator timer ( 2us resolution) */ + u16 imt; + /* Interrupt Clear timer (2us resolution) */ + u16 ict; + + unsigned long flags; + /* structs defined in atl2_hw.h */ + u32 bd_number; /* board number */ + bool pci_using_64; + bool have_msi; + struct atl2_hw hw; + + u32 usr_cmd; + /* FIXME */ + /* u32 regs_buff[ATL2_REGS_LEN]; */ + u32 pci_state[16]; + + u32 *config_space; +}; + +enum atl2_state_t { + __ATL2_TESTING, + __ATL2_RESETTING, + __ATL2_DOWN +}; + +#endif /* _ATL2_H_ */ diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c index b3e7fcf0f6e..3cc9d1089ca 100644 --- a/drivers/net/atlx/atlx.c +++ b/drivers/net/atlx/atlx.c @@ -105,7 +105,6 @@ static void atlx_check_for_link(struct atlx_adapter *adapter) netdev->name); adapter->link_speed = SPEED_0; netif_carrier_off(netdev); - netif_stop_queue(netdev); } } schedule_work(&adapter->link_chg_task); diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 5ee1b0557a0..019b13c08ae 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -94,8 +94,8 @@ static irqreturn_t au1000_interrupt(int, void *); static void au1000_tx_timeout(struct net_device *); static void set_rx_mode(struct net_device *); static int au1000_ioctl(struct net_device *, struct ifreq *, int); -static int mdio_read(struct net_device *, int, int); -static void mdio_write(struct net_device *, int, int, u16); +static int au1000_mdio_read(struct net_device *, int, int); +static void au1000_mdio_write(struct net_device *, int, int, u16); static void au1000_adjust_link(struct net_device *); static void enable_mac(struct net_device *, int); @@ -191,7 +191,7 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES]; /* * MII operations */ -static int mdio_read(struct net_device *dev, int phy_addr, int reg) +static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg) { struct au1000_private *aup = (struct au1000_private *) dev->priv; volatile u32 *const mii_control_reg = &aup->mac->mii_control; @@ -225,7 +225,8 @@ static int mdio_read(struct net_device *dev, int phy_addr, int reg) return (int)*mii_data_reg; } -static void mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value) +static void au1000_mdio_write(struct net_device *dev, int phy_addr, + int reg, u16 value) { struct au1000_private *aup = (struct au1000_private *) dev->priv; volatile u32 *const mii_control_reg = &aup->mac->mii_control; @@ -249,7 +250,7 @@ static void mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value) *mii_control_reg = mii_control; } -static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) +static int au1000_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) { /* WARNING: bus->phy_map[phy_addr].attached_dev == dev does * _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus) */ @@ -257,21 +258,21 @@ static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) enable_mac(dev, 0); /* make sure the MAC associated with this * mii_bus is enabled */ - return mdio_read(dev, phy_addr, regnum); + return au1000_mdio_read(dev, phy_addr, regnum); } -static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, - u16 value) +static int au1000_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, + u16 value) { struct net_device *const dev = bus->priv; enable_mac(dev, 0); /* make sure the MAC associated with this * mii_bus is enabled */ - mdio_write(dev, phy_addr, regnum, value); + au1000_mdio_write(dev, phy_addr, regnum, value); return 0; } -static int mdiobus_reset(struct mii_bus *bus) +static int au1000_mdiobus_reset(struct mii_bus *bus) { struct net_device *const dev = bus->priv; @@ -290,7 +291,7 @@ static int mii_probe (struct net_device *dev) if(aup->mac_id == 0) { /* get PHY0 */ # if defined(AU1XXX_PHY0_ADDR) - phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus.phy_map[AU1XXX_PHY0_ADDR]; + phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus->phy_map[AU1XXX_PHY0_ADDR]; # else printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n", dev->name); @@ -298,7 +299,7 @@ static int mii_probe (struct net_device *dev) # endif /* defined(AU1XXX_PHY0_ADDR) */ } else if (aup->mac_id == 1) { /* get PHY1 */ # if defined(AU1XXX_PHY1_ADDR) - phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus.phy_map[AU1XXX_PHY1_ADDR]; + phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus->phy_map[AU1XXX_PHY1_ADDR]; # else printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n", dev->name); @@ -311,8 +312,8 @@ static int mii_probe (struct net_device *dev) /* find the first (lowest address) PHY on the current MAC's MII bus */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) - if (aup->mii_bus.phy_map[phy_addr]) { - phydev = aup->mii_bus.phy_map[phy_addr]; + if (aup->mii_bus->phy_map[phy_addr]) { + phydev = aup->mii_bus->phy_map[phy_addr]; # if !defined(AU1XXX_PHY_SEARCH_HIGHEST_ADDR) break; /* break out with first one found */ # endif @@ -331,7 +332,7 @@ static int mii_probe (struct net_device *dev) * the MAC0 MII bus */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { struct phy_device *const tmp_phydev = - au_macs[0]->mii_bus.phy_map[phy_addr]; + au_macs[0]->mii_bus->phy_map[phy_addr]; if (!tmp_phydev) continue; /* no PHY here... */ @@ -653,6 +654,8 @@ static struct net_device * au1000_probe(int port_num) aup = dev->priv; + spin_lock_init(&aup->lock); + /* Allocate the data buffers */ /* Snooping works fine with eth on all au1xxx */ aup->vaddr = (u32)dma_alloc_noncoherent(NULL, MAX_BUF_SIZE * @@ -696,28 +699,32 @@ static struct net_device * au1000_probe(int port_num) *aup->enable = 0; aup->mac_enabled = 0; - aup->mii_bus.priv = dev; - aup->mii_bus.read = mdiobus_read; - aup->mii_bus.write = mdiobus_write; - aup->mii_bus.reset = mdiobus_reset; - aup->mii_bus.name = "au1000_eth_mii"; - snprintf(aup->mii_bus.id, MII_BUS_ID_SIZE, "%x", aup->mac_id); - aup->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + aup->mii_bus = mdiobus_alloc(); + if (aup->mii_bus == NULL) + goto err_out; + + aup->mii_bus->priv = dev; + aup->mii_bus->read = au1000_mdiobus_read; + aup->mii_bus->write = au1000_mdiobus_write; + aup->mii_bus->reset = au1000_mdiobus_reset; + aup->mii_bus->name = "au1000_eth_mii"; + snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id); + aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); for(i = 0; i < PHY_MAX_ADDR; ++i) - aup->mii_bus.irq[i] = PHY_POLL; + aup->mii_bus->irq[i] = PHY_POLL; /* if known, set corresponding PHY IRQs */ #if defined(AU1XXX_PHY_STATIC_CONFIG) # if defined(AU1XXX_PHY0_IRQ) if (AU1XXX_PHY0_BUSID == aup->mac_id) - aup->mii_bus.irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ; + aup->mii_bus->irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ; # endif # if defined(AU1XXX_PHY1_IRQ) if (AU1XXX_PHY1_BUSID == aup->mac_id) - aup->mii_bus.irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ; + aup->mii_bus->irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ; # endif #endif - mdiobus_register(&aup->mii_bus); + mdiobus_register(aup->mii_bus); if (mii_probe(dev) != 0) { goto err_out; @@ -753,7 +760,6 @@ static struct net_device * au1000_probe(int port_num) aup->tx_db_inuse[i] = pDB; } - spin_lock_init(&aup->lock); dev->base_addr = base; dev->irq = irq; dev->open = au1000_open; @@ -774,6 +780,11 @@ static struct net_device * au1000_probe(int port_num) return dev; err_out: + if (aup->mii_bus != NULL) { + mdiobus_unregister(aup->mii_bus); + mdiobus_free(aup->mii_bus); + } + /* here we should have a valid dev plus aup-> register addresses * so we can reset the mac properly.*/ reset_mac(dev); @@ -1004,6 +1015,8 @@ static void __exit au1000_cleanup_module(void) if (dev) { aup = (struct au1000_private *) dev->priv; unregister_netdev(dev); + mdiobus_unregister(aup->mii_bus); + mdiobus_free(aup->mii_bus); for (j = 0; j < NUM_RX_DMA; j++) if (aup->rx_db_inuse[j]) ReleaseDB(aup, aup->rx_db_inuse[j]); diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h index f3baeaa1285..824ecd5ff3a 100644 --- a/drivers/net/au1000_eth.h +++ b/drivers/net/au1000_eth.h @@ -106,7 +106,7 @@ struct au1000_private { int old_duplex; struct phy_device *phy_dev; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; /* These variables are just for quick access to certain regs addresses. */ volatile mac_reg_t *mac; /* mac registers */ diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index a886a4b9f7e..4207d6efddc 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c @@ -153,7 +153,7 @@ static void ax_reset_8390(struct net_device *dev) while ((ei_inb(addr + EN0_ISR) & ENISR_RESET) == 0) { if (jiffies - reset_start_time > 2*HZ/100) { dev_warn(&ax->dev->dev, "%s: %s did not complete.\n", - __FUNCTION__, dev->name); + __func__, dev->name); break; } } @@ -173,7 +173,7 @@ static void ax_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, if (ei_status.dmaing) { dev_err(&ax->dev->dev, "%s: DMAing conflict in %s " "[DMAstat:%d][irqlock:%d].\n", - dev->name, __FUNCTION__, + dev->name, __func__, ei_status.dmaing, ei_status.irqlock); return; } @@ -215,7 +215,7 @@ static void ax_block_input(struct net_device *dev, int count, dev_err(&ax->dev->dev, "%s: DMAing conflict in %s " "[DMAstat:%d][irqlock:%d].\n", - dev->name, __FUNCTION__, + dev->name, __func__, ei_status.dmaing, ei_status.irqlock); return; } @@ -260,7 +260,7 @@ static void ax_block_output(struct net_device *dev, int count, if (ei_status.dmaing) { dev_err(&ax->dev->dev, "%s: DMAing conflict in %s." "[DMAstat:%d][irqlock:%d]\n", - dev->name, __FUNCTION__, + dev->name, __func__, ei_status.dmaing, ei_status.irqlock); return; } @@ -396,7 +396,7 @@ ax_phy_issueaddr(struct net_device *dev, int phy_addr, int reg, int opc) { if (phy_debug) pr_debug("%s: dev %p, %04x, %04x, %d\n", - __FUNCTION__, dev, phy_addr, reg, opc); + __func__, dev, phy_addr, reg, opc); ax_mii_ei_outbits(dev, 0x3f, 6); /* pre-amble */ ax_mii_ei_outbits(dev, 1, 2); /* frame-start */ @@ -422,7 +422,7 @@ ax_phy_read(struct net_device *dev, int phy_addr, int reg) spin_unlock_irqrestore(&ei_local->page_lock, flags); if (phy_debug) - pr_debug("%s: %04x.%04x => read %04x\n", __FUNCTION__, + pr_debug("%s: %04x.%04x => read %04x\n", __func__, phy_addr, reg, result); return result; @@ -436,7 +436,7 @@ ax_phy_write(struct net_device *dev, int phy_addr, int reg, int value) unsigned long flags; dev_dbg(&ax->dev->dev, "%s: %p, %04x, %04x %04x\n", - __FUNCTION__, dev, phy_addr, reg, value); + __func__, dev, phy_addr, reg, value); spin_lock_irqsave(&ei->page_lock, flags); diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 3db7db1828e..b458d607a9c 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -253,7 +253,7 @@ init_error: * MII operations */ /* Wait until the previous MDC/MDIO transaction has completed */ -static void mdio_poll(void) +static void bfin_mdio_poll(void) { int timeout_cnt = MAX_TIMEOUT_CNT; @@ -269,25 +269,25 @@ static void mdio_poll(void) } /* Read an off-chip register in a PHY through the MDC/MDIO port */ -static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) +static int bfin_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) { - mdio_poll(); + bfin_mdio_poll(); /* read mode */ bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) | SET_REGAD((u16) regnum) | STABUSY); - mdio_poll(); + bfin_mdio_poll(); return (int) bfin_read_EMAC_STADAT(); } /* Write an off-chip register in a PHY through the MDC/MDIO port */ -static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, - u16 value) +static int bfin_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, + u16 value) { - mdio_poll(); + bfin_mdio_poll(); bfin_write_EMAC_STADAT((u32) value); @@ -297,12 +297,12 @@ static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, STAOP | STABUSY); - mdio_poll(); + bfin_mdio_poll(); return 0; } -static int mdiobus_reset(struct mii_bus *bus) +static int bfin_mdiobus_reset(struct mii_bus *bus) { return 0; } @@ -398,7 +398,7 @@ static int mii_probe(struct net_device *dev) /* search for connect PHY device */ for (i = 0; i < PHY_MAX_ADDR; i++) { - struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i]; + struct phy_device *const tmp_phydev = lp->mii_bus->phy_map[i]; if (!tmp_phydev) continue; /* no PHY here... */ @@ -811,14 +811,14 @@ static void bfin_mac_enable(void) { u32 opmode; - pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__); + pr_debug("%s: %s\n", DRV_NAME, __func__); /* Set RX DMA */ bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a)); bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config); /* Wait MII done */ - mdio_poll(); + bfin_mdio_poll(); /* We enable only RX here */ /* ASTP : Enable Automatic Pad Stripping @@ -847,7 +847,7 @@ static void bfin_mac_enable(void) /* Our watchdog timed out. Called by the networking layer */ static void bfin_mac_timeout(struct net_device *dev) { - pr_debug("%s: %s\n", dev->name, __FUNCTION__); + pr_debug("%s: %s\n", dev->name, __func__); bfin_mac_disable(); @@ -949,7 +949,7 @@ static int bfin_mac_open(struct net_device *dev) { struct bfin_mac_local *lp = netdev_priv(dev); int retval; - pr_debug("%s: %s\n", dev->name, __FUNCTION__); + pr_debug("%s: %s\n", dev->name, __func__); /* * Check that the address is valid. If its not, refuse @@ -989,7 +989,7 @@ static int bfin_mac_open(struct net_device *dev) static int bfin_mac_close(struct net_device *dev) { struct bfin_mac_local *lp = netdev_priv(dev); - pr_debug("%s: %s\n", dev->name, __FUNCTION__); + pr_debug("%s: %s\n", dev->name, __func__); netif_stop_queue(dev); netif_carrier_off(dev); @@ -1058,17 +1058,21 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) setup_mac_addr(ndev->dev_addr); /* MDIO bus initial */ - lp->mii_bus.priv = ndev; - lp->mii_bus.read = mdiobus_read; - lp->mii_bus.write = mdiobus_write; - lp->mii_bus.reset = mdiobus_reset; - lp->mii_bus.name = "bfin_mac_mdio"; - snprintf(lp->mii_bus.id, MII_BUS_ID_SIZE, "0"); - lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + lp->mii_bus = mdiobus_alloc(); + if (lp->mii_bus == NULL) + goto out_err_mdiobus_alloc; + + lp->mii_bus->priv = ndev; + lp->mii_bus->read = bfin_mdiobus_read; + lp->mii_bus->write = bfin_mdiobus_write; + lp->mii_bus->reset = bfin_mdiobus_reset; + lp->mii_bus->name = "bfin_mac_mdio"; + snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "0"); + lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); for (i = 0; i < PHY_MAX_ADDR; ++i) - lp->mii_bus.irq[i] = PHY_POLL; + lp->mii_bus->irq[i] = PHY_POLL; - rc = mdiobus_register(&lp->mii_bus); + rc = mdiobus_register(lp->mii_bus); if (rc) { dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); goto out_err_mdiobus_register; @@ -1121,8 +1125,10 @@ out_err_reg_ndev: free_irq(IRQ_MAC_RX, ndev); out_err_request_irq: out_err_mii_probe: - mdiobus_unregister(&lp->mii_bus); + mdiobus_unregister(lp->mii_bus); out_err_mdiobus_register: + mdiobus_free(lp->mii_bus); +out_err_mdiobus_alloc: peripheral_free_list(pin_req); out_err_setup_pin_mux: out_err_probe_mac: @@ -1139,7 +1145,8 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - mdiobus_unregister(&lp->mii_bus); + mdiobus_unregister(lp->mii_bus); + mdiobus_free(lp->mii_bus); unregister_netdev(ndev); diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h index beff51064ff..052b5dce3e3 100644 --- a/drivers/net/bfin_mac.h +++ b/drivers/net/bfin_mac.h @@ -66,7 +66,7 @@ struct bfin_mac_local { int old_duplex; struct phy_device *phydev; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; }; extern void bfin_get_ether_addr(char *addr); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 2486a656f12..430d430bce2 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -57,8 +57,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.8.0" -#define DRV_MODULE_RELDATE "Aug 14, 2008" +#define DRV_MODULE_VERSION "1.8.1" +#define DRV_MODULE_RELDATE "Oct 7, 2008" #define RUN_AT(x) (jiffies + (x)) @@ -69,7 +69,7 @@ static char version[] __devinitdata = "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>"); -MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 Driver"); +MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); @@ -1127,7 +1127,7 @@ bnx2_init_all_rx_contexts(struct bnx2 *bp) } } -static int +static void bnx2_set_mac_link(struct bnx2 *bp) { u32 val; @@ -1193,8 +1193,6 @@ bnx2_set_mac_link(struct bnx2 *bp) if (CHIP_NUM(bp) == CHIP_NUM_5709) bnx2_init_all_rx_contexts(bp); - - return 0; } static void @@ -2478,6 +2476,11 @@ bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) return -ENOMEM; mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(bp->pdev, mapping)) { + __free_page(page); + return -EIO; + } + rx_pg->page = page; pci_unmap_addr_set(rx_pg, mapping, mapping); rxbd->rx_bd_haddr_hi = (u64) mapping >> 32; @@ -2520,6 +2523,10 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(bp->pdev, mapping)) { + dev_kfree_skb(skb); + return -EIO; + } rx_buf->skb = skb; pci_unmap_addr_set(rx_buf, mapping, mapping); @@ -2594,7 +2601,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) sw_cons = txr->tx_cons; while (sw_cons != hw_cons) { - struct sw_bd *tx_buf; + struct sw_tx_bd *tx_buf; struct sk_buff *skb; int i, last; @@ -2619,21 +2626,13 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) } } - pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping), - skb_headlen(skb), PCI_DMA_TODEVICE); + skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE); tx_buf->skb = NULL; last = skb_shinfo(skb)->nr_frags; for (i = 0; i < last; i++) { sw_cons = NEXT_TX_BD(sw_cons); - - pci_unmap_page(bp->pdev, - pci_unmap_addr( - &txr->tx_buf_ring[TX_RING_IDX(sw_cons)], - mapping), - skb_shinfo(skb)->frags[i].size, - PCI_DMA_TODEVICE); } sw_cons = NEXT_TX_BD(sw_cons); @@ -2674,11 +2673,31 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, { struct sw_pg *cons_rx_pg, *prod_rx_pg; struct rx_bd *cons_bd, *prod_bd; - dma_addr_t mapping; int i; - u16 hw_prod = rxr->rx_pg_prod, prod; + u16 hw_prod, prod; u16 cons = rxr->rx_pg_cons; + cons_rx_pg = &rxr->rx_pg_ring[cons]; + + /* The caller was unable to allocate a new page to replace the + * last one in the frags array, so we need to recycle that page + * and then free the skb. + */ + if (skb) { + struct page *page; + struct skb_shared_info *shinfo; + + shinfo = skb_shinfo(skb); + shinfo->nr_frags--; + page = shinfo->frags[shinfo->nr_frags].page; + shinfo->frags[shinfo->nr_frags].page = NULL; + + cons_rx_pg->page = page; + dev_kfree_skb(skb); + } + + hw_prod = rxr->rx_pg_prod; + for (i = 0; i < count; i++) { prod = RX_PG_RING_IDX(hw_prod); @@ -2687,20 +2706,6 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)]; prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)]; - if (i == 0 && skb) { - struct page *page; - struct skb_shared_info *shinfo; - - shinfo = skb_shinfo(skb); - shinfo->nr_frags--; - page = shinfo->frags[shinfo->nr_frags].page; - shinfo->frags[shinfo->nr_frags].page = NULL; - mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); - cons_rx_pg->page = page; - pci_unmap_addr_set(cons_rx_pg, mapping, mapping); - dev_kfree_skb(skb); - } if (prod != cons) { prod_rx_pg->page = cons_rx_pg->page; cons_rx_pg->page = NULL; @@ -2786,6 +2791,8 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb, skb_put(skb, hdr_len); for (i = 0; i < pages; i++) { + dma_addr_t mapping_old; + frag_len = min(frag_size, (unsigned int) PAGE_SIZE); if (unlikely(frag_len <= 4)) { unsigned int tail = 4 - frag_len; @@ -2808,9 +2815,10 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb, } rx_pg = &rxr->rx_pg_ring[pg_cons]; - pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), - PAGE_SIZE, PCI_DMA_FROMDEVICE); - + /* Don't unmap yet. If we're unable to allocate a new + * page, we need to recycle the page and the DMA addr. + */ + mapping_old = pci_unmap_addr(rx_pg, mapping); if (i == pages - 1) frag_len -= 4; @@ -2827,6 +2835,9 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb, return err; } + pci_unmap_page(bp->pdev, mapping_old, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + frag_size -= frag_len; skb->data_len += frag_len; skb->truesize += frag_len; @@ -3250,6 +3261,9 @@ bnx2_set_rx_mode(struct net_device *dev) struct dev_addr_list *uc_ptr; int i; + if (!netif_running(dev)) + return; + spin_lock_bh(&bp->phy_lock); rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS | @@ -4970,31 +4984,20 @@ bnx2_free_tx_skbs(struct bnx2 *bp) continue; for (j = 0; j < TX_DESC_CNT; ) { - struct sw_bd *tx_buf = &txr->tx_buf_ring[j]; + struct sw_tx_bd *tx_buf = &txr->tx_buf_ring[j]; struct sk_buff *skb = tx_buf->skb; - int k, last; if (skb == NULL) { j++; continue; } - pci_unmap_single(bp->pdev, - pci_unmap_addr(tx_buf, mapping), - skb_headlen(skb), PCI_DMA_TODEVICE); + skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE); tx_buf->skb = NULL; - last = skb_shinfo(skb)->nr_frags; - for (k = 0; k < last; k++) { - tx_buf = &txr->tx_buf_ring[j + k + 1]; - pci_unmap_page(bp->pdev, - pci_unmap_addr(tx_buf, mapping), - skb_shinfo(skb)->frags[j].size, - PCI_DMA_TODEVICE); - } + j += skb_shinfo(skb)->nr_frags + 1; dev_kfree_skb(skb); - j += k + 1; } } } @@ -5075,6 +5078,21 @@ bnx2_init_nic(struct bnx2 *bp, int reset_phy) } static int +bnx2_shutdown_chip(struct bnx2 *bp) +{ + u32 reset_code; + + if (bp->flags & BNX2_FLAG_NO_WOL) + reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; + else if (bp->wol) + reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; + else + reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; + + return bnx2_reset_chip(bp, reset_code); +} + +static int bnx2_test_registers(struct bnx2 *bp) { int ret; @@ -5357,8 +5375,11 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) for (i = 14; i < pkt_size; i++) packet[i] = (unsigned char) (i & 0xff); - map = pci_map_single(bp->pdev, skb->data, pkt_size, - PCI_DMA_TODEVICE); + if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) { + dev_kfree_skb(skb); + return -EIO; + } + map = skb_shinfo(skb)->dma_maps[0]; REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); @@ -5393,7 +5414,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) udelay(5); - pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE); + skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE); dev_kfree_skb(skb); if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod) @@ -5508,6 +5529,9 @@ bnx2_test_link(struct bnx2 *bp) { u32 bmsr; + if (!netif_running(bp->dev)) + return -ENODEV; + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { if (bp->link_up) return 0; @@ -5600,7 +5624,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) { u32 bmcr; - bp->current_interval = bp->timer_interval; + bp->current_interval = BNX2_TIMER_INTERVAL; bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); @@ -5629,7 +5653,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; } } else - bp->current_interval = bp->timer_interval; + bp->current_interval = BNX2_TIMER_INTERVAL; if (check_link) { u32 val; @@ -5674,11 +5698,11 @@ bnx2_5708_serdes_timer(struct bnx2 *bp) } else { bnx2_disable_forced_2g5(bp); bp->serdes_an_pending = 2; - bp->current_interval = bp->timer_interval; + bp->current_interval = BNX2_TIMER_INTERVAL; } } else - bp->current_interval = bp->timer_interval; + bp->current_interval = BNX2_TIMER_INTERVAL; spin_unlock(&bp->phy_lock); } @@ -5951,13 +5975,14 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); dma_addr_t mapping; struct tx_bd *txbd; - struct sw_bd *tx_buf; + struct sw_tx_bd *tx_buf; u32 len, vlan_tag_flags, last_frag, mss; u16 prod, ring_prod; int i; struct bnx2_napi *bnapi; struct bnx2_tx_ring_info *txr; struct netdev_queue *txq; + struct skb_shared_info *sp; /* Determine which tx ring we will be placed on */ i = skb_get_queue_mapping(skb); @@ -5989,7 +6014,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) } #endif if ((mss = skb_shinfo(skb)->gso_size)) { - u32 tcp_opt_len, ip_tcp_len; + u32 tcp_opt_len; struct iphdr *iph; vlan_tag_flags |= TX_BD_FLAGS_SW_LSO; @@ -6013,21 +6038,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL; } } else { - if (skb_header_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr); - iph = ip_hdr(skb); - iph->check = 0; - iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); - tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, - iph->daddr, 0, - IPPROTO_TCP, - 0); if (tcp_opt_len || (iph->ihl > 5)) { vlan_tag_flags |= ((iph->ihl - 5) + (tcp_opt_len >> 2)) << 8; @@ -6036,11 +6047,16 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) } else mss = 0; - mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); + if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + sp = skb_shinfo(skb); + mapping = sp->dma_maps[0]; tx_buf = &txr->tx_buf_ring[ring_prod]; tx_buf->skb = skb; - pci_unmap_addr_set(tx_buf, mapping, mapping); txbd = &txr->tx_desc_ring[ring_prod]; @@ -6059,10 +6075,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd = &txr->tx_desc_ring[ring_prod]; len = frag->size; - mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset, - len, PCI_DMA_TODEVICE); - pci_unmap_addr_set(&txr->tx_buf_ring[ring_prod], - mapping, mapping); + mapping = sp->dma_maps[i + 1]; txbd->tx_bd_haddr_hi = (u64) mapping >> 32; txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff; @@ -6097,20 +6110,13 @@ static int bnx2_close(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); - u32 reset_code; cancel_work_sync(&bp->reset_task); bnx2_disable_int_sync(bp); bnx2_napi_disable(bp); del_timer_sync(&bp->timer); - if (bp->flags & BNX2_FLAG_NO_WOL) - reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; - else if (bp->wol) - reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; - else - reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; - bnx2_reset_chip(bp, reset_code); + bnx2_shutdown_chip(bp); bnx2_free_irq(bp); bnx2_free_skbs(bp); bnx2_free_mem(bp); @@ -6479,6 +6485,9 @@ bnx2_nway_reset(struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); u32 bmcr; + if (!netif_running(dev)) + return -EAGAIN; + if (!(bp->autoneg & AUTONEG_SPEED)) { return -EINVAL; } @@ -6534,6 +6543,9 @@ bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, struct bnx2 *bp = netdev_priv(dev); int rc; + if (!netif_running(dev)) + return -EAGAIN; + /* parameters already validated in ethtool_get_eeprom */ rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); @@ -6548,6 +6560,9 @@ bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, struct bnx2 *bp = netdev_priv(dev); int rc; + if (!netif_running(dev)) + return -EAGAIN; + /* parameters already validated in ethtool_set_eeprom */ rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); @@ -6712,11 +6727,11 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) bp->autoneg &= ~AUTONEG_FLOW_CTRL; } - spin_lock_bh(&bp->phy_lock); - - bnx2_setup_phy(bp, bp->phy_port); - - spin_unlock_bh(&bp->phy_lock); + if (netif_running(dev)) { + spin_lock_bh(&bp->phy_lock); + bnx2_setup_phy(bp, bp->phy_port); + spin_unlock_bh(&bp->phy_lock); + } return 0; } @@ -6907,6 +6922,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) { struct bnx2 *bp = netdev_priv(dev); + bnx2_set_power_state(bp, PCI_D0); + memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS); if (etest->flags & ETH_TEST_FL_OFFLINE) { int i; @@ -6926,9 +6943,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) if ((buf[2] = bnx2_test_loopback(bp)) != 0) etest->flags |= ETH_TEST_FL_FAILED; - if (!netif_running(bp->dev)) { - bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); - } + if (!netif_running(bp->dev)) + bnx2_shutdown_chip(bp); else { bnx2_init_nic(bp, 1); bnx2_netif_start(bp); @@ -6956,6 +6972,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) etest->flags |= ETH_TEST_FL_FAILED; } + if (!netif_running(bp->dev)) + bnx2_set_power_state(bp, PCI_D3hot); } static void @@ -7021,6 +7039,8 @@ bnx2_phys_id(struct net_device *dev, u32 data) int i; u32 save; + bnx2_set_power_state(bp, PCI_D0); + if (data == 0) data = 2; @@ -7045,6 +7065,10 @@ bnx2_phys_id(struct net_device *dev, u32 data) } 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; } @@ -7516,8 +7540,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS; - bp->timer_interval = HZ; - bp->current_interval = HZ; + bp->current_interval = BNX2_TIMER_INTERVAL; bp->phy_addr = 1; @@ -7607,7 +7630,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX; init_timer(&bp->timer); - bp->timer.expires = RUN_AT(bp->timer_interval); + bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL); bp->timer.data = (unsigned long) bp; bp->timer.function = bnx2_timer; @@ -7720,7 +7743,6 @@ 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); - bp->name = board_info[ent->driver_data].name; dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; if (CHIP_NUM(bp) == CHIP_NUM_5709) @@ -7747,7 +7769,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, " "IRQ %d, node addr %s\n", dev->name, - bp->name, + board_info[ent->driver_data].name, ((CHIP_ID(bp) & 0xf000) >> 12) + 'A', ((CHIP_ID(bp) & 0x0ff0) >> 4), bnx2_bus_string(bp, str), @@ -7781,7 +7803,6 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct bnx2 *bp = netdev_priv(dev); - u32 reset_code; /* PCI register 4 needs to be saved whether netif_running() or not. * MSI address and data need to be saved if using MSI and @@ -7795,13 +7816,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) bnx2_netif_stop(bp); netif_device_detach(dev); del_timer_sync(&bp->timer); - if (bp->flags & BNX2_FLAG_NO_WOL) - reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; - else if (bp->wol) - reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; - else - reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; - bnx2_reset_chip(bp, reset_code); + bnx2_shutdown_chip(bp); bnx2_free_skbs(bp); bnx2_set_power_state(bp, pci_choose_state(pdev, state)); return 0; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index c3c579f98ed..617d9534016 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6526,10 +6526,14 @@ struct sw_pg { DECLARE_PCI_UNMAP_ADDR(mapping) }; +struct sw_tx_bd { + struct sk_buff *skb; +}; + #define SW_RXBD_RING_SIZE (sizeof(struct sw_bd) * RX_DESC_CNT) #define SW_RXPG_RING_SIZE (sizeof(struct sw_pg) * RX_DESC_CNT) #define RXBD_RING_SIZE (sizeof(struct rx_bd) * RX_DESC_CNT) -#define SW_TXBD_RING_SIZE (sizeof(struct sw_bd) * TX_DESC_CNT) +#define SW_TXBD_RING_SIZE (sizeof(struct sw_tx_bd) * TX_DESC_CNT) #define TXBD_RING_SIZE (sizeof(struct tx_bd) * TX_DESC_CNT) /* Buffered flash (Atmel: AT45DB011B) specific information */ @@ -6597,7 +6601,7 @@ struct flash_spec { struct bnx2_irq { irq_handler_t handler; - u16 vector; + unsigned int vector; u8 requested; char name[16]; }; @@ -6609,7 +6613,7 @@ struct bnx2_tx_ring_info { u32 tx_bseq_addr; struct tx_bd *tx_desc_ring; - struct sw_bd *tx_buf_ring; + struct sw_tx_bd *tx_buf_ring; u16 tx_cons; u16 hw_tx_cons; @@ -6654,6 +6658,8 @@ struct bnx2_napi { struct bnx2_tx_ring_info tx_ring; }; +#define BNX2_TIMER_INTERVAL HZ + struct bnx2 { /* Fields used in the tx and intr/napi performance paths are grouped */ /* together in the beginning of the structure. */ @@ -6701,9 +6707,6 @@ struct bnx2 { /* End of fields used in the performance code paths. */ - char *name; - - int timer_interval; int current_interval; struct timer_list timer; struct work_struct reset_task; diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index e4b1de43556..24c3cc40c23 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -15,854 +15,854 @@ */ static u8 bnx2_COM_b06FwText[] = { - 0xcd, 0x7c, 0x0d, 0x70, 0x5c, 0xd5, 0x95, 0xe6, 0xe9, 0xd7, 0xdd, 0x52, - 0x4b, 0x96, 0xe5, 0x27, 0xb9, 0x51, 0x1a, 0xa2, 0x24, 0xef, 0xa9, 0x9f, - 0xa4, 0x06, 0x29, 0xe4, 0xd9, 0x08, 0x10, 0x49, 0x0f, 0x34, 0xdd, 0x92, - 0x11, 0x89, 0x77, 0x24, 0x40, 0x61, 0xbc, 0x3b, 0xae, 0xac, 0xa6, 0x2d, - 0x13, 0x42, 0x31, 0x35, 0xae, 0x0a, 0x3b, 0x71, 0xb2, 0x04, 0x37, 0x2d, - 0x99, 0x38, 0x8c, 0xec, 0x56, 0x64, 0x59, 0x66, 0x67, 0xd8, 0xd9, 0x4e, - 0x4b, 0xb2, 0x19, 0xa6, 0xed, 0xc6, 0x90, 0x1f, 0xa6, 0x92, 0x0c, 0x5a, - 0xe3, 0x00, 0x93, 0xcd, 0x56, 0x41, 0x2a, 0xb5, 0xcb, 0x6c, 0x51, 0xbb, - 0x5e, 0x27, 0x4c, 0xb2, 0xa9, 0xda, 0x0a, 0x3b, 0x93, 0xda, 0x65, 0xf2, - 0x33, 0x6f, 0xbf, 0xef, 0xbe, 0xfb, 0xa4, 0x96, 0xac, 0x38, 0x4c, 0xa6, - 0x52, 0x35, 0xaa, 0xea, 0xba, 0xef, 0xde, 0x77, 0x7f, 0xce, 0x3d, 0xf7, - 0xdc, 0x73, 0xbe, 0x73, 0xee, 0x7d, 0xba, 0x55, 0xa4, 0x59, 0xf4, 0xdf, - 0x56, 0xfc, 0x06, 0x7e, 0xff, 0x0f, 0xf6, 0xdd, 0x78, 0xbd, 0x7b, 0x3d, - 0xf3, 0x46, 0x54, 0x22, 0x4c, 0xc3, 0xf8, 0xc5, 0xf1, 0xdb, 0xa9, 0x9f, - 0x37, 0xfb, 0x33, 0xf1, 0xbb, 0x29, 0x24, 0x32, 0xf1, 0x23, 0x91, 0xd0, - 0x86, 0x77, 0xb1, 0x4d, 0xea, 0x7b, 0xde, 0x2f, 0xe9, 0x48, 0xff, 0x19, - 0xf8, 0x59, 0x57, 0xae, 0xb2, 0x3a, 0xee, 0xaf, 0xfb, 0x17, 0xd6, 0xcd, - 0xb7, 0xea, 0x9f, 0xc4, 0x8c, 0xf4, 0xc5, 0xdf, 0xce, 0x3a, 0x12, 0x0b, - 0xa7, 0xbf, 0x3b, 0xba, 0xcf, 0x11, 0xc9, 0x54, 0xfb, 0xac, 0x9c, 0xfc, - 0xc2, 0x2b, 0xc4, 0x23, 0xc2, 0xf2, 0xf7, 0xa4, 0x7f, 0x7e, 0xe8, 0x1b, - 0x37, 0xdb, 0x6f, 0x95, 0xc3, 0x12, 0x33, 0xd3, 0x6f, 0x8b, 0xd9, 0x23, - 0xb1, 0x4e, 0xb4, 0x79, 0xb2, 0xf7, 0x29, 0x43, 0x5a, 0x83, 0xbe, 0xcc, - 0x89, 0x70, 0x5a, 0xc6, 0x26, 0x67, 0x0e, 0x79, 0x86, 0x23, 0x85, 0x6b, - 0xd2, 0x8e, 0x55, 0x94, 0x96, 0xc1, 0xe9, 0x81, 0x9b, 0x05, 0xf9, 0xb1, - 0xc9, 0x6a, 0x4c, 0xb2, 0xb5, 0x42, 0x8b, 0xe1, 0x38, 0x48, 0x63, 0x85, - 0x77, 0xa7, 0x25, 0xd6, 0x90, 0x9e, 0x6f, 0x7c, 0xc9, 0xe1, 0xf8, 0x89, - 0xd1, 0xac, 0xf3, 0x6e, 0x89, 0x38, 0x9e, 0x37, 0x8d, 0xf1, 0x77, 0x55, - 0x7f, 0xe1, 0x3d, 0x1a, 0xf1, 0xc7, 0x36, 0xd2, 0x07, 0xc3, 0x4c, 0x43, - 0x69, 0x6b, 0xb4, 0xab, 0xaa, 0xf2, 0x0d, 0x7e, 0xde, 0xd1, 0xf9, 0x58, - 0xb3, 0x4f, 0xbb, 0x34, 0x81, 0xf6, 0x58, 0x24, 0x9d, 0x6e, 0x42, 0x1f, - 0xb1, 0x68, 0xfa, 0x99, 0xdf, 0x5a, 0x56, 0xf5, 0xee, 0xd7, 0xf5, 0xee, - 0x8f, 0xfa, 0xed, 0x26, 0x47, 0x7b, 0xaa, 0x4c, 0x1f, 0x1a, 0xed, 0x56, - 0xe9, 0xc3, 0xa3, 0x49, 0x95, 0x16, 0x54, 0xbd, 0x50, 0x7a, 0x7a, 0xd4, - 0x51, 0x69, 0xa7, 0x2e, 0x4f, 0x8d, 0x5a, 0x2a, 0xed, 0xd7, 0xa9, 0xab, - 0xd3, 0x01, 0x9d, 0x0e, 0xea, 0x34, 0xad, 0xd3, 0x8c, 0x4e, 0x87, 0x74, - 0x3f, 0x23, 0x3a, 0xbf, 0x5b, 0xa7, 0x63, 0x3a, 0x1d, 0xd7, 0xe9, 0x1e, - 0x9d, 0xee, 0xd5, 0x74, 0x4d, 0xe8, 0xf4, 0x41, 0x5d, 0x7e, 0x40, 0xd3, - 0x79, 0x10, 0xf4, 0x7c, 0xa6, 0x51, 0xcb, 0x2d, 0xe6, 0x6b, 0xc9, 0xbe, - 0x99, 0x98, 0x14, 0x4b, 0x61, 0xc9, 0xa9, 0xf5, 0xfc, 0x7c, 0x54, 0x9a, - 0x63, 0x32, 0x55, 0x8b, 0xc9, 0x45, 0x25, 0xae, 0x3f, 0xf4, 0xbe, 0xd1, - 0x6b, 0xca, 0x33, 0xb5, 0xb8, 0xbc, 0x50, 0x93, 0xd0, 0x58, 0x6f, 0x93, - 0x18, 0x73, 0xd7, 0x48, 0xc6, 0x0c, 0x49, 0x58, 0xf1, 0xd5, 0x92, 0xec, - 0x4c, 0x07, 0xf2, 0x76, 0x42, 0xe4, 0xe5, 0xa8, 0xbf, 0x8e, 0x31, 0x09, - 0x2f, 0x70, 0x5d, 0x16, 0x46, 0x5f, 0x9a, 0x4f, 0x48, 0xe4, 0x98, 0x85, - 0xfe, 0x5b, 0x24, 0xba, 0x20, 0x9d, 0x61, 0xe9, 0x4e, 0xdc, 0x87, 0x1a, - 0x43, 0xd5, 0x88, 0x0c, 0x57, 0x43, 0x58, 0xab, 0x18, 0xe4, 0xa4, 0x05, - 0x3f, 0x13, 0xbf, 0x38, 0x7e, 0x09, 0xfc, 0x3c, 0xf4, 0xd3, 0x29, 0xb9, - 0x2a, 0xfb, 0xc4, 0xb8, 0x25, 0x8c, 0x5f, 0xb2, 0xcd, 0x09, 0x21, 0x4d, - 0x09, 0xf9, 0x46, 0xaf, 0x4f, 0xd3, 0x0b, 0xb5, 0x58, 0x28, 0x7b, 0x52, - 0x0e, 0xe4, 0x5c, 0xb1, 0x0c, 0xa7, 0x59, 0xf2, 0x66, 0xc8, 0x9a, 0x4c, - 0xb5, 0x4b, 0x61, 0x1c, 0xef, 0x4a, 0x92, 0x31, 0xd0, 0x77, 0xde, 0x94, - 0x09, 0xff, 0x1d, 0xcb, 0xfe, 0x1e, 0xfb, 0xd5, 0x36, 0x29, 0xb8, 0x2f, - 0x94, 0xfe, 0x02, 0xcf, 0xec, 0xeb, 0xcd, 0x88, 0x4f, 0xf3, 0xdb, 0xc8, - 0xb3, 0xfc, 0x67, 0xdb, 0xfc, 0x3c, 0x9f, 0x59, 0x37, 0x18, 0x33, 0x98, - 0x2b, 0xc7, 0xee, 0xc5, 0x7c, 0x39, 0xfe, 0xea, 0x7c, 0x41, 0x47, 0x4b, - 0x28, 0x77, 0xd2, 0x92, 0xc3, 0xa5, 0x5b, 0x25, 0xeb, 0x7a, 0xde, 0x3e, - 0x57, 0xe2, 0x86, 0x74, 0x9b, 0x39, 0xbc, 0xad, 0x54, 0x25, 0x94, 0x2d, - 0x05, 0xfc, 0x60, 0xbf, 0x11, 0x94, 0x75, 0xa0, 0x7e, 0x6b, 0x68, 0xe8, - 0x24, 0x68, 0x4f, 0x93, 0x2f, 0x90, 0x59, 0xb7, 0x3b, 0x31, 0x89, 0xf1, - 0x16, 0xab, 0xdd, 0xee, 0x79, 0x31, 0xd1, 0x67, 0x3b, 0xea, 0x90, 0x47, - 0xec, 0x8b, 0x7d, 0xb2, 0xbf, 0x16, 0xb4, 0x8d, 0xe3, 0x1d, 0x69, 0xf2, - 0xbc, 0xac, 0x6b, 0x32, 0x2f, 0x65, 0xf0, 0xad, 0x4c, 0xbe, 0x35, 0x77, - 0xca, 0xa9, 0x2a, 0xc7, 0xd8, 0x8c, 0xee, 0xeb, 0xfe, 0x99, 0xd1, 0x9d, - 0x40, 0xff, 0x71, 0xa4, 0x5b, 0x42, 0xd9, 0xe3, 0x1e, 0xc6, 0x4f, 0xe0, - 0x79, 0xb3, 0x39, 0x5c, 0xd4, 0x32, 0x98, 0x00, 0xed, 0x71, 0x39, 0xa7, - 0xe4, 0x70, 0x8b, 0x84, 0x21, 0x87, 0x5c, 0xe3, 0xb6, 0x85, 0x1b, 0x25, - 0x1f, 0xb7, 0x2d, 0xea, 0xce, 0xae, 0x9d, 0x4d, 0x98, 0xa3, 0xd6, 0x82, - 0xc7, 0xe2, 0x90, 0xc3, 0xf3, 0x6d, 0x06, 0x4a, 0x0c, 0xb1, 0xcd, 0x7f, - 0x25, 0x05, 0xc9, 0x2d, 0x7d, 0x2a, 0x24, 0xcd, 0x06, 0xea, 0x5d, 0x1b, - 0xf2, 0x79, 0x40, 0xfe, 0x64, 0xc0, 0x9f, 0x90, 0xf8, 0xfb, 0x3a, 0x23, - 0x5d, 0x55, 0xbe, 0xef, 0xb3, 0x0c, 0xf5, 0x6e, 0x08, 0xef, 0x22, 0x92, - 0xdc, 0x19, 0xbc, 0x1f, 0xc2, 0xfb, 0x6b, 0x64, 0xc2, 0x04, 0x2d, 0xa5, - 0xe7, 0x8d, 0x2c, 0x68, 0xbc, 0x3d, 0xa2, 0xe6, 0x8a, 0xba, 0x13, 0x75, - 0xfd, 0x4c, 0xa0, 0xde, 0x1f, 0x63, 0x2c, 0xd0, 0x5b, 0xb2, 0x40, 0x4b, - 0x07, 0x68, 0x21, 0x8d, 0x05, 0x23, 0x5b, 0x8b, 0x20, 0x3f, 0x6d, 0xe4, - 0x4e, 0x1f, 0xc1, 0xb3, 0x98, 0x46, 0xfa, 0x79, 0xa6, 0x68, 0xbf, 0xb7, - 0xae, 0xfd, 0x5e, 0xb4, 0xe7, 0x18, 0x6c, 0xef, 0xcb, 0x7f, 0x41, 0xc9, - 0xa2, 0x75, 0x05, 0x7e, 0x84, 0x7f, 0x0d, 0x7e, 0x7c, 0x4d, 0xf3, 0xe3, - 0x67, 0xf2, 0x9b, 0xe7, 0xc7, 0x7f, 0xff, 0x0d, 0xf1, 0x43, 0x24, 0x7f, - 0x9c, 0xcf, 0x11, 0x29, 0x28, 0xbd, 0xc5, 0x7d, 0x4b, 0x79, 0xa7, 0xce, - 0x22, 0x9f, 0x28, 0xc7, 0xd8, 0x03, 0xb5, 0x08, 0xd2, 0xa7, 0x90, 0x6e, - 0x09, 0x8d, 0x1d, 0xbf, 0x84, 0xf5, 0xf7, 0xc4, 0xdc, 0x19, 0xd8, 0x8d, - 0x42, 0xc2, 0x94, 0x4e, 0x31, 0xaf, 0x87, 0xd1, 0xee, 0xb0, 0xcd, 0xbc, - 0xbc, 0x89, 0xf7, 0xbf, 0x08, 0x05, 0xf6, 0x3d, 0x3b, 0xd3, 0xf4, 0x76, - 0x46, 0x3d, 0x45, 0xc9, 0xcf, 0x8c, 0x91, 0x8e, 0x84, 0x72, 0x25, 0x6b, - 0xc2, 0x48, 0xc7, 0xa1, 0xa7, 0x98, 0x1f, 0x0c, 0xf9, 0x34, 0x0f, 0xa0, - 0x6e, 0xa0, 0xb3, 0x02, 0xda, 0x07, 0x40, 0xfb, 0x46, 0xdd, 0x95, 0x01, - 0x2d, 0xa4, 0x81, 0x74, 0x55, 0xc2, 0x9a, 0xf7, 0xe8, 0xe7, 0xa0, 0xea, - 0x27, 0x9c, 0x1e, 0x14, 0xda, 0xd0, 0xfc, 0x0c, 0xf7, 0x01, 0xdb, 0xb1, - 0x2f, 0x5f, 0x27, 0xe7, 0xab, 0x41, 0x1f, 0x85, 0xba, 0x3e, 0x0a, 0xa0, - 0x47, 0xb6, 0x19, 0x4e, 0x14, 0x6b, 0xcf, 0xae, 0x8e, 0xe0, 0xdd, 0x93, - 0x92, 0x3d, 0x7d, 0xb3, 0x81, 0x39, 0xa0, 0x5f, 0xf2, 0x68, 0x0c, 0x3a, - 0x9b, 0xfb, 0x2c, 0x26, 0xb9, 0x38, 0xcb, 0x3e, 0xa6, 0xc7, 0x8d, 0x48, - 0x46, 0xe5, 0x5f, 0x69, 0x5d, 0xa3, 0xe3, 0x79, 0x3d, 0x9f, 0x34, 0xe6, - 0x43, 0x1a, 0x82, 0xb9, 0xa4, 0xeb, 0xe6, 0x12, 0xf0, 0x9a, 0xbc, 0x30, - 0xa1, 0xe3, 0x63, 0xda, 0x86, 0xb0, 0xdd, 0x74, 0xdd, 0xda, 0x4d, 0xa3, - 0x0d, 0x79, 0x8f, 0x3a, 0x1b, 0xec, 0x0a, 0x6d, 0xca, 0x10, 0xfa, 0x29, - 0xce, 0x1b, 0x92, 0x73, 0x61, 0xab, 0xdd, 0x77, 0x6b, 0x79, 0x5d, 0x93, - 0xa5, 0xe8, 0xa6, 0xb2, 0x74, 0xc8, 0xf0, 0xf5, 0x35, 0x6c, 0x0b, 0xec, - 0xcf, 0xd4, 0xbc, 0x9d, 0x0a, 0x64, 0xa9, 0x38, 0xf3, 0x4e, 0x64, 0x29, - 0x68, 0x1f, 0x83, 0xec, 0x06, 0x63, 0x6c, 0xa4, 0x39, 0xa8, 0x03, 0x1a, - 0x4b, 0x59, 0x8d, 0x51, 0x38, 0x8e, 0x6f, 0x1b, 0xca, 0xeb, 0x6c, 0xc3, - 0x11, 0xb4, 0x95, 0x50, 0xae, 0xb7, 0x45, 0xf6, 0xcf, 0x07, 0x7d, 0x1c, - 0x51, 0x32, 0x3b, 0x39, 0x63, 0x9b, 0xc3, 0x61, 0xc9, 0x0c, 0xcf, 0x0e, - 0xca, 0x50, 0xad, 0x13, 0x6b, 0xfa, 0xb6, 0x07, 0xdb, 0x79, 0x7d, 0x54, - 0x1c, 0xe8, 0x45, 0xcc, 0x79, 0x00, 0x3c, 0xae, 0x45, 0xc5, 0x48, 0xbb, - 0x48, 0xeb, 0x31, 0x56, 0x24, 0x32, 0xbc, 0x2e, 0xdf, 0x80, 0x3a, 0xe8, - 0x7b, 0x60, 0x63, 0x3d, 0xc8, 0x27, 0x78, 0x9b, 0x75, 0x7f, 0xe1, 0xc1, - 0x0e, 0x6b, 0x9b, 0xc5, 0x52, 0xea, 0x89, 0x40, 0x47, 0x7c, 0x14, 0xfb, - 0x5b, 0xed, 0x85, 0x82, 0x91, 0x3e, 0x80, 0x3e, 0x44, 0xc9, 0x69, 0xb1, - 0xf6, 0x4c, 0xb0, 0xef, 0x55, 0xf9, 0xae, 0x01, 0xca, 0x5e, 0x19, 0x98, - 0x80, 0x73, 0x5a, 0x52, 0x7b, 0x3d, 0x67, 0xc6, 0x65, 0xba, 0xc4, 0xf9, - 0x2c, 0x49, 0xb2, 0xfa, 0xa7, 0x92, 0x3b, 0x2d, 0xf2, 0xad, 0x19, 0xd6, - 0xfb, 0xba, 0xae, 0xf7, 0x3c, 0xea, 0x25, 0xad, 0xa1, 0x90, 0x0d, 0x3b, - 0x60, 0x63, 0x9b, 0xf4, 0x59, 0x48, 0xcd, 0x11, 0xfc, 0x86, 0x68, 0x64, - 0x50, 0xcf, 0xc7, 0x40, 0xcf, 0x83, 0x1f, 0x22, 0x77, 0x95, 0x1a, 0xa1, - 0x4f, 0xfe, 0x27, 0x68, 0x8d, 0xcb, 0xe3, 0x98, 0xc7, 0x4b, 0x33, 0xc4, - 0x59, 0x5f, 0x97, 0xe5, 0x19, 0xe2, 0xae, 0xe7, 0x65, 0x7a, 0x26, 0xe9, - 0x7e, 0x0b, 0x7c, 0x3e, 0x25, 0x9c, 0x4b, 0x9f, 0x8b, 0x14, 0x18, 0xd0, - 0xb6, 0x1e, 0x83, 0x3e, 0xeb, 0xdd, 0xe9, 0xf7, 0xd7, 0xad, 0xfb, 0x73, - 0xaa, 0xb6, 0x5c, 0x34, 0xa9, 0x9f, 0x2e, 0xdf, 0xe3, 0x59, 0xbd, 0xc7, - 0xc7, 0xdc, 0x4e, 0x31, 0xb0, 0xaf, 0x33, 0xe3, 0x05, 0x58, 0x3f, 0xee, - 0xeb, 0xff, 0x6b, 0xac, 0xe1, 0x9f, 0x04, 0xb0, 0xaa, 0xad, 0xec, 0xdd, - 0x3f, 0x6e, 0x8f, 0xd7, 0xef, 0x6d, 0x8e, 0xdf, 0x8a, 0x36, 0x11, 0xa4, - 0x57, 0xde, 0xd7, 0xe8, 0xa3, 0xae, 0xed, 0x20, 0xf7, 0x05, 0xda, 0xfc, - 0x09, 0x78, 0x41, 0xfe, 0xbf, 0x93, 0xfd, 0xdc, 0x17, 0x7e, 0x47, 0xfb, - 0x79, 0xfc, 0x4a, 0xfb, 0xb9, 0x7e, 0x2f, 0x9f, 0x25, 0x2f, 0x30, 0xb6, - 0xcc, 0xfa, 0xb2, 0xd5, 0x0d, 0x5e, 0x5b, 0x90, 0x53, 0xd0, 0x50, 0xfa, - 0x07, 0x2f, 0x13, 0xf1, 0xf1, 0x9c, 0x2f, 0x4f, 0xac, 0x17, 0xd4, 0xf1, - 0x75, 0xef, 0x50, 0xed, 0xa2, 0xd2, 0xb3, 0xe7, 0x94, 0x9e, 0xb5, 0x8f, - 0x14, 0x84, 0xf2, 0x76, 0x43, 0x98, 0x7c, 0x7f, 0xc6, 0xfd, 0x2c, 0x68, - 0xb4, 0x2d, 0xcb, 0xe8, 0x2e, 0x18, 0xc6, 0x67, 0xe5, 0xc0, 0xe2, 0x43, - 0x72, 0xa0, 0xc4, 0x3e, 0xd2, 0x78, 0xef, 0xa0, 0xac, 0x09, 0xba, 0x96, - 0x3a, 0xfd, 0xed, 0x90, 0x3f, 0x96, 0x01, 0xfb, 0xb5, 0x12, 0xba, 0xab, - 0x76, 0x21, 0x94, 0x5d, 0xe4, 0xde, 0x45, 0x79, 0xad, 0x5e, 0xe7, 0x07, - 0xfa, 0xbe, 0x5e, 0xb7, 0x17, 0x42, 0x63, 0xa5, 0x69, 0xe2, 0x40, 0x23, - 0xeb, 0x46, 0xb5, 0xee, 0xf8, 0x9a, 0x29, 0xad, 0xb0, 0x2d, 0xc6, 0x3c, - 0x78, 0x45, 0x9c, 0x4a, 0xde, 0xa5, 0x24, 0x13, 0x21, 0x9e, 0xe4, 0xb3, - 0x78, 0xe1, 0x34, 0xf7, 0x9e, 0x44, 0xc2, 0xe9, 0x2e, 0xf0, 0x8e, 0x75, - 0x6e, 0x05, 0xad, 0xb0, 0x7b, 0xee, 0xfb, 0x84, 0x72, 0xf9, 0x42, 0xe9, - 0x36, 0xe4, 0x23, 0x9a, 0xbf, 0x51, 0xd4, 0x61, 0x7f, 0x3f, 0x6d, 0x90, - 0xd6, 0xe3, 0xd0, 0x15, 0x41, 0xbf, 0xac, 0x93, 0xd0, 0x75, 0x5a, 0x74, - 0x9d, 0x5b, 0xf0, 0x7e, 0x0e, 0xf5, 0x6c, 0x57, 0x84, 0x7c, 0x60, 0x59, - 0x3b, 0xe6, 0x85, 0xba, 0x8b, 0xe9, 0xf0, 0x7a, 0xba, 0x6e, 0xaa, 0xab, - 0xcb, 0xfc, 0x66, 0x58, 0x97, 0xf2, 0x24, 0x5a, 0x97, 0xb1, 0x6c, 0x10, - 0xcf, 0x5d, 0x32, 0xb1, 0x98, 0x81, 0x4e, 0xba, 0x5d, 0xf5, 0x13, 0x75, - 0xd6, 0xd9, 0x3a, 0xd0, 0x64, 0x69, 0x9a, 0xb6, 0x04, 0xfa, 0x18, 0x65, - 0xae, 0x2e, 0x6b, 0xa8, 0x2b, 0x0b, 0xe4, 0xe7, 0x5f, 0x83, 0x76, 0x8e, - 0x3d, 0xa2, 0x71, 0x98, 0xe7, 0xe5, 0x28, 0x77, 0xfd, 0xff, 0x52, 0xf3, - 0xa2, 0x60, 0x86, 0xd5, 0x5e, 0xa9, 0xfe, 0xf6, 0xda, 0x5e, 0x01, 0x6e, - 0x57, 0xbd, 0x70, 0x8e, 0xa4, 0xa5, 0x05, 0x6b, 0x3b, 0x04, 0x5a, 0xb1, - 0x86, 0x1d, 0x21, 0xcc, 0xb7, 0x45, 0xf2, 0xb5, 0xb4, 0x7e, 0xc7, 0xf2, - 0x88, 0x8c, 0xc5, 0x83, 0xf9, 0x7d, 0xc0, 0xf4, 0xb1, 0x37, 0xea, 0x94, - 0xb6, 0x44, 0xfc, 0xbd, 0x68, 0x4a, 0xfe, 0xe4, 0x10, 0x64, 0x9e, 0xd8, - 0xb0, 0x01, 0x32, 0x1f, 0x57, 0x36, 0xc7, 0x70, 0x58, 0x1f, 0xef, 0x4e, - 0xff, 0xbb, 0xb0, 0xdf, 0x86, 0xf5, 0x82, 0x36, 0xc1, 0xd8, 0xed, 0xab, - 0x6d, 0xc7, 0x5c, 0x43, 0xc2, 0x6a, 0x7c, 0x94, 0x9d, 0x5e, 0x3f, 0xbe, - 0xd1, 0x11, 0x8c, 0xff, 0xa7, 0xba, 0xaf, 0xf6, 0xba, 0xbe, 0xe2, 0x57, - 0x18, 0x1f, 0xef, 0x4e, 0xff, 0xee, 0x76, 0xbf, 0x4d, 0xbc, 0xae, 0x4d, - 0xc7, 0x86, 0x36, 0xac, 0x1f, 0x8c, 0x81, 0x77, 0xa7, 0xef, 0x6b, 0xf1, - 0xdb, 0xb0, 0x5e, 0x03, 0x6c, 0x2c, 0xdf, 0x71, 0x0f, 0x1e, 0xa8, 0xdb, - 0x83, 0x07, 0xb0, 0x07, 0x03, 0xd9, 0xde, 0x88, 0xd7, 0x03, 0xbf, 0x8b, - 0xfe, 0x16, 0x31, 0xde, 0x9a, 0x7f, 0x15, 0x59, 0x68, 0x01, 0x7e, 0x6a, - 0xa5, 0x4f, 0xa5, 0xf1, 0x39, 0x7d, 0x2c, 0xe2, 0x71, 0x71, 0x22, 0xd2, - 0x0d, 0x5d, 0xd9, 0x9d, 0xd8, 0xcf, 0x8d, 0x5f, 0x8d, 0x2b, 0xdc, 0x9e, - 0xd1, 0x63, 0xd0, 0xbf, 0x22, 0xdf, 0x99, 0xcf, 0xad, 0xfa, 0x5b, 0x9d, - 0xf0, 0xc7, 0x88, 0xbb, 0x89, 0xdb, 0x02, 0xfa, 0x03, 0x7a, 0x0e, 0x1a, - 0x6b, 0x7b, 0x33, 0x63, 0x0c, 0xd5, 0x86, 0x0c, 0x7f, 0x6f, 0xf2, 0xfd, - 0x41, 0x6d, 0x5b, 0x37, 0xd2, 0xfb, 0x9e, 0x0d, 0xf4, 0x12, 0xdf, 0x59, - 0x32, 0x05, 0x19, 0x89, 0x2c, 0x50, 0xd7, 0x2f, 0x8c, 0x2e, 0xcf, 0x13, - 0xc7, 0xf4, 0x83, 0x2f, 0xa4, 0x97, 0xfc, 0xa3, 0x4e, 0x69, 0x85, 0x9e, - 0xea, 0x4e, 0x55, 0x50, 0x9f, 0x7e, 0xfe, 0x84, 0xf2, 0x0f, 0x5b, 0x90, - 0xc2, 0x89, 0x03, 0xad, 0x13, 0xa0, 0x75, 0x42, 0xfb, 0x86, 0xfb, 0x61, - 0x47, 0x22, 0xc7, 0x02, 0x5a, 0x6f, 0x89, 0x04, 0x6b, 0xb3, 0x9e, 0xf6, - 0x7a, 0xfb, 0xe7, 0xe3, 0xc0, 0xbb, 0x7a, 0xd5, 0x9e, 0x2c, 0x10, 0x3b, - 0x4e, 0x9c, 0x0e, 0xf6, 0xa3, 0xf8, 0x7b, 0xa9, 0x35, 0xc0, 0x01, 0x9c, - 0x0f, 0x71, 0x08, 0x75, 0x4f, 0x30, 0x87, 0x16, 0xe9, 0x5a, 0xe0, 0x1c, - 0x56, 0xe9, 0x8f, 0x33, 0xca, 0x72, 0x00, 0xfa, 0x3b, 0xaf, 0x68, 0xdd, - 0x2d, 0x93, 0xa5, 0xf7, 0x69, 0xfa, 0x5b, 0x40, 0xff, 0x18, 0x64, 0x7b, - 0x4d, 0x77, 0xe5, 0xab, 0xe3, 0xc8, 0xfb, 0x98, 0x90, 0x3c, 0xce, 0x57, - 0xa9, 0xc7, 0xf4, 0x7c, 0x9a, 0x39, 0x9f, 0x8d, 0x3a, 0x6e, 0x33, 0xbe, - 0xbe, 0x77, 0x03, 0x5f, 0x45, 0xf3, 0x35, 0x26, 0x0d, 0x0b, 0xca, 0xbf, - 0x46, 0xbf, 0xe4, 0x35, 0xed, 0xe8, 0xc2, 0xe8, 0xf4, 0xbc, 0xf4, 0x33, - 0x08, 0x95, 0x07, 0xdf, 0x50, 0x36, 0xd0, 0x20, 0xdd, 0xee, 0x05, 0xcc, - 0x3b, 0x8f, 0xf5, 0x36, 0x8e, 0xf9, 0xf2, 0x4d, 0xfe, 0xe6, 0xab, 0xcd, - 0xf0, 0xe9, 0x39, 0x36, 0x79, 0x46, 0xfa, 0x4d, 0x45, 0xcf, 0x2a, 0xbf, - 0x41, 0xdf, 0x7d, 0xd5, 0x8d, 0xbc, 0xad, 0xd7, 0x33, 0x41, 0xec, 0xe0, - 0x35, 0xd3, 0xdf, 0x17, 0x9b, 0xc5, 0x0e, 0x5a, 0xa0, 0xa3, 0x23, 0x8c, - 0x13, 0x80, 0xf7, 0x8c, 0xf3, 0x5c, 0x8a, 0xd0, 0x17, 0x78, 0xa1, 0x04, - 0x3d, 0x73, 0x9c, 0xd8, 0xa5, 0x55, 0xef, 0x8f, 0x1b, 0xb4, 0x0d, 0x8b, - 0x2a, 0xdb, 0x21, 0x86, 0x49, 0x7c, 0x84, 0x32, 0xe4, 0x17, 0x99, 0x0f, - 0xe8, 0xb8, 0x7b, 0x4f, 0xd4, 0x79, 0x21, 0x12, 0xe8, 0x84, 0x35, 0xba, - 0xea, 0x63, 0x03, 0x1e, 0x30, 0xe5, 0xfb, 0x20, 0xb7, 0xb7, 0xc3, 0xff, - 0xb7, 0x24, 0x9f, 0xe2, 0x3e, 0x1a, 0x54, 0x3e, 0x92, 0xe1, 0xec, 0x47, - 0x59, 0x13, 0xca, 0x60, 0x4c, 0x4d, 0xcc, 0xdf, 0xf9, 0x3d, 0x99, 0x80, - 0x8c, 0xe7, 0x53, 0x7d, 0xa0, 0x83, 0xf8, 0x0e, 0x58, 0xcb, 0x49, 0x31, - 0x7e, 0x80, 0xbf, 0x7b, 0xa3, 0xfe, 0xbc, 0xf6, 0x20, 0xdf, 0x8c, 0x3a, - 0x5d, 0xba, 0xce, 0x16, 0x61, 0x1c, 0x2a, 0x6f, 0xb6, 0x22, 0xed, 0xd9, - 0x50, 0xf7, 0x43, 0xc8, 0xdf, 0xa2, 0xfb, 0x2f, 0xe0, 0xfd, 0x4d, 0xf8, - 0x0d, 0xa1, 0xec, 0x66, 0x94, 0xb9, 0x28, 0xbb, 0x11, 0xf9, 0x0f, 0xe9, - 0xb8, 0x44, 0xd0, 0xa6, 0x15, 0xf9, 0x47, 0xf1, 0x1e, 0xba, 0xc2, 0x7c, - 0x05, 0xef, 0x6f, 0xc1, 0xef, 0xfa, 0x0d, 0x75, 0xda, 0x37, 0xe4, 0x4f, - 0xae, 0xf2, 0xe0, 0x85, 0xd2, 0x55, 0xfa, 0x99, 0xf2, 0xcc, 0xfc, 0x2b, - 0x3a, 0x7f, 0xfb, 0x86, 0xf2, 0xfb, 0x83, 0x7c, 0xdd, 0x1a, 0xc2, 0x0e, - 0x9a, 0x01, 0xd6, 0xbd, 0xda, 0xf4, 0xd7, 0xe0, 0x3d, 0x7e, 0xbc, 0xa0, - 0x14, 0xb4, 0x23, 0xf6, 0xbd, 0x3d, 0xbc, 0xbe, 0xaf, 0xff, 0xd6, 0xb0, - 0x96, 0x6f, 0x09, 0x0d, 0x9f, 0x64, 0xd9, 0x4f, 0x1b, 0xd6, 0xd7, 0x79, - 0x5f, 0xe3, 0x5a, 0x7e, 0x6b, 0x68, 0xf8, 0x38, 0xcb, 0xee, 0x6b, 0x5c, - 0x5f, 0x67, 0xb8, 0x71, 0x6d, 0x1e, 0x6b, 0xba, 0x30, 0x92, 0xae, 0x50, - 0x8e, 0xb1, 0x17, 0xaa, 0xa3, 0xd9, 0x19, 0xcf, 0x9b, 0x72, 0x57, 0x12, - 0x61, 0xa1, 0x0d, 0x22, 0x66, 0x66, 0xf9, 0x53, 0x28, 0x07, 0xa6, 0xaa, - 0x8d, 0x09, 0x75, 0xd2, 0xe6, 0xd8, 0xd8, 0xd2, 0xd8, 0x58, 0x65, 0x23, - 0x59, 0x85, 0x65, 0x9f, 0x18, 0x05, 0xf6, 0xd2, 0xcf, 0x4f, 0xe2, 0xd9, - 0xaa, 0xc7, 0xdf, 0xe8, 0xb7, 0x3c, 0x9a, 0x9d, 0xa7, 0xcd, 0x5b, 0x1a, - 0xdd, 0x37, 0xcf, 0x3d, 0x7f, 0x0a, 0x7b, 0x3e, 0x24, 0xd3, 0xca, 0xfe, - 0x91, 0x0e, 0xb6, 0x2b, 0x8f, 0x76, 0x2d, 0x31, 0xad, 0x8c, 0x3a, 0x4b, - 0x61, 0xd9, 0x1f, 0xf7, 0xdb, 0x32, 0x6f, 0x2d, 0x05, 0x7b, 0xa0, 0x59, - 0xa2, 0x69, 0xca, 0xa4, 0x9d, 0x82, 0x0f, 0x80, 0xf9, 0x1c, 0x19, 0x9d, - 0x76, 0x28, 0x9f, 0x9f, 0x82, 0xdd, 0x6f, 0x96, 0x06, 0xa5, 0x6f, 0x1e, - 0xd7, 0x63, 0x9d, 0xc2, 0x58, 0xdb, 0xd4, 0x7e, 0xca, 0x3a, 0x91, 0x04, - 0xc6, 0x39, 0x64, 0x38, 0x7d, 0x18, 0x8f, 0x1e, 0x7b, 0xa7, 0x4c, 0xd5, - 0xb8, 0x6f, 0xf6, 0x44, 0xd7, 0xfc, 0xf4, 0x39, 0xb4, 0x0b, 0xfc, 0x43, - 0x8e, 0x57, 0x01, 0x3e, 0x84, 0x2c, 0xa7, 0x6d, 0x33, 0x1b, 0x86, 0x9d, - 0x9f, 0x0f, 0xea, 0x90, 0xa6, 0x63, 0xa3, 0xc9, 0xa5, 0x24, 0xfa, 0xea, - 0xa4, 0x0e, 0x83, 0xee, 0x0a, 0xe3, 0xc7, 0xbe, 0xd9, 0x0e, 0xb6, 0x68, - 0x90, 0x76, 0x64, 0x0e, 0x76, 0xa4, 0x53, 0x0e, 0x97, 0x54, 0x1f, 0x16, - 0xfb, 0x28, 0xea, 0xb6, 0x5d, 0x4b, 0x0d, 0xf0, 0xb1, 0x92, 0xe6, 0x8b, - 0xb2, 0xd6, 0x76, 0x58, 0xfc, 0x76, 0x7e, 0xdf, 0x3f, 0xf1, 0x32, 0xf1, - 0xfa, 0xbd, 0xdf, 0x2c, 0x61, 0xd0, 0x91, 0x43, 0x1f, 0x1c, 0x7f, 0xad, - 0xef, 0xa0, 0xbf, 0xa4, 0x79, 0xfe, 0xb2, 0xbe, 0xb6, 0x69, 0xfc, 0x66, - 0x5b, 0xb9, 0x5f, 0x6b, 0x6c, 0xce, 0xf7, 0x09, 0xc8, 0x83, 0x44, 0x72, - 0xbd, 0xd0, 0x8b, 0xb5, 0x41, 0x2d, 0x23, 0x4f, 0xa2, 0xac, 0xde, 0xc7, - 0xf2, 0xe5, 0xab, 0x00, 0x6c, 0x59, 0xc4, 0x3e, 0x0f, 0xa7, 0x33, 0x6d, - 0x7e, 0xcc, 0xeb, 0x4a, 0x7e, 0x15, 0xe4, 0x06, 0x7d, 0x16, 0x57, 0xdb, - 0x72, 0x4e, 0x4f, 0x8e, 0xbe, 0x34, 0x93, 0xc0, 0x9c, 0x7c, 0xbb, 0xe0, - 0xf3, 0x9a, 0x36, 0x27, 0x24, 0xcb, 0x8e, 0x05, 0xff, 0x9d, 0x36, 0xde, - 0x92, 0x97, 0x9d, 0xc0, 0xfe, 0xd0, 0x16, 0xa1, 0x7e, 0x8d, 0xb4, 0x91, - 0xf6, 0x39, 0xcc, 0xcd, 0x93, 0x59, 0xd7, 0x97, 0xc1, 0x5e, 0xd8, 0x91, - 0xff, 0x18, 0xb1, 0x8f, 0xd0, 0xcf, 0xbb, 0x18, 0xa9, 0x9f, 0x4f, 0x80, - 0x15, 0x9e, 0xd0, 0x31, 0xe8, 0x39, 0x2d, 0x2f, 0x65, 0xc8, 0x4b, 0x9f, - 0x65, 0x4a, 0x0f, 0x68, 0x47, 0x9d, 0xfe, 0x6e, 0xf8, 0x5b, 0xf4, 0xe5, - 0x13, 0xa0, 0xc7, 0x84, 0xee, 0xd8, 0xa6, 0x7d, 0x87, 0xb7, 0xa2, 0xb4, - 0x6d, 0x6d, 0x2a, 0xbe, 0x3d, 0xa7, 0xe4, 0xd9, 0x97, 0xef, 0xb0, 0x7e, - 0x1f, 0xc8, 0x54, 0x98, 0x90, 0x46, 0xd6, 0xe2, 0xb8, 0xac, 0xbf, 0xa0, - 0xeb, 0xcf, 0xa3, 0x7e, 0x08, 0x73, 0xf2, 0xbc, 0x49, 0x45, 0xef, 0x02, - 0xf8, 0x1e, 0x96, 0xe2, 0xaa, 0xcc, 0x2f, 0x40, 0xe6, 0x29, 0xdf, 0x73, - 0xd8, 0xaf, 0x20, 0xfe, 0x6e, 0xca, 0x7d, 0x45, 0x86, 0x4e, 0xef, 0x6f, - 0x60, 0xcc, 0xd5, 0x32, 0xe8, 0x03, 0x53, 0x26, 0x3b, 0xe5, 0xb1, 0x52, - 0xd2, 0x9c, 0xaa, 0x5b, 0xcb, 0x5d, 0xeb, 0xd6, 0x92, 0x32, 0xa0, 0xea, - 0xa7, 0x58, 0xbf, 0x52, 0x27, 0x03, 0x8b, 0xf3, 0x57, 0x6a, 0x47, 0x19, - 0x60, 0xbb, 0xcd, 0xfc, 0x05, 0xc6, 0x28, 0x3d, 0x6f, 0xd9, 0x25, 0xfe, - 0x6f, 0x94, 0x82, 0x92, 0xb1, 0x90, 0x14, 0x5d, 0xee, 0xab, 0xac, 0x15, - 0x11, 0x1b, 0x58, 0xe9, 0xf7, 0x41, 0x67, 0x26, 0x15, 0x15, 0x3f, 0xa6, - 0x31, 0x81, 0x35, 0x58, 0x31, 0x3d, 0xef, 0x25, 0x47, 0xa4, 0x02, 0x1f, - 0x78, 0x19, 0x69, 0xb1, 0x8a, 0x3d, 0xdb, 0x1c, 0x81, 0x0e, 0x08, 0x64, - 0x3c, 0x26, 0x65, 0xd4, 0x59, 0xc4, 0xbb, 0xc7, 0xaa, 0x81, 0xc4, 0x78, - 0x9e, 0x01, 0x1e, 0xed, 0x73, 0x7e, 0xea, 0xe5, 0xe3, 0xf5, 0x75, 0x03, - 0x4c, 0x4c, 0x2c, 0x4b, 0x6c, 0x4a, 0x4c, 0xc9, 0x77, 0xc4, 0x89, 0x87, - 0x40, 0x0b, 0xf7, 0x6c, 0xab, 0xc4, 0xd2, 0x76, 0x62, 0x44, 0x02, 0xdb, - 0xff, 0x3a, 0x64, 0xa9, 0xe0, 0x35, 0x3a, 0x9d, 0xf2, 0x1c, 0xe4, 0xe6, - 0xd9, 0x55, 0x1c, 0x63, 0x41, 0x8e, 0x68, 0x47, 0x3d, 0x39, 0xe7, 0x3a, - 0xd6, 0xe7, 0x90, 0x7e, 0xc7, 0xfd, 0x00, 0xf9, 0xf6, 0x84, 0x48, 0x3f, - 0x7c, 0x32, 0xe8, 0xf5, 0xd9, 0x00, 0xdb, 0xb7, 0xd2, 0x37, 0xd4, 0xb2, - 0x74, 0x11, 0x7d, 0xda, 0xa6, 0x01, 0x50, 0x7b, 0x07, 0xea, 0xf9, 0x7b, - 0x23, 0x28, 0x3b, 0x84, 0xba, 0xa4, 0x81, 0x7e, 0xfb, 0x77, 0xb1, 0x67, - 0x3d, 0xef, 0x1e, 0xf7, 0xe5, 0x3a, 0x5d, 0xb3, 0x80, 0xf5, 0x57, 0x72, - 0x3e, 0xd0, 0x26, 0x8c, 0xf3, 0x4a, 0x7f, 0xbb, 0xf2, 0x2b, 0xf9, 0x0c, - 0x79, 0x1f, 0x20, 0x16, 0xb2, 0x14, 0xd6, 0x24, 0x6e, 0x78, 0x16, 0xbc, - 0xff, 0xa4, 0xc2, 0x34, 0xc4, 0x6f, 0xa0, 0xbf, 0x44, 0x4c, 0xe1, 0x63, - 0x69, 0x1f, 0xd7, 0x11, 0x5b, 0xa4, 0xb8, 0x36, 0x1a, 0x5f, 0xb0, 0x2d, - 0xeb, 0xb1, 0x6d, 0xfd, 0xfa, 0xb1, 0xce, 0xb6, 0x50, 0xee, 0x38, 0xe5, - 0x99, 0xf6, 0xb1, 0x4d, 0xf6, 0xa7, 0x1a, 0xc1, 0xf7, 0x76, 0x6d, 0xc7, - 0x3f, 0x08, 0xcc, 0x06, 0xec, 0x6d, 0xd2, 0x87, 0x0a, 0x78, 0x7d, 0x23, - 0xca, 0x7e, 0x0e, 0xfe, 0xb3, 0x0c, 0xfe, 0x95, 0xb2, 0x93, 0x0f, 0x61, - 0x2f, 0x97, 0xb7, 0xf9, 0x31, 0x34, 0xae, 0x43, 0x80, 0x13, 0x02, 0xdc, - 0x67, 0x6a, 0xbc, 0xcf, 0xb5, 0xf1, 0xe3, 0x6d, 0x86, 0xaa, 0x4b, 0x5f, - 0xab, 0xde, 0xc7, 0xe5, 0x1e, 0xf6, 0xbc, 0x73, 0x6e, 0x80, 0x23, 0xeb, - 0xfd, 0xc4, 0xc0, 0x07, 0x8c, 0x89, 0xd5, 0x4e, 0x4c, 0xf1, 0x47, 0x0d, - 0x6b, 0x58, 0xe6, 0x1f, 0xbc, 0xb0, 0x43, 0x9f, 0x93, 0x38, 0x26, 0xf0, - 0x07, 0x59, 0x97, 0xd8, 0xe6, 0x51, 0x8c, 0x11, 0x16, 0xab, 0x83, 0xf9, - 0x1f, 0xeb, 0x36, 0x7c, 0xf6, 0xa4, 0x67, 0x67, 0xbd, 0x3c, 0x0f, 0xfa, - 0xfe, 0x62, 0x73, 0x10, 0x03, 0xee, 0x54, 0xfa, 0x64, 0x4d, 0x2e, 0x02, - 0x9a, 0x82, 0x71, 0x7d, 0xff, 0xb4, 0x1d, 0xb4, 0xdd, 0x05, 0x9b, 0xb2, - 0xb3, 0xdd, 0xae, 0xf3, 0x45, 0xeb, 0x69, 0xaa, 0xc7, 0x57, 0x16, 0xc6, - 0x68, 0x94, 0x9d, 0x1d, 0xe4, 0x5d, 0xa7, 0xb2, 0x2d, 0x6b, 0xeb, 0x41, - 0xdb, 0xcf, 0xb1, 0x37, 0x96, 0xdf, 0x52, 0x47, 0xd7, 0x46, 0xcc, 0x47, - 0x1f, 0xd7, 0xc7, 0x7c, 0x99, 0xb8, 0x27, 0xbb, 0xdc, 0x00, 0xdf, 0xd5, - 0xd3, 0x41, 0x8c, 0x47, 0x9a, 0xa3, 0x75, 0x3e, 0xf2, 0xef, 0xea, 0x33, - 0xaa, 0x39, 0x3d, 0x97, 0xc0, 0x97, 0x4e, 0xa2, 0xfe, 0x7f, 0x00, 0xdd, - 0x7c, 0x26, 0xed, 0x01, 0x1e, 0x4c, 0xfa, 0x6d, 0x9b, 0x37, 0xc3, 0xfd, - 0xdc, 0x27, 0x01, 0x6f, 0xda, 0xf5, 0xba, 0xd4, 0xfb, 0xe3, 0xea, 0xe7, - 0xae, 0xd7, 0x1d, 0x37, 0xd6, 0xcd, 0xa9, 0x5f, 0x0a, 0x8b, 0x94, 0x85, - 0xf7, 0x23, 0x0d, 0xfc, 0xa1, 0x01, 0xd8, 0x8e, 0x0c, 0xfc, 0x1f, 0xfa, - 0x45, 0x97, 0xf9, 0x44, 0x3c, 0xc3, 0x1c, 0xcf, 0xc3, 0x47, 0x56, 0xb6, - 0xc3, 0xb7, 0x8b, 0xc8, 0x43, 0x87, 0xd4, 0xee, 0xa6, 0x5c, 0x8d, 0x4f, - 0x54, 0xdd, 0xf1, 0xc9, 0xea, 0xc0, 0x38, 0x7d, 0x07, 0x5f, 0xce, 0x50, - 0xbf, 0x2a, 0x13, 0x06, 0xda, 0x65, 0x55, 0x3b, 0x15, 0xcb, 0xd8, 0xa4, - 0x1f, 0xe1, 0x1e, 0x9c, 0xf0, 0xc7, 0x8a, 0x8d, 0xe7, 0xa0, 0x77, 0x16, - 0x67, 0x61, 0xd7, 0x1c, 0x3b, 0x43, 0x59, 0xdc, 0xe7, 0xda, 0x23, 0x4a, - 0xde, 0xe2, 0xf6, 0x18, 0xd7, 0xaf, 0x32, 0xfb, 0x5e, 0xe8, 0x4d, 0x4f, - 0xee, 0x84, 0xfe, 0x7b, 0x00, 0xf2, 0x29, 0x67, 0xa0, 0xfc, 0xce, 0x40, - 0x61, 0x9d, 0x89, 0x8b, 0x71, 0xa2, 0x53, 0xa2, 0x47, 0x13, 0x12, 0x39, - 0x4a, 0xff, 0x2b, 0x69, 0xde, 0x29, 0x02, 0x3b, 0xf8, 0xe2, 0xcd, 0x86, - 0xd8, 0x83, 0x19, 0x49, 0xc2, 0x87, 0xec, 0x33, 0x2b, 0x48, 0x8b, 0x92, - 0x4c, 0x9d, 0x46, 0x5f, 0xd1, 0x33, 0xa8, 0x8b, 0x76, 0x4d, 0xcb, 0x16, - 0x7e, 0x1d, 0xd2, 0xbc, 0xec, 0xef, 0x8f, 0xe6, 0xe5, 0xf5, 0xf1, 0x9b, - 0xa1, 0xd5, 0xf8, 0x0d, 0xdf, 0xbf, 0xad, 0xe3, 0x4e, 0x5f, 0xd2, 0xbe, - 0x0c, 0xe5, 0x82, 0xf6, 0x4c, 0xf9, 0x63, 0xd0, 0xdd, 0x5f, 0x82, 0xff, - 0xeb, 0x48, 0xae, 0x04, 0x9c, 0x9e, 0xf6, 0xe4, 0x69, 0xb7, 0xe0, 0x65, - 0x07, 0x3c, 0x79, 0xdd, 0x75, 0x0a, 0x79, 0xb1, 0xdf, 0xa6, 0x8e, 0xfb, - 0xb1, 0xfb, 0x21, 0xd9, 0xd3, 0x66, 0xef, 0xc9, 0x84, 0x0a, 0x5e, 0x8b, - 0xd3, 0x2c, 0x57, 0xa7, 0x0f, 0xc9, 0xbe, 0x1d, 0x2b, 0x66, 0x58, 0x32, - 0x57, 0x03, 0x0b, 0x26, 0xf2, 0x4a, 0x3f, 0xbd, 0xa1, 0x7c, 0xea, 0xfb, - 0xbb, 0x0f, 0xc9, 0xd6, 0x1d, 0xb6, 0x79, 0x29, 0x4c, 0x9c, 0x76, 0x08, - 0xf8, 0xdf, 0x4e, 0xe4, 0xc2, 0x8e, 0xb9, 0x5b, 0xec, 0x91, 0x4f, 0x0b, - 0xcf, 0x8c, 0x1d, 0xe9, 0x3a, 0xea, 0x24, 0x1e, 0x0c, 0xf5, 0x1c, 0x78, - 0x90, 0x3e, 0xdd, 0x19, 0xe6, 0x3d, 0x89, 0xed, 0x30, 0xf1, 0x1c, 0x97, - 0xae, 0x13, 0x96, 0x24, 0xc1, 0x97, 0x5e, 0xc5, 0x13, 0x9e, 0x5d, 0x25, - 0xa4, 0xe7, 0x28, 0x71, 0x93, 0xe2, 0x4d, 0x2f, 0x78, 0x93, 0x02, 0x6f, - 0xe0, 0x47, 0xf5, 0x99, 0x97, 0x90, 0x9e, 0x97, 0xe4, 0xe0, 0x9b, 0xe0, - 0x4d, 0x2f, 0x78, 0xd3, 0x73, 0xc6, 0x42, 0x7b, 0xf4, 0xb1, 0xdc, 0x85, - 0xb4, 0x59, 0x3e, 0x72, 0x55, 0x07, 0x9e, 0x1d, 0x49, 0x1e, 0x8d, 0x61, - 0x8c, 0x90, 0xec, 0xea, 0x2e, 0xc8, 0xf0, 0x0e, 0xf8, 0x63, 0xf1, 0x43, - 0x72, 0x01, 0xb6, 0xa7, 0x04, 0xbf, 0xe0, 0xe9, 0x41, 0x7b, 0x6c, 0x05, - 0xfa, 0xb3, 0x76, 0x97, 0x27, 0xaf, 0xec, 0xf8, 0x2b, 0x2f, 0x71, 0x95, - 0xbd, 0x47, 0x42, 0x03, 0x32, 0x5d, 0x52, 0x36, 0x21, 0x91, 0x0d, 0x2b, - 0x2c, 0x86, 0x39, 0x16, 0x60, 0x57, 0x78, 0x16, 0xee, 0x40, 0xbf, 0x7f, - 0x5a, 0x1e, 0x28, 0x4f, 0xe1, 0x07, 0x1f, 0x73, 0x86, 0x75, 0x0f, 0xc0, - 0x87, 0x7b, 0x48, 0xf6, 0xcf, 0x00, 0x2f, 0xa6, 0x41, 0xf7, 0x80, 0x03, - 0x1f, 0xee, 0x7c, 0xa3, 0xb4, 0xa2, 0x0c, 0xbc, 0x1d, 0xab, 0x6d, 0xf4, - 0xdd, 0x56, 0xb0, 0x0e, 0x83, 0xf2, 0x97, 0xb5, 0x01, 0xf9, 0x6a, 0xad, - 0x5f, 0xbe, 0x0c, 0x7b, 0xf2, 0x6c, 0xad, 0x13, 0x7b, 0x25, 0x81, 0x35, - 0x49, 0x63, 0x7d, 0x5c, 0xf9, 0x4a, 0x2d, 0x25, 0x5f, 0x02, 0xaf, 0x9e, - 0xc3, 0x6f, 0xb8, 0x94, 0x92, 0x5d, 0xa5, 0x7e, 0xbd, 0x46, 0x5c, 0x1f, - 0x07, 0xf4, 0x38, 0x98, 0xbb, 0xfd, 0x54, 0x01, 0xfb, 0x6f, 0xb1, 0xe6, - 0xbc, 0x55, 0x91, 0xc7, 0x1a, 0x19, 0x5f, 0x3e, 0xb5, 0x6a, 0x53, 0x0a, - 0x9e, 0xe9, 0xd8, 0x47, 0x26, 0xb0, 0x0e, 0x15, 0xec, 0xd3, 0x31, 0xc5, - 0xfb, 0x35, 0x7b, 0x53, 0xf1, 0xed, 0x4d, 0x30, 0xbf, 0xd9, 0xbc, 0x7c, - 0x47, 0xb2, 0x73, 0xd3, 0xb2, 0xef, 0xb8, 0x27, 0xbf, 0xe3, 0x7a, 0x90, - 0x63, 0xea, 0xdf, 0x01, 0xea, 0x75, 0x6b, 0x22, 0x6c, 0x28, 0xff, 0xc9, - 0xc7, 0x2a, 0xbd, 0xdb, 0xb1, 0x67, 0x53, 0x19, 0x63, 0x4a, 0x92, 0x73, - 0x53, 0xd2, 0x35, 0x07, 0x59, 0x70, 0xd9, 0xd7, 0x8a, 0x69, 0x5c, 0x26, - 0x0f, 0x1c, 0xc7, 0x1e, 0xcc, 0x89, 0x63, 0xbe, 0x25, 0x29, 0x8c, 0x7f, - 0x50, 0xba, 0xd1, 0xc6, 0x41, 0x9b, 0x4b, 0x6a, 0xec, 0x16, 0x8c, 0xdd, - 0x28, 0x87, 0xe3, 0x36, 0x64, 0x8d, 0x76, 0xfb, 0xff, 0x48, 0xb6, 0xc2, - 0xf4, 0x6f, 0x25, 0x7b, 0xea, 0x91, 0x98, 0x34, 0xf3, 0x19, 0xaa, 0x61, - 0x81, 0xe5, 0x5d, 0x48, 0x59, 0xee, 0xc0, 0x77, 0xfe, 0x89, 0x64, 0xcf, - 0x72, 0xec, 0xb7, 0x50, 0xfe, 0x8a, 0x64, 0x8f, 0xfd, 0x1c, 0xf9, 0x0b, - 0x48, 0xdf, 0x46, 0x3a, 0x26, 0x5d, 0xc7, 0x24, 0x94, 0x3d, 0xfb, 0x6d, - 0xe4, 0x23, 0x48, 0x0f, 0xa3, 0xde, 0x6d, 0xa0, 0xef, 0xaf, 0xd1, 0x5f, - 0x06, 0x7a, 0xee, 0xc3, 0x9a, 0x7e, 0x96, 0xb3, 0x8c, 0xef, 0x0e, 0x43, - 0xa7, 0xfd, 0x0f, 0x8f, 0xf1, 0x44, 0xf5, 0xbc, 0xc8, 0x3c, 0x75, 0x1b, - 0x9f, 0xa7, 0xc0, 0x93, 0x83, 0xc8, 0x7b, 0xf2, 0x90, 0x4b, 0x1b, 0x73, - 0x93, 0x8c, 0x9b, 0x05, 0xaf, 0x19, 0x58, 0xa2, 0x05, 0xfb, 0x60, 0x6a, - 0xe7, 0xe6, 0xfb, 0xe0, 0x48, 0xcf, 0x21, 0x69, 0xda, 0x11, 0xcc, 0x3f, - 0x98, 0xaf, 0x63, 0xfe, 0x48, 0xf1, 0xc1, 0x2e, 0x3c, 0x28, 0x9c, 0x87, - 0x93, 0x78, 0xdc, 0xe8, 0xd9, 0xf3, 0x00, 0xf6, 0x81, 0x71, 0x96, 0x79, - 0x7f, 0x1f, 0x18, 0x67, 0xa1, 0x1b, 0x16, 0xe0, 0x17, 0x2e, 0x74, 0x4a, - 0xe3, 0xb1, 0xb5, 0x7d, 0xd0, 0x70, 0xec, 0x57, 0xef, 0x83, 0xc6, 0xb3, - 0xa8, 0x77, 0x96, 0x3c, 0x43, 0x1f, 0xa7, 0xc8, 0xb3, 0x0e, 0xa4, 0x9f, - 0xc6, 0x5c, 0x49, 0x7b, 0x23, 0x68, 0xf7, 0xb1, 0xd0, 0xcd, 0x90, 0xf7, - 0xfb, 0x77, 0x1c, 0xd4, 0xe5, 0xff, 0xd9, 0x1b, 0x89, 0xdb, 0x65, 0x09, - 0x91, 0xa7, 0xa8, 0x5b, 0x21, 0x0f, 0x6f, 0x69, 0x92, 0xe6, 0x03, 0xd2, - 0x45, 0xfe, 0x55, 0x76, 0x23, 0x5f, 0xf0, 0xa2, 0x4e, 0x8b, 0xe6, 0x27, - 0xb0, 0xd1, 0x00, 0xcb, 0x5f, 0x83, 0xcc, 0x10, 0xa3, 0xbe, 0x21, 0xfb, - 0x66, 0x3c, 0x19, 0x77, 0x39, 0xff, 0xef, 0x63, 0xfe, 0x99, 0x1d, 0x71, - 0x59, 0xb1, 0xe2, 0xe0, 0xc9, 0x22, 0x74, 0xfb, 0x05, 0xf1, 0xf9, 0xc0, - 0x33, 0x89, 0x5d, 0xe2, 0x24, 0x86, 0xc5, 0x49, 0xbd, 0x09, 0x3e, 0x0c, - 0x43, 0xf6, 0x73, 0x35, 0xca, 0xce, 0xab, 0x32, 0x04, 0x99, 0xf8, 0x9e, - 0x6b, 0xa7, 0x80, 0x7f, 0xa0, 0x2f, 0x28, 0x17, 0x94, 0x89, 0x56, 0xa5, - 0x93, 0x16, 0x5c, 0xfb, 0x89, 0x8a, 0x5c, 0x27, 0x0b, 0xed, 0xa4, 0x1d, - 0xef, 0x8e, 0x29, 0x7b, 0x91, 0x9a, 0x30, 0xba, 0xa1, 0xa3, 0x53, 0x62, - 0xf6, 0x7c, 0xb1, 0x31, 0xb8, 0xbf, 0x92, 0x9f, 0x0b, 0xc9, 0x54, 0x0f, - 0xd7, 0x8a, 0xfd, 0x22, 0x5f, 0x29, 0x78, 0x11, 0xe7, 0x2d, 0xef, 0x64, - 0x87, 0x25, 0x9f, 0xec, 0x59, 0x95, 0xcb, 0xb2, 0x88, 0xbf, 0x2f, 0x86, - 0xd4, 0x7a, 0x04, 0x74, 0x07, 0x73, 0x09, 0xde, 0xf5, 0xd7, 0xbd, 0xe3, - 0x5c, 0x28, 0xeb, 0xab, 0x7b, 0xc7, 0xba, 0x9c, 0xd6, 0x9f, 0x41, 0x9e, - 0xec, 0x27, 0x8a, 0xf2, 0x3a, 0x64, 0x0f, 0x3c, 0x3c, 0xcb, 0x94, 0x3c, - 0x9c, 0x82, 0xdc, 0xbf, 0x26, 0xbb, 0xe6, 0xb8, 0x67, 0x5e, 0xc3, 0x5c, - 0x95, 0x2e, 0x81, 0x8e, 0x60, 0x7f, 0x9e, 0x4c, 0xbb, 0xdd, 0xa9, 0x53, - 0x72, 0x5d, 0x62, 0x12, 0x7e, 0xe6, 0x84, 0xe9, 0xc9, 0xb2, 0x5b, 0x90, - 0xe5, 0x41, 0xb4, 0xa9, 0x7c, 0x1a, 0xbf, 0x79, 0x3d, 0xb7, 0x47, 0xc0, - 0x77, 0xdb, 0x2a, 0x1b, 0x9f, 0x01, 0xdf, 0x1f, 0x92, 0xe4, 0xb1, 0x55, - 0x5d, 0x03, 0xb9, 0xf3, 0x75, 0x4d, 0xf2, 0xac, 0x29, 0x95, 0x92, 0x23, - 0x1f, 0xa3, 0x0e, 0x29, 0x71, 0x5e, 0xd0, 0x31, 0x3c, 0xdf, 0x2f, 0x41, - 0xcf, 0x94, 0xa0, 0x53, 0xa0, 0x43, 0xbe, 0x8c, 0xf2, 0x2f, 0xa1, 0xce, - 0x73, 0xf0, 0x99, 0x9e, 0x05, 0xde, 0x3b, 0x07, 0x1c, 0xf1, 0x4c, 0x29, - 0xa3, 0xfd, 0x57, 0x35, 0x5f, 0xd8, 0x2c, 0xe5, 0xef, 0x48, 0xa5, 0x4c, - 0x7e, 0xfc, 0x44, 0xad, 0x6d, 0xd6, 0xdd, 0x46, 0x6c, 0x05, 0xca, 0x44, - 0xca, 0xe5, 0x80, 0x27, 0xd4, 0x7d, 0x3c, 0x1b, 0x0a, 0x74, 0x65, 0xcb, - 0x06, 0x5d, 0x29, 0xf2, 0x62, 0xd5, 0xc7, 0x90, 0xc4, 0xc4, 0xc5, 0x19, - 0x6b, 0xf5, 0x0c, 0xb5, 0x08, 0xbb, 0x79, 0x1e, 0xbe, 0x45, 0x2c, 0xfd, - 0x2d, 0x89, 0x9d, 0xf0, 0xbc, 0x1f, 0xc0, 0x6e, 0x16, 0xb0, 0x26, 0x46, - 0x08, 0xe5, 0x4b, 0x7c, 0x47, 0xb9, 0xa7, 0x6c, 0x87, 0x78, 0x96, 0x22, - 0x2f, 0xa3, 0xac, 0xa2, 0x7c, 0xae, 0x6f, 0x83, 0x1e, 0x4d, 0x9f, 0x2a, - 0x63, 0xbd, 0x46, 0xc9, 0x8d, 0xa7, 0xe0, 0xd7, 0xf4, 0x99, 0x8d, 0x68, - 0x5f, 0x5e, 0x62, 0x1b, 0x7b, 0x90, 0x57, 0xb9, 0x5e, 0x5e, 0x62, 0x79, - 0xa7, 0x5c, 0x80, 0xff, 0x49, 0x1a, 0x2a, 0xf3, 0x69, 0xf1, 0xe3, 0xc5, - 0xd4, 0x57, 0xa4, 0x15, 0x79, 0xf0, 0x2b, 0x5b, 0xa2, 0x9d, 0x8d, 0x48, - 0x21, 0x41, 0x5e, 0x27, 0xe4, 0xfc, 0xcc, 0x1f, 0x37, 0x31, 0x1e, 0x9b, - 0x75, 0xf8, 0x1c, 0xc4, 0x37, 0xcc, 0x77, 0x10, 0xdf, 0x60, 0x4c, 0x23, - 0x02, 0x5b, 0xa6, 0xe2, 0x1c, 0x48, 0xad, 0x3a, 0x9f, 0x97, 0xef, 0x7d, - 0x6c, 0xb4, 0x86, 0x19, 0x89, 0x21, 0x39, 0x5f, 0xbb, 0xb0, 0x02, 0xfd, - 0xd1, 0x9e, 0x7e, 0x49, 0xee, 0x5e, 0xf0, 0xe7, 0x67, 0x9c, 0x12, 0xde, - 0xe3, 0x91, 0x4b, 0xf3, 0xb6, 0x7b, 0x51, 0x78, 0x06, 0xe2, 0x62, 0xbd, - 0xfe, 0xa0, 0x09, 0xfa, 0x6b, 0x30, 0x63, 0x7c, 0xbb, 0xc9, 0xc7, 0x67, - 0x11, 0x99, 0x9a, 0xe1, 0x99, 0x2b, 0x74, 0x1b, 0x70, 0xe3, 0xef, 0x45, - 0xf0, 0x5c, 0x65, 0x1e, 0x7e, 0xa8, 0xef, 0xc3, 0xe2, 0xd9, 0xef, 0x8f, - 0x3c, 0x37, 0x16, 0x38, 0xf7, 0x90, 0xdc, 0x0d, 0x74, 0x22, 0xe8, 0xbf, - 0x4b, 0x8f, 0xd5, 0x75, 0x2a, 0xc5, 0xf8, 0xb5, 0x24, 0xa1, 0x2f, 0xb2, - 0xf0, 0x1f, 0x73, 0xf1, 0x4e, 0x8d, 0xc7, 0xf9, 0x6e, 0x23, 0xde, 0x0c, - 0xfc, 0xba, 0x94, 0x7c, 0xbe, 0x14, 0x60, 0xbd, 0x14, 0x6c, 0xac, 0x44, - 0x46, 0x7a, 0x3d, 0xf9, 0x81, 0x4b, 0x7e, 0xf5, 0x23, 0xef, 0xca, 0x91, - 0xda, 0x2f, 0x3b, 0x5b, 0xad, 0xff, 0x6b, 0x01, 0x8d, 0xfc, 0x81, 0x3e, - 0xe0, 0x23, 0xd2, 0x6e, 0xc0, 0x9e, 0x17, 0x81, 0xbb, 0x8c, 0x33, 0x9d, - 0xea, 0x9d, 0x01, 0x6c, 0x50, 0x99, 0x81, 0x6e, 0x3c, 0xc3, 0xf3, 0x66, - 0xe8, 0xb6, 0x33, 0x51, 0x29, 0xce, 0x52, 0x2e, 0xa5, 0xdd, 0xc0, 0x7a, - 0xb1, 0x7e, 0x65, 0xa6, 0x13, 0x69, 0x0b, 0x52, 0x4b, 0xf5, 0x53, 0x99, - 0x71, 0x54, 0xfb, 0xca, 0x4c, 0x4a, 0xb5, 0xab, 0xcc, 0xf4, 0x23, 0x75, - 0xa5, 0xe1, 0x0c, 0x9c, 0xa5, 0x33, 0x3d, 0x32, 0x75, 0x12, 0xf6, 0x65, - 0xc0, 0x50, 0x77, 0x35, 0x26, 0x60, 0x7f, 0x22, 0xf0, 0xac, 0x2e, 0x9a, - 0x83, 0xc0, 0x58, 0x37, 0x01, 0x83, 0xdc, 0x24, 0xce, 0x09, 0xce, 0x9f, - 0xba, 0xf7, 0x3c, 0x63, 0x5e, 0x89, 0x4f, 0x48, 0x46, 0xf6, 0xcf, 0x36, - 0x62, 0xbf, 0x46, 0xcc, 0xa2, 0x74, 0x9b, 0xc3, 0xc8, 0xe7, 0xcb, 0xe4, - 0xdb, 0xbd, 0xca, 0x5f, 0xcb, 0xba, 0x37, 0x34, 0x4b, 0x73, 0x1a, 0x63, - 0xbc, 0x93, 0xf6, 0xbd, 0x90, 0x3f, 0x47, 0xf7, 0x91, 0x06, 0x3d, 0xf5, - 0xfc, 0xe0, 0x39, 0x73, 0xe6, 0x57, 0x9c, 0x33, 0x53, 0xae, 0xc9, 0xdf, - 0x7b, 0xe5, 0xbc, 0x93, 0x96, 0x97, 0x9d, 0x94, 0x5c, 0x70, 0x76, 0xca, - 0x37, 0x61, 0xa7, 0x5f, 0x72, 0xce, 0x34, 0x11, 0x0b, 0x54, 0xd4, 0xd9, - 0x5d, 0xb0, 0x56, 0x8e, 0x8e, 0x9d, 0xff, 0x50, 0x96, 0x67, 0x88, 0x9d, - 0xbd, 0xdb, 0xf6, 0xb9, 0x05, 0xda, 0x2d, 0xd0, 0x40, 0xac, 0x56, 0x80, - 0xfd, 0x3b, 0x24, 0xc3, 0x2e, 0xed, 0x9e, 0xb2, 0x51, 0x89, 0x61, 0x7f, - 0x3f, 0xbb, 0x79, 0xe8, 0xd5, 0xf3, 0xb3, 0xd8, 0x4f, 0x42, 0xf9, 0xc7, - 0x73, 0x99, 0xeb, 0xee, 0xc8, 0xe3, 0x25, 0xce, 0xb3, 0xb8, 0xbd, 0x59, - 0xc2, 0x32, 0xa2, 0xf0, 0x42, 0xab, 0xbc, 0xb8, 0xb4, 0x45, 0x0c, 0x58, - 0x28, 0xe3, 0xda, 0xa8, 0xba, 0xe5, 0x42, 0x9f, 0x5b, 0xda, 0x78, 0xb6, - 0xf6, 0x87, 0xe0, 0x0d, 0xfd, 0x7f, 0xcc, 0xad, 0x8d, 0x33, 0x09, 0xf2, - 0xfd, 0xd8, 0x5f, 0x7c, 0x0e, 0x49, 0xce, 0x89, 0xe3, 0x99, 0x29, 0xf7, - 0x1c, 0x63, 0x63, 0x61, 0xf1, 0x31, 0xf7, 0x21, 0xf5, 0xbe, 0xd1, 0xb9, - 0x15, 0xb8, 0x8e, 0xf2, 0x8a, 0x74, 0xd9, 0x1f, 0x37, 0x07, 0x1c, 0x97, - 0xef, 0xe7, 0x1d, 0x1b, 0x3b, 0x55, 0xc0, 0x5e, 0x98, 0x50, 0xf5, 0x07, - 0xe4, 0xa5, 0x99, 0x52, 0xb3, 0xbf, 0x3f, 0x06, 0xf5, 0x33, 0xdf, 0xd3, - 0xa7, 0x62, 0x8c, 0xe4, 0x99, 0xd1, 0x69, 0xe7, 0xa2, 0xde, 0x3f, 0x12, - 0xba, 0xb3, 0x17, 0x38, 0xf4, 0x68, 0x03, 0xe6, 0x62, 0x5b, 0x56, 0xc8, - 0xe8, 0x30, 0x80, 0xe3, 0x87, 0x95, 0xcd, 0xed, 0x55, 0x31, 0xe8, 0x53, - 0xa9, 0x56, 0xa9, 0x98, 0x8e, 0xba, 0x93, 0xb7, 0x62, 0xee, 0x20, 0xd6, - 0xc7, 0xaf, 0x09, 0x65, 0xdd, 0x48, 0x1b, 0x91, 0xbe, 0x5f, 0x8a, 0xc7, - 0xcf, 0xe8, 0xf1, 0xa2, 0x1b, 0xf2, 0x1f, 0xd1, 0xe9, 0x67, 0xb5, 0x3f, - 0xc5, 0x71, 0xa2, 0xe2, 0x7c, 0xa1, 0x45, 0xba, 0x8f, 0x9a, 0xc0, 0xb6, - 0x09, 0x60, 0xdd, 0x4e, 0x49, 0x1d, 0xb5, 0xe4, 0xda, 0xa3, 0x41, 0x9c, - 0xe9, 0x2b, 0xa3, 0x49, 0x15, 0xd7, 0xfc, 0xf2, 0xa8, 0x53, 0x56, 0xe7, - 0xed, 0xfa, 0xee, 0xe0, 0x8a, 0xbe, 0x53, 0xf8, 0xca, 0x68, 0xaf, 0x4a, - 0xbf, 0x3d, 0x9a, 0x52, 0xe9, 0xab, 0xa3, 0xd7, 0x56, 0x7d, 0xff, 0xa8, - 0xb8, 0x98, 0x92, 0xcf, 0x95, 0x88, 0x2f, 0x07, 0x80, 0x1d, 0x5d, 0xe8, - 0x99, 0x7e, 0xe8, 0x99, 0x14, 0xf4, 0xcc, 0x20, 0xf5, 0x0c, 0xf4, 0xf6, - 0xab, 0xd0, 0xdb, 0xae, 0x7c, 0x0f, 0xf2, 0xfa, 0x8c, 0xdb, 0x08, 0x5c, - 0xe8, 0x79, 0xfe, 0x5c, 0xed, 0x27, 0x56, 0xb0, 0xbe, 0x95, 0xd3, 0x12, - 0x6b, 0x83, 0x0e, 0xda, 0xb1, 0xd0, 0x20, 0x8b, 0x71, 0xcf, 0x9b, 0x73, - 0x1d, 0xb9, 0x84, 0xfa, 0x59, 0x87, 0xfb, 0xf8, 0x6f, 0x9a, 0xe9, 0x8f, - 0x5d, 0x9a, 0xd9, 0x09, 0x9d, 0x44, 0x79, 0x8f, 0x49, 0x65, 0x3c, 0x21, - 0x4b, 0xf0, 0xcf, 0xd6, 0xea, 0xa4, 0xf0, 0xcc, 0xfd, 0xff, 0x13, 0xd4, - 0x4d, 0xc1, 0x3e, 0x98, 0xb2, 0xdc, 0x6b, 0xc9, 0xa9, 0x5e, 0x7b, 0xd0, - 0x32, 0xa8, 0xbb, 0x2c, 0x29, 0xc3, 0xbf, 0xaf, 0x94, 0x58, 0x9f, 0xf5, - 0xb0, 0x3f, 0x4b, 0x7e, 0xbb, 0xe9, 0x52, 0xa0, 0x27, 0x06, 0x18, 0x7b, - 0x8c, 0xe4, 0x7a, 0x7d, 0x1b, 0x60, 0x18, 0x8d, 0x90, 0x03, 0x17, 0xfc, - 0x1f, 0x47, 0xf9, 0x00, 0xef, 0x9a, 0xa0, 0x8c, 0x58, 0x28, 0xb6, 0x85, - 0x18, 0x31, 0xe7, 0x8e, 0xa3, 0x8c, 0x6d, 0xec, 0x44, 0x12, 0xe5, 0x63, - 0x92, 0x4c, 0xe4, 0xd5, 0xbd, 0xb7, 0x0e, 0x94, 0xb1, 0x8f, 0xb0, 0x8e, - 0xc1, 0x74, 0x6c, 0xf1, 0xcf, 0x7d, 0x83, 0xf2, 0x3e, 0x15, 0x0f, 0xc8, - 0x98, 0x2e, 0xf6, 0x03, 0xcb, 0x92, 0x26, 0xdb, 0xe5, 0x5c, 0x57, 0xe9, - 0xc2, 0x7b, 0xaa, 0x3c, 0xb7, 0x8b, 0xc9, 0xdd, 0xd5, 0x16, 0xc9, 0x55, - 0x1b, 0xae, 0xa0, 0xff, 0x83, 0x3d, 0x79, 0x3e, 0x61, 0x0a, 0xef, 0x60, - 0xf8, 0xfb, 0x3c, 0xb2, 0x93, 0x7b, 0x02, 0x7c, 0x87, 0xfd, 0x7d, 0x0e, - 0xf3, 0x7d, 0x16, 0xf6, 0xf7, 0x1c, 0xec, 0xef, 0x33, 0xa5, 0x35, 0xfd, - 0xe1, 0xdb, 0x5d, 0xea, 0x80, 0xa7, 0xb0, 0x66, 0x63, 0xc0, 0xfd, 0xbb, - 0xe1, 0x0f, 0x8c, 0x00, 0xfb, 0x0f, 0x61, 0xfd, 0xd2, 0x58, 0xbb, 0x71, - 0xde, 0x55, 0xc2, 0x3a, 0x0e, 0xaa, 0xb3, 0xe5, 0x59, 0x75, 0xdf, 0xe3, - 0x87, 0xca, 0xf6, 0x3e, 0x56, 0x32, 0x60, 0x1f, 0x0a, 0xde, 0x76, 0xc7, - 0x06, 0xfe, 0x5b, 0xdd, 0xcf, 0x83, 0x2f, 0x42, 0xaf, 0xfc, 0x1d, 0xe8, - 0x7a, 0x76, 0x96, 0xf6, 0x1c, 0x75, 0x7c, 0xbc, 0xed, 0x32, 0xbe, 0x85, - 0xfd, 0x7c, 0xe4, 0xbc, 0xac, 0x00, 0x77, 0x64, 0x28, 0xc7, 0xf0, 0x1f, - 0xec, 0x67, 0xca, 0xd2, 0x43, 0x1d, 0x58, 0xe6, 0x5e, 0x19, 0x38, 0x96, - 0x00, 0xd6, 0x03, 0x92, 0x57, 0x67, 0xa9, 0x78, 0x3e, 0xbb, 0x55, 0x0c, - 0xe2, 0x3d, 0xf7, 0x2a, 0x94, 0x51, 0x6f, 0x04, 0x18, 0x69, 0x65, 0xb0, - 0x5d, 0x32, 0x3b, 0xda, 0x95, 0xee, 0xb0, 0xdd, 0x97, 0x31, 0xee, 0x2e, - 0x69, 0x04, 0x86, 0x2b, 0x60, 0x8c, 0x83, 0xf2, 0x37, 0x2e, 0xe3, 0x52, - 0xbe, 0xef, 0x07, 0x5a, 0x62, 0xe0, 0x59, 0xd3, 0x3e, 0xc7, 0x8c, 0xed, - 0xaa, 0xb1, 0xff, 0x98, 0xc2, 0x58, 0x39, 0x61, 0xff, 0xb0, 0x13, 0x18, - 0x33, 0x79, 0x8c, 0xb2, 0xdf, 0x87, 0x75, 0xfb, 0x2d, 0x60, 0x20, 0x72, - 0xf5, 0x5b, 0x5b, 0xfc, 0xfd, 0x42, 0xfa, 0x57, 0x88, 0x27, 0x18, 0xf7, - 0xf7, 0xfd, 0xf2, 0x55, 0xda, 0x06, 0x40, 0xef, 0x73, 0x5b, 0x82, 0xf3, - 0xe3, 0xae, 0x63, 0xbe, 0xbd, 0xee, 0x3a, 0x8b, 0x56, 0x73, 0xd2, 0xc1, - 0x93, 0x68, 0x43, 0xae, 0x95, 0xdb, 0x23, 0x7e, 0x3f, 0xc6, 0x82, 0x09, - 0x59, 0xa5, 0x1e, 0xe8, 0x80, 0x9c, 0x33, 0x4f, 0x9d, 0x42, 0x9d, 0x40, - 0x59, 0x70, 0xa4, 0x58, 0x83, 0x4e, 0x68, 0xed, 0x94, 0x32, 0x79, 0xb6, - 0x40, 0x3d, 0xf1, 0x43, 0x99, 0xde, 0xa0, 0x2b, 0x87, 0x24, 0xf0, 0x6b, - 0x5b, 0x24, 0x9a, 0x76, 0xcc, 0x7b, 0xd4, 0x1c, 0x7d, 0x7d, 0xb9, 0x9f, - 0xf8, 0x73, 0x36, 0x63, 0xb7, 0x8b, 0xc6, 0x9e, 0x0a, 0x3f, 0x7d, 0x1f, - 0x73, 0x65, 0x1f, 0x8a, 0x4f, 0x83, 0x43, 0xbe, 0x2f, 0xa0, 0xe2, 0x7c, - 0xc0, 0xc1, 0x89, 0xbf, 0x83, 0xae, 0xcd, 0x11, 0x97, 0x80, 0xcf, 0x5d, - 0x73, 0x94, 0xa3, 0xed, 0xd4, 0x65, 0xc0, 0x79, 0x29, 0xea, 0x6b, 0x59, - 0x3a, 0x06, 0xcc, 0x65, 0xdc, 0x2a, 0x79, 0xca, 0x2b, 0xef, 0x48, 0x2c, - 0x19, 0x32, 0x3d, 0xdf, 0x2a, 0xdd, 0x0b, 0x8c, 0xa9, 0x7e, 0xb3, 0x59, - 0x5a, 0x19, 0x57, 0xa5, 0x0d, 0x1a, 0x90, 0x1c, 0xca, 0xbb, 0x16, 0xc2, - 0x2a, 0x06, 0x56, 0x36, 0xc8, 0xa3, 0x7e, 0xe8, 0x03, 0x3b, 0xb5, 0x62, - 0x7c, 0xb4, 0xc9, 0xc7, 0x90, 0x90, 0xa5, 0x12, 0x64, 0xac, 0x04, 0x19, - 0x2b, 0x41, 0xc6, 0x4a, 0x90, 0x31, 0x60, 0xbf, 0x67, 0xb1, 0xff, 0xce, - 0x95, 0x06, 0xb5, 0x5d, 0xdf, 0xa3, 0xec, 0xfa, 0xe1, 0xd2, 0xab, 0x1e, - 0xd3, 0x2f, 0x29, 0xdf, 0xb4, 0x1f, 0x32, 0x48, 0x5f, 0x34, 0xf0, 0x51, - 0x5f, 0x95, 0xa7, 0x66, 0x5f, 0x93, 0x53, 0xb3, 0x6b, 0x38, 0x70, 0xaa, - 0xe4, 0xc9, 0xcb, 0x2e, 0xfc, 0xcf, 0x45, 0x62, 0xaa, 0x4c, 0x5b, 0xa3, - 0xc2, 0x56, 0x87, 0x24, 0xaf, 0x70, 0xb2, 0xb2, 0x23, 0xc0, 0x57, 0x0a, - 0x17, 0x72, 0x6f, 0x4a, 0xfb, 0x8e, 0xd7, 0xe5, 0x1c, 0xec, 0xf8, 0x52, - 0xed, 0x0d, 0x79, 0x4e, 0xe1, 0x71, 0xf2, 0xe1, 0x7d, 0xf2, 0xb7, 0xa6, - 0x7f, 0x86, 0x7f, 0x0a, 0x58, 0x63, 0xa9, 0x97, 0xba, 0x23, 0x02, 0x5b, - 0x60, 0x17, 0xba, 0xb0, 0xaf, 0x0f, 0x18, 0xef, 0x02, 0xa6, 0xe1, 0xfb, - 0xad, 0xf2, 0xe2, 0x6c, 0xa1, 0x4e, 0x26, 0xa8, 0x1f, 0xec, 0x23, 0x62, - 0xd0, 0x4e, 0xd1, 0x6e, 0x72, 0xbe, 0xb4, 0x53, 0x6d, 0x2d, 0xbc, 0x3f, - 0x56, 0x39, 0x7e, 0xc3, 0x16, 0xc6, 0x18, 0xe3, 0x0e, 0x79, 0xfa, 0xba, - 0x1c, 0xa8, 0xb2, 0xec, 0x35, 0xac, 0x0f, 0xd3, 0x37, 0xbd, 0xbb, 0xe3, - 0x1c, 0x8f, 0xfd, 0x02, 0x37, 0x75, 0x60, 0xae, 0xa5, 0xcf, 0x6a, 0xcc, - 0xdd, 0xaf, 0x70, 0xf4, 0xe5, 0x78, 0x99, 0x7c, 0x72, 0xc1, 0xa7, 0xd7, - 0x55, 0x0c, 0x70, 0x93, 0xd8, 0xf0, 0x13, 0xd8, 0x57, 0x85, 0x8b, 0xc2, - 0x38, 0x25, 0x63, 0xb8, 0x8c, 0x0f, 0xd7, 0x6b, 0x0c, 0x75, 0x57, 0x40, - 0xee, 0x82, 0x7e, 0xb9, 0x1b, 0xfa, 0xe5, 0x9e, 0xcb, 0xee, 0x5f, 0x07, - 0x71, 0xff, 0xee, 0x42, 0xd8, 0xe8, 0x94, 0xb1, 0x6a, 0x7d, 0x5b, 0xc6, - 0x6e, 0x37, 0x8b, 0xd5, 0x32, 0x8e, 0x9b, 0xda, 0x10, 0xff, 0xa3, 0x6c, - 0x78, 0xf2, 0x92, 0xcb, 0xb8, 0x5b, 0x70, 0x67, 0x7f, 0x33, 0xfc, 0x65, - 0xb5, 0x04, 0x71, 0xe6, 0x48, 0xfa, 0xa2, 0xf0, 0xee, 0x7e, 0x71, 0x86, - 0x78, 0x20, 0xae, 0xee, 0xd9, 0x19, 0x2a, 0xce, 0xe7, 0xb7, 0x2d, 0xce, - 0xa8, 0x73, 0xa5, 0x02, 0xe3, 0xd5, 0xe6, 0x4e, 0xdb, 0x1c, 0x0b, 0xfb, - 0xf7, 0x65, 0xb8, 0x97, 0x7d, 0x5d, 0x06, 0x59, 0xac, 0xad, 0xdd, 0xb1, - 0x1c, 0x52, 0xfa, 0xe2, 0x22, 0xf6, 0x00, 0xd7, 0x0b, 0xfe, 0x02, 0xf6, - 0xc9, 0x14, 0xf4, 0x53, 0x5e, 0xf5, 0x17, 0xa3, 0x5c, 0x64, 0xb2, 0x61, - 0x43, 0xa2, 0x27, 0xe8, 0x0b, 0xf9, 0xb1, 0x96, 0x5c, 0xd8, 0x56, 0xfa, - 0x1b, 0xb4, 0x03, 0x9f, 0x71, 0x7f, 0x5a, 0x13, 0x8d, 0xe9, 0x06, 0xd8, - 0x55, 0xac, 0x5f, 0x8d, 0x31, 0x01, 0xec, 0xdd, 0xe5, 0xef, 0xca, 0xfe, - 0xf9, 0xe1, 0x16, 0x5f, 0xfe, 0x19, 0x3b, 0xe6, 0xfc, 0x02, 0x1a, 0xd6, - 0xf7, 0x6d, 0x9c, 0x90, 0x58, 0x33, 0x6c, 0xda, 0x87, 0xe1, 0x67, 0xec, - 0x82, 0xac, 0xac, 0xc4, 0xd9, 0xaf, 0xbf, 0x67, 0xa6, 0x4b, 0xec, 0xfb, - 0xbb, 0x32, 0x3c, 0x7f, 0xb6, 0x85, 0xb6, 0x64, 0x19, 0x7a, 0xe0, 0xbc, - 0x49, 0x1b, 0x3a, 0x0e, 0x1b, 0xd7, 0x21, 0xdf, 0x9f, 0xa7, 0x7d, 0x4c, - 0x9a, 0xa7, 0xa4, 0x2f, 0x71, 0x0a, 0x34, 0x7d, 0xde, 0x8d, 0xd0, 0x47, - 0xf3, 0x86, 0x50, 0xf6, 0x4d, 0x49, 0x9a, 0x5d, 0x21, 0x3e, 0xf7, 0x99, - 0x8f, 0x03, 0xc3, 0x66, 0xcc, 0xa4, 0x79, 0x5d, 0x88, 0x72, 0x04, 0x9f, - 0x7b, 0x79, 0x8d, 0xce, 0x37, 0xe7, 0x95, 0x9f, 0xa4, 0xf4, 0xcc, 0xb2, - 0xcb, 0xf1, 0x40, 0xb7, 0xd2, 0x59, 0xd7, 0x41, 0x9f, 0xc4, 0xf4, 0x99, - 0x1b, 0xda, 0x10, 0xdb, 0xb8, 0x11, 0x9d, 0x7f, 0x44, 0xb2, 0x27, 0xe3, - 0xd0, 0x67, 0xec, 0x2b, 0xf0, 0x1d, 0x68, 0x23, 0x03, 0xbc, 0x4d, 0x7b, - 0x77, 0x2b, 0xec, 0xde, 0x35, 0x8a, 0x9e, 0x11, 0xb7, 0x5f, 0xa6, 0x8e, - 0x73, 0xec, 0x5e, 0xe8, 0xf2, 0x84, 0x92, 0xdb, 0x62, 0xe9, 0x7c, 0x22, - 0x06, 0x9d, 0x1c, 0xdb, 0x41, 0x7e, 0x7e, 0x50, 0xee, 0x70, 0xc6, 0xe5, - 0x4e, 0xc8, 0xce, 0x90, 0xe3, 0xca, 0x30, 0xd6, 0x62, 0x97, 0x03, 0xbb, - 0xa3, 0x30, 0x74, 0x23, 0xfc, 0x2e, 0x8e, 0xdd, 0xa1, 0xef, 0x5c, 0xf8, - 0xf8, 0xf1, 0xcf, 0x6a, 0x3e, 0x8f, 0xb2, 0xf3, 0x2f, 0x2b, 0xde, 0x8c, - 0xb8, 0x37, 0x69, 0x3b, 0xdb, 0x2a, 0x39, 0x55, 0xef, 0x26, 0x65, 0x8f, - 0x8b, 0x4b, 0xf7, 0x22, 0x85, 0x6d, 0x5e, 0x82, 0xbe, 0x01, 0xe6, 0x2e, - 0x56, 0x77, 0x22, 0x0f, 0x1b, 0xba, 0x94, 0x46, 0xfa, 0x41, 0xa4, 0xac, - 0xfb, 0xb9, 0x16, 0x3f, 0x96, 0x5b, 0x7f, 0x87, 0xcc, 0xbf, 0x7f, 0xfa, - 0x61, 0x85, 0x4b, 0x2f, 0xaa, 0xfb, 0x87, 0x06, 0xb0, 0x4e, 0x16, 0x7a, - 0xa5, 0x05, 0x18, 0x68, 0xe6, 0x84, 0x9d, 0x1a, 0x0e, 0xdd, 0x26, 0x1f, - 0x81, 0x2f, 0x5f, 0x71, 0xb9, 0x96, 0x3b, 0xe5, 0x13, 0xb7, 0x50, 0x46, - 0x6e, 0x93, 0x7d, 0xb7, 0x84, 0x64, 0x5f, 0xbf, 0x9d, 0x21, 0xdd, 0xd7, - 0xbe, 0x3f, 0xf0, 0xa7, 0xbb, 0x47, 0x92, 0xa1, 0x01, 0x79, 0x1c, 0x32, - 0x56, 0x80, 0x7c, 0x0d, 0xd7, 0xc8, 0x73, 0xea, 0x7b, 0xea, 0xf9, 0x14, - 0xb0, 0x72, 0x80, 0xfd, 0x1c, 0x99, 0xa9, 0x35, 0x88, 0x75, 0x15, 0xe3, - 0xc9, 0x96, 0x7f, 0xae, 0x71, 0x15, 0x65, 0x02, 0x3e, 0xc8, 0x55, 0xfe, - 0xfe, 0x54, 0xf7, 0xfe, 0xae, 0xf2, 0xed, 0x0a, 0xfc, 0x5f, 0x8f, 0x38, - 0xcf, 0xbf, 0x5f, 0x70, 0x51, 0xeb, 0xd2, 0xe4, 0xd6, 0x55, 0x7c, 0xd7, - 0x4a, 0xff, 0xe1, 0xeb, 0x2d, 0x6b, 0xdf, 0x2d, 0x6c, 0x94, 0xc5, 0x20, - 0xee, 0x56, 0xc6, 0x9c, 0x69, 0xd3, 0x6d, 0x93, 0xba, 0xb0, 0xcd, 0xd9, - 0x23, 0x7f, 0x09, 0xfb, 0xfe, 0xd5, 0x55, 0xfb, 0xbe, 0x17, 0xfc, 0xd8, - 0x88, 0x01, 0x1c, 0xf3, 0x2e, 0xcc, 0x65, 0x04, 0xeb, 0x79, 0x27, 0x7e, - 0x77, 0x94, 0xd6, 0xc5, 0xf1, 0x66, 0x0b, 0xc0, 0x93, 0x0d, 0x0e, 0xfb, - 0x5b, 0x17, 0xcf, 0x2b, 0xe4, 0x65, 0x35, 0x56, 0x38, 0x78, 0x49, 0x68, - 0xf7, 0xde, 0x92, 0x68, 0x8f, 0xf3, 0x56, 0x57, 0xc8, 0x79, 0xde, 0x08, - 0xf1, 0xec, 0xdb, 0x95, 0xd3, 0x35, 0xe2, 0xb0, 0x0b, 0x62, 0x9c, 0x25, - 0x06, 0x7b, 0x45, 0xc5, 0xa0, 0x2a, 0xa5, 0x6f, 0x23, 0x45, 0x7d, 0xe8, - 0xc7, 0xb0, 0x1f, 0xa7, 0x50, 0x58, 0x85, 0x7a, 0xf6, 0x4e, 0xac, 0xc3, - 0x14, 0x7e, 0x5d, 0x3b, 0xae, 0xc3, 0xfe, 0xa5, 0x9c, 0x32, 0xf6, 0xd5, - 0x63, 0xee, 0x08, 0xf1, 0xdd, 0x66, 0x71, 0xb0, 0xef, 0x48, 0x64, 0x0e, - 0xb6, 0xce, 0xa0, 0x7e, 0xe0, 0x3c, 0x68, 0x27, 0x4d, 0x59, 0x3c, 0xce, - 0xbd, 0xbe, 0x59, 0xfd, 0xa0, 0x6e, 0x30, 0x17, 0x65, 0x37, 0x32, 0x79, - 0xc6, 0x38, 0x4b, 0x5c, 0x03, 0x17, 0x6b, 0xe0, 0xc9, 0x09, 0xb7, 0x0d, - 0x7a, 0x3b, 0x2e, 0xe1, 0x13, 0x9e, 0x0c, 0x29, 0xec, 0xda, 0x07, 0xcc, - 0xb5, 0x55, 0xe3, 0x86, 0xb8, 0x44, 0x4e, 0x74, 0x4a, 0x23, 0x70, 0x75, - 0xc3, 0x51, 0xda, 0xc8, 0xa4, 0x35, 0x04, 0x21, 0x88, 0xa8, 0xbb, 0xac, - 0xf6, 0xe0, 0xf7, 0xa5, 0xcf, 0xfa, 0xbe, 0x10, 0x2f, 0xfd, 0x7b, 0xac, - 0x9f, 0xed, 0x5e, 0xd8, 0xa4, 0x7e, 0x71, 0xad, 0x3e, 0xe4, 0x88, 0xb1, - 0x35, 0xb6, 0x61, 0xac, 0x2d, 0x39, 0xf8, 0x3d, 0xc6, 0xd8, 0xe0, 0x6b, - 0x36, 0x9c, 0xf1, 0x69, 0x30, 0x96, 0xdb, 0xa5, 0x72, 0x92, 0x7b, 0x94, - 0x71, 0x16, 0xd3, 0xf7, 0x53, 0x4b, 0xf4, 0x57, 0xf9, 0xde, 0xd2, 0xef, - 0xbb, 0xf4, 0x7b, 0xfa, 0xa3, 0x05, 0xaf, 0x01, 0x3c, 0xdd, 0x05, 0xfd, - 0x79, 0xef, 0x4e, 0x47, 0xe1, 0x86, 0x7b, 0x57, 0xd7, 0x6c, 0xb7, 0xba, - 0x4f, 0x54, 0x29, 0x1d, 0x12, 0x67, 0xc7, 0x4a, 0x2a, 0x22, 0x63, 0x58, - 0x0b, 0xe6, 0x33, 0xa4, 0x27, 0x75, 0x58, 0x0e, 0xa8, 0xb5, 0xa9, 0x1c, - 0xb7, 0x8f, 0x58, 0xa1, 0x29, 0x31, 0x2a, 0x7c, 0xfe, 0x34, 0xd2, 0xc3, - 0xc0, 0x3b, 0x7e, 0xec, 0xd2, 0xa8, 0xac, 0xe7, 0x25, 0x30, 0x86, 0xb9, - 0x6b, 0x5d, 0x1c, 0x6b, 0x2d, 0xc6, 0xc5, 0xf7, 0x43, 0xea, 0x7d, 0x6a, - 0x5d, 0x9c, 0x2b, 0x67, 0x10, 0xcb, 0x04, 0xef, 0xb9, 0x16, 0x5c, 0x2f, - 0xd8, 0xe2, 0xe3, 0x41, 0xcc, 0xab, 0x55, 0xaf, 0x0b, 0xd7, 0x67, 0x46, - 0xce, 0x99, 0xf6, 0x08, 0xe5, 0xef, 0x86, 0x9d, 0x57, 0xcb, 0x44, 0x07, - 0xe3, 0x6d, 0xf5, 0x34, 0x6c, 0x8c, 0xa3, 0xd5, 0x8f, 0xbf, 0x31, 0xfe, - 0xc6, 0xb1, 0xfd, 0x18, 0x5b, 0x76, 0x5d, 0x8c, 0xad, 0x7e, 0x3c, 0x8e, - 0xb5, 0x15, 0xfe, 0x53, 0xc1, 0x8b, 0x3b, 0x5c, 0xa3, 0x6e, 0x6b, 0x9e, - 0xf9, 0x2f, 0x1a, 0x58, 0xc7, 0x38, 0xec, 0x08, 0xd7, 0x32, 0x38, 0x6f, - 0xe6, 0x9a, 0x26, 0xad, 0xc3, 0xfe, 0x7a, 0x0e, 0xfa, 0xeb, 0xee, 0xaf, - 0xff, 0x85, 0xd5, 0x75, 0xa4, 0x7d, 0xe0, 0x3a, 0x76, 0x88, 0x40, 0xcf, - 0x1a, 0x47, 0xb9, 0x86, 0x4c, 0xb9, 0x86, 0x7c, 0xc7, 0x35, 0xec, 0xd2, - 0xef, 0xb8, 0x7e, 0xc0, 0x69, 0x5f, 0xe0, 0x3d, 0xd5, 0xac, 0xfa, 0x06, - 0xab, 0xab, 0x27, 0xd8, 0x8b, 0x29, 0x79, 0x6e, 0xb1, 0x59, 0xcc, 0xb4, - 0x3f, 0xaf, 0xf1, 0x75, 0xf1, 0x76, 0x9e, 0x5f, 0xf5, 0x13, 0x7b, 0x06, - 0xf3, 0x4a, 0x70, 0x5e, 0x07, 0xe4, 0x75, 0xc9, 0xcf, 0x44, 0xe0, 0x03, - 0xa6, 0x80, 0x73, 0xfa, 0xa1, 0x6f, 0x19, 0x1f, 0x45, 0x59, 0x95, 0x78, - 0x85, 0xb6, 0x2e, 0x85, 0xbd, 0x42, 0x1d, 0x4c, 0x3c, 0xf2, 0x9a, 0xe4, - 0xca, 0x81, 0x8e, 0x41, 0xff, 0x46, 0xd0, 0x3f, 0xf9, 0x9c, 0xb9, 0x76, - 0xbb, 0xac, 0x58, 0xdb, 0xc5, 0xb6, 0x96, 0x64, 0x6d, 0x5d, 0xc7, 0x37, - 0xe7, 0xbb, 0x7b, 0x6f, 0x78, 0x4d, 0x36, 0xc6, 0x37, 0x59, 0xfb, 0x49, - 0x09, 0xde, 0x07, 0x6b, 0xbf, 0xe9, 0x3a, 0x14, 0x5e, 0x15, 0xae, 0x05, - 0x79, 0x40, 0x3c, 0x1c, 0x95, 0x7f, 0x13, 0xe7, 0x7e, 0x2c, 0xa8, 0x33, - 0xcd, 0xa4, 0xd1, 0xa3, 0x74, 0xc6, 0x90, 0xeb, 0xcb, 0x6b, 0x01, 0xe3, - 0xc4, 0xba, 0xff, 0xd0, 0x1b, 0x8a, 0xc3, 0xcf, 0xed, 0xa6, 0x7e, 0x09, - 0xf6, 0x74, 0xb3, 0xda, 0xd3, 0x9f, 0x77, 0x43, 0x52, 0x74, 0x42, 0x32, - 0xe5, 0x1c, 0x52, 0x18, 0xff, 0xa3, 0xe8, 0xeb, 0x13, 0xba, 0xaf, 0x29, - 0xe9, 0xd1, 0xfa, 0xe7, 0x20, 0xe4, 0xdc, 0x93, 0x7b, 0xdc, 0x9d, 0x72, - 0x43, 0x1b, 0xf7, 0x40, 0x30, 0xff, 0x43, 0xd2, 0xbd, 0x73, 0xc5, 0x82, - 0x67, 0x70, 0x6d, 0x74, 0x95, 0x07, 0xdc, 0x67, 0x81, 0x7c, 0xfb, 0x7c, - 0xf0, 0xe7, 0xbf, 0x6e, 0xae, 0x7a, 0x9e, 0x9c, 0x33, 0xeb, 0x71, 0xae, - 0x3e, 0x96, 0x5f, 0x9b, 0x6b, 0x50, 0xbf, 0x05, 0xb2, 0x64, 0x5b, 0x12, - 0xaa, 0xe7, 0xcd, 0xaa, 0x8e, 0x1a, 0x61, 0x8c, 0x64, 0xc5, 0xb4, 0x53, - 0x56, 0x28, 0x88, 0x45, 0xfb, 0x58, 0xb7, 0x0b, 0x38, 0xdc, 0xe9, 0xe9, - 0x49, 0xe5, 0x55, 0x8c, 0xd4, 0x50, 0xf3, 0x9a, 0x02, 0x26, 0x5b, 0x74, - 0x5f, 0xf5, 0x3e, 0x09, 0xcc, 0x3a, 0x21, 0x0f, 0x49, 0x78, 0x5d, 0x2c, - 0x17, 0xf9, 0xb3, 0x8c, 0xe7, 0xda, 0x56, 0x06, 0x6b, 0xfc, 0x3b, 0xf0, - 0xe1, 0x2b, 0xd0, 0xfb, 0x1f, 0xa3, 0x6d, 0x28, 0xc1, 0x5e, 0x00, 0x97, - 0x7c, 0xf5, 0x8a, 0x18, 0x7e, 0xa2, 0x2e, 0x96, 0xeb, 0xe3, 0xd3, 0x73, - 0x0a, 0x93, 0x12, 0xb7, 0x1f, 0x09, 0xdd, 0xd5, 0x1b, 0x86, 0x9f, 0x51, - 0xf0, 0x62, 0x0e, 0x71, 0xdc, 0x21, 0xb9, 0x03, 0xeb, 0x73, 0x7a, 0xb1, - 0x10, 0xda, 0x55, 0x0a, 0x64, 0x15, 0x7e, 0x65, 0xcd, 0x4e, 0x9d, 0x07, - 0x3f, 0x9e, 0xd2, 0x98, 0x8f, 0xe7, 0x35, 0x15, 0xed, 0xb3, 0x30, 0x36, - 0x54, 0xac, 0x1d, 0x92, 0x69, 0x97, 0xb1, 0x9d, 0x6e, 0x29, 0xc6, 0x33, - 0x57, 0x37, 0xae, 0xf2, 0xc8, 0x36, 0xe1, 0xf3, 0xa5, 0xa8, 0xbf, 0x2b, - 0xfa, 0xbc, 0xe3, 0x29, 0x25, 0x5f, 0x41, 0x5c, 0x98, 0xfe, 0x11, 0xcf, - 0xab, 0xba, 0xcd, 0x11, 0x3e, 0x97, 0x29, 0x03, 0xca, 0x67, 0x02, 0x2f, - 0xef, 0x90, 0xcc, 0x98, 0xa5, 0x70, 0xcb, 0x63, 0x25, 0xee, 0x17, 0xe2, - 0xff, 0xd7, 0x81, 0xfd, 0x23, 0x58, 0x33, 0xfa, 0x01, 0x1c, 0x9b, 0xfb, - 0x02, 0x65, 0x55, 0xf3, 0x97, 0xec, 0x8b, 0x0f, 0x6d, 0x23, 0xc6, 0x78, - 0xa1, 0xf4, 0x98, 0xe2, 0xdf, 0x8a, 0x04, 0xb1, 0x73, 0x85, 0x05, 0x0b, - 0xd9, 0x70, 0x48, 0x92, 0x73, 0xff, 0x16, 0x32, 0xd4, 0x0f, 0x1f, 0x89, - 0xf5, 0x44, 0x9d, 0x5f, 0x0d, 0x01, 0x73, 0x19, 0xce, 0xbb, 0xa4, 0x68, - 0x46, 0xa5, 0xa8, 0xee, 0xfe, 0xf1, 0x3c, 0x37, 0xac, 0x62, 0x3b, 0x45, - 0x93, 0x98, 0x3f, 0xbd, 0x2d, 0xb8, 0xfb, 0x57, 0x34, 0xd9, 0x8e, 0x79, - 0x96, 0x4f, 0x49, 0x74, 0xee, 0xa0, 0x34, 0xcc, 0x3d, 0x24, 0x8d, 0xc7, - 0x88, 0xf1, 0x18, 0xbb, 0x37, 0x6e, 0x6d, 0x14, 0x62, 0xee, 0x6f, 0x61, - 0xec, 0x43, 0xf2, 0x03, 0x37, 0xa0, 0xe9, 0xba, 0xad, 0xd2, 0xca, 0x3a, - 0x41, 0x9e, 0xcf, 0xc4, 0x09, 0x3c, 0x17, 0x77, 0xfc, 0x18, 0xa9, 0x3a, - 0x57, 0x41, 0x5a, 0xe1, 0xb9, 0x38, 0xdf, 0xbf, 0x66, 0xfa, 0xa9, 0x8f, - 0xf7, 0x7d, 0xdf, 0x83, 0x6d, 0x52, 0x75, 0xd8, 0x62, 0xfd, 0xf7, 0xa1, - 0x39, 0x94, 0xe7, 0xe7, 0x83, 0x3b, 0x3a, 0x06, 0x7c, 0x5f, 0xbb, 0x40, - 0x9f, 0xc1, 0xe4, 0xb7, 0x98, 0xf3, 0x05, 0xf0, 0xf9, 0x1a, 0x75, 0xbf, - 0x87, 0x77, 0x24, 0x50, 0xcf, 0xf2, 0x31, 0x1f, 0xf3, 0x09, 0xf0, 0xf9, - 0xfd, 0x9d, 0x46, 0xfa, 0x7f, 0x5f, 0x9d, 0x1d, 0x20, 0xa6, 0xd8, 0xc6, - 0xb3, 0x3f, 0x60, 0x55, 0xae, 0xed, 0x77, 0xb1, 0xb6, 0x8d, 0xea, 0xac, - 0xa5, 0x58, 0xa2, 0x0f, 0x95, 0xc7, 0x9a, 0xf1, 0x9e, 0x1c, 0x7d, 0xad, - 0xbc, 0x8e, 0x81, 0x92, 0x4e, 0xe2, 0xe8, 0x00, 0x93, 0xb3, 0xcf, 0xcd, - 0xee, 0x03, 0x07, 0x7e, 0x12, 0xd7, 0x38, 0xa1, 0x68, 0x1e, 0xde, 0xe0, - 0x23, 0x1c, 0xc6, 0xfe, 0x5b, 0x84, 0x0c, 0x4d, 0x42, 0xef, 0x0c, 0x85, - 0xb9, 0x27, 0x9a, 0xb5, 0xff, 0xe8, 0xd0, 0x57, 0x0e, 0x8d, 0xa1, 0x0f, - 0xe3, 0xd8, 0x1b, 0x32, 0x05, 0x9d, 0x3b, 0x5d, 0x4b, 0xaa, 0x6f, 0x78, - 0x32, 0x09, 0xde, 0xdb, 0x62, 0xf9, 0x7f, 0x81, 0x8c, 0xbc, 0x01, 0x0c, - 0xba, 0x05, 0xfc, 0x34, 0xf4, 0xbd, 0x90, 0x0f, 0xe8, 0xf8, 0x4f, 0x8c, - 0xf1, 0x6f, 0xe8, 0xaa, 0xa2, 0x8f, 0xef, 0xe2, 0xd3, 0x48, 0xbf, 0xd0, - 0xec, 0xcb, 0xc8, 0xcb, 0x7a, 0x8d, 0x9b, 0x50, 0xfe, 0xa8, 0x8a, 0xfb, - 0xf9, 0x73, 0xb2, 0xb5, 0x7f, 0x10, 0xc5, 0x3a, 0x73, 0x5e, 0x5f, 0x41, - 0x3d, 0xae, 0x6f, 0xaf, 0x3e, 0x0f, 0x6d, 0x56, 0x3a, 0x29, 0xe7, 0x5a, - 0xf0, 0x75, 0x89, 0x89, 0x80, 0xa9, 0x5d, 0xb6, 0x7b, 0x76, 0x1b, 0xcf, - 0x1b, 0x1b, 0x1c, 0x85, 0xe7, 0x3b, 0xc2, 0x12, 0x94, 0xdd, 0x8e, 0x32, - 0xc6, 0x25, 0xde, 0x85, 0xb5, 0x61, 0x59, 0x16, 0x79, 0x8e, 0x75, 0xb5, - 0x1e, 0x87, 0x63, 0x0c, 0xb7, 0xac, 0xa7, 0x89, 0x73, 0xe9, 0xd8, 0xf0, - 0xfd, 0x00, 0xcb, 0xde, 0xa5, 0xcb, 0x22, 0x7a, 0x7e, 0xb7, 0xeb, 0x6f, - 0x67, 0xed, 0x23, 0x99, 0x55, 0x3c, 0x4a, 0xfa, 0x62, 0xaa, 0x5d, 0xc6, - 0xf4, 0x65, 0xe7, 0x30, 0xd6, 0x23, 0x92, 0xf6, 0xda, 0xb9, 0x47, 0x86, - 0xc2, 0x81, 0x5f, 0x98, 0x50, 0xbe, 0x9e, 0x65, 0xf8, 0x77, 0x84, 0xce, - 0x5d, 0x76, 0x0f, 0xda, 0xbf, 0x53, 0x3e, 0xdc, 0xdb, 0x24, 0x8b, 0xb3, - 0x31, 0x7d, 0x3f, 0x31, 0xa1, 0xf6, 0x49, 0x7e, 0x9c, 0xf9, 0x1f, 0x6d, - 0xe3, 0x77, 0xcb, 0x86, 0xc3, 0xf2, 0x0e, 0xcd, 0xdf, 0x77, 0xa9, 0xfb, - 0x3c, 0xbc, 0x67, 0x52, 0x2c, 0xff, 0x44, 0xbd, 0x3f, 0x3d, 0xdf, 0xa0, - 0xea, 0x9f, 0x9e, 0xdf, 0x78, 0x27, 0x87, 0x65, 0xef, 0x66, 0x4c, 0x41, - 0x96, 0x66, 0x1a, 0x64, 0x79, 0xde, 0xa2, 0x8f, 0x94, 0x6e, 0x5c, 0xfb, - 0xf6, 0x45, 0x7f, 0xa7, 0xe6, 0xc9, 0x30, 0xd6, 0x6f, 0x71, 0x70, 0x5a, - 0x2a, 0x83, 0xf4, 0x01, 0xd4, 0xbd, 0x3b, 0xc8, 0x48, 0x03, 0xf0, 0x5f, - 0xc1, 0xab, 0x38, 0x8c, 0xbd, 0xb6, 0x6a, 0x1f, 0xea, 0xc7, 0xda, 0xcf, - 0x22, 0x8f, 0x0c, 0xc9, 0xf5, 0x4f, 0x29, 0xba, 0x2a, 0x8a, 0x57, 0xc1, - 0xb7, 0x45, 0xec, 0x9f, 0xdf, 0x17, 0x85, 0x35, 0x7e, 0x7c, 0x50, 0xf3, - 0xfc, 0xaf, 0x75, 0xfa, 0x88, 0xec, 0x3b, 0xfe, 0x19, 0xd0, 0xda, 0xe4, - 0xdf, 0x2d, 0x92, 0xfa, 0xef, 0x36, 0x22, 0xea, 0xdb, 0x95, 0x88, 0xf3, - 0x08, 0xca, 0x18, 0x7b, 0x7a, 0x44, 0xcd, 0x83, 0xf7, 0xd7, 0x0a, 0xf2, - 0xab, 0xee, 0x64, 0x04, 0xfe, 0x0f, 0xef, 0x08, 0x35, 0xeb, 0xfe, 0x76, - 0xe9, 0x75, 0x1c, 0x97, 0x7d, 0xd0, 0xef, 0x79, 0xe0, 0x40, 0xde, 0xab, - 0x9a, 0x08, 0xd7, 0x8f, 0x19, 0xc8, 0xb2, 0xef, 0x5b, 0x07, 0x67, 0xfd, - 0x61, 0xe5, 0x03, 0xac, 0xfa, 0xe9, 0xba, 0x7c, 0x5c, 0xf6, 0x97, 0x94, - 0xbf, 0xae, 0xce, 0xe8, 0xa6, 0xb1, 0x27, 0x87, 0x94, 0x0e, 0x8f, 0x85, - 0x86, 0xab, 0x69, 0xc9, 0x9f, 0xdc, 0x8d, 0x71, 0x18, 0xfb, 0xca, 0xe8, - 0xb3, 0xb0, 0xbd, 0xb2, 0xaf, 0xe6, 0x8f, 0x3d, 0x59, 0xe2, 0xfb, 0x24, - 0xec, 0x22, 0xdf, 0xe7, 0x12, 0x61, 0x15, 0xcd, 0xbf, 0x0e, 0x6d, 0x1b, - 0x34, 0x6f, 0x79, 0x9f, 0x9e, 0xed, 0xb9, 0xff, 0x3e, 0x6e, 0x4a, 0x73, - 0x0e, 0xef, 0xd9, 0x26, 0xe8, 0x6f, 0x12, 0x7a, 0x9a, 0xfe, 0xe8, 0xc3, - 0xb2, 0x52, 0x9e, 0x96, 0xf3, 0xe5, 0x40, 0xce, 0x78, 0xb7, 0x99, 0xb4, - 0xdf, 0xa9, 0xef, 0x36, 0x67, 0xb0, 0x0e, 0xeb, 0x79, 0x95, 0x5b, 0xf7, - 0xfd, 0xd1, 0x5f, 0x98, 0xfe, 0x37, 0x80, 0xb7, 0xa9, 0x7b, 0x4a, 0xeb, - 0xe5, 0x9d, 0xfd, 0x2c, 0x9b, 0x8c, 0xed, 0xfb, 0x77, 0xad, 0x3a, 0xea, - 0xde, 0xc7, 0xf5, 0xfd, 0xa6, 0xe7, 0xf4, 0x9d, 0x78, 0xf2, 0x73, 0x4c, - 0xd3, 0x7b, 0x1d, 0xf6, 0x1e, 0xfb, 0x7c, 0x54, 0xaf, 0x1b, 0xd2, 0x45, - 0x3e, 0x53, 0x0f, 0xad, 0xe8, 0xf3, 0x4e, 0x53, 0x8f, 0x51, 0x7f, 0xbf, - 0xac, 0xa1, 0x6e, 0x5c, 0xb6, 0xe7, 0xb7, 0x48, 0xc1, 0x5d, 0x6b, 0x96, - 0x1d, 0xd7, 0xf7, 0xd8, 0x82, 0xbb, 0xd5, 0x2c, 0x0b, 0xee, 0x5b, 0x91, - 0x5f, 0x8c, 0xe1, 0x21, 0xad, 0x8d, 0xe9, 0xe7, 0xb1, 0xba, 0x6f, 0x74, - 0x82, 0x3e, 0x23, 0xe8, 0xe3, 0xf6, 0xf0, 0xe5, 0x77, 0xb1, 0xf9, 0xdd, - 0x14, 0x65, 0xd1, 0xe0, 0x37, 0xdd, 0xf4, 0x7b, 0x80, 0x55, 0xb6, 0xca, - 0xa4, 0xa2, 0xa7, 0xa0, 0xee, 0x27, 0x64, 0xdd, 0x26, 0x19, 0x32, 0xfd, - 0xfc, 0xe4, 0xe2, 0x46, 0x39, 0x65, 0xf9, 0xf5, 0x31, 0x69, 0x2e, 0x60, - 0x1c, 0xbe, 0xdf, 0xec, 0x1b, 0x81, 0xa8, 0xfe, 0x4e, 0xc9, 0x45, 0x9b, - 0xcf, 0x53, 0xde, 0x0b, 0x85, 0xd5, 0xbb, 0x90, 0x05, 0x15, 0x97, 0x14, - 0x23, 0xb8, 0x93, 0xc8, 0x6f, 0xd6, 0x45, 0x9e, 0xa9, 0xf2, 0xbb, 0xad, - 0xdb, 0xd4, 0xbd, 0x11, 0xff, 0x2c, 0x8e, 0x74, 0x75, 0x2b, 0x9d, 0x5c, - 0xa9, 0x16, 0xc9, 0x53, 0x1d, 0x87, 0x8d, 0xea, 0x38, 0x2c, 0x79, 0x3c, - 0x02, 0x1e, 0xff, 0x3f, 0xbd, 0x2e, 0xc1, 0x77, 0x5f, 0x3c, 0xeb, 0xe1, - 0x79, 0xd0, 0xa3, 0x6a, 0x2e, 0xd4, 0xd1, 0x68, 0xfb, 0xde, 0xb0, 0xda, - 0xbb, 0xea, 0x9b, 0x78, 0xc8, 0x27, 0xbf, 0x71, 0x87, 0x7e, 0x2d, 0xf1, - 0x5b, 0xf6, 0x11, 0xf5, 0x3d, 0x47, 0xa5, 0xca, 0x75, 0xe5, 0x37, 0xec, - 0x63, 0x75, 0xf2, 0x18, 0xd6, 0x63, 0x6d, 0x69, 0x93, 0x66, 0x7f, 0xdd, - 0xf9, 0x2d, 0x48, 0xa5, 0x1a, 0xdc, 0xa3, 0xdc, 0xb2, 0xc2, 0x3d, 0x21, - 0xbe, 0x5f, 0xab, 0xbe, 0x67, 0xa9, 0xa8, 0xef, 0x43, 0x2c, 0x7e, 0x67, - 0x09, 0xdb, 0xb1, 0x07, 0xcf, 0x3c, 0x47, 0xdd, 0x8b, 0x14, 0x3a, 0xa7, - 0x3a, 0x81, 0xf4, 0x21, 0xc9, 0xa9, 0x38, 0x57, 0x0b, 0xf2, 0x93, 0x6a, - 0xec, 0x62, 0xf5, 0x7e, 0xd9, 0x77, 0xf2, 0x01, 0x7e, 0x43, 0xa3, 0xbe, - 0xc3, 0xcf, 0xba, 0xa4, 0x31, 0x2e, 0x53, 0x6a, 0xde, 0x85, 0xb5, 0x6f, - 0x33, 0x7c, 0x39, 0x6a, 0xe3, 0x9a, 0x16, 0xaa, 0x2d, 0xa0, 0x31, 0xa4, - 0xef, 0x52, 0x12, 0xff, 0x06, 0xf3, 0x6f, 0xe6, 0xfd, 0x3c, 0x8f, 0xe7, - 0x65, 0xfb, 0x4a, 0xbc, 0x2b, 0x99, 0xd4, 0x7e, 0x31, 0x63, 0x65, 0x8c, - 0xc7, 0x53, 0xc6, 0xed, 0xd4, 0x04, 0xb4, 0x7f, 0x54, 0x12, 0x3c, 0xcb, - 0xd5, 0x73, 0x69, 0xa9, 0x9b, 0x0b, 0xef, 0x87, 0xfa, 0xf3, 0xe1, 0x37, - 0x27, 0xf9, 0x52, 0xfd, 0xf7, 0x32, 0xea, 0x9b, 0x70, 0xf5, 0x7d, 0xca, - 0x44, 0xf5, 0x41, 0xb9, 0xaf, 0xb4, 0x55, 0x7f, 0x2b, 0x13, 0x93, 0xfb, - 0xaa, 0x6f, 0x28, 0x9e, 0xe6, 0xd5, 0x77, 0x3e, 0x51, 0xbd, 0x66, 0x71, - 0xd5, 0xc7, 0xda, 0xf7, 0x3e, 0x76, 0xdd, 0xb7, 0x1f, 0x51, 0x99, 0x58, - 0xfc, 0x65, 0xdf, 0xfc, 0x3c, 0x2c, 0xfc, 0xee, 0xe3, 0x25, 0x77, 0x5a, - 0x1e, 0x2b, 0x7b, 0xde, 0x1d, 0x2e, 0xb1, 0xd4, 0x16, 0x39, 0x1f, 0xcf, - 0x0c, 0x7e, 0xcf, 0x69, 0x0f, 0x55, 0x66, 0x1b, 0xa1, 0xaf, 0x1b, 0x95, - 0x2d, 0x61, 0x7e, 0x71, 0x96, 0x7b, 0x3e, 0x82, 0x39, 0xda, 0xe6, 0x25, - 0xf9, 0x54, 0x1b, 0xe3, 0x4c, 0x77, 0xc0, 0x77, 0xfb, 0xb8, 0xeb, 0xeb, - 0xe5, 0xcf, 0x2d, 0xed, 0x96, 0xcf, 0x55, 0x63, 0xa1, 0xca, 0x0c, 0xef, - 0xd7, 0xd9, 0x23, 0x65, 0x49, 0xa2, 0x1e, 0xfb, 0x87, 0xbc, 0x24, 0xb6, - 0xcb, 0xd3, 0xc7, 0x7f, 0xee, 0x5d, 0x72, 0xf0, 0x1e, 0xba, 0xe6, 0xbc, - 0x1b, 0xc4, 0xd2, 0xe0, 0x37, 0x1f, 0x65, 0xbd, 0xed, 0x90, 0x03, 0xd8, - 0x6d, 0xec, 0x39, 0xfa, 0x75, 0x97, 0xb4, 0xde, 0x32, 0x8e, 0x5e, 0x23, - 0x97, 0x56, 0xef, 0xe4, 0xbe, 0x0e, 0xd9, 0xb6, 0x7c, 0xfe, 0xab, 0xd8, - 0xf3, 0x41, 0x09, 0x7f, 0x01, 0x76, 0xe2, 0x0b, 0x0d, 0x4a, 0xb7, 0xd3, - 0x9e, 0x01, 0xf3, 0x03, 0xd7, 0x47, 0xd0, 0xcf, 0xfe, 0x36, 0x5f, 0x66, - 0xa7, 0x45, 0xbe, 0xd8, 0x24, 0x99, 0x36, 0xfa, 0x8d, 0xf2, 0x2b, 0xf4, - 0x57, 0xfd, 0x3e, 0x4b, 0xc9, 0x9f, 0x71, 0x8f, 0xd7, 0x38, 0x97, 0x64, - 0xe2, 0x7f, 0xc9, 0x27, 0x65, 0x22, 0xc1, 0xb9, 0x3c, 0x2c, 0x85, 0xf2, - 0xa3, 0xf8, 0x71, 0x9e, 0xa4, 0xfb, 0x5f, 0xe8, 0xb3, 0xfb, 0x31, 0x29, - 0xce, 0xa4, 0x65, 0x6a, 0x7e, 0x92, 0xdf, 0xe4, 0x8e, 0xdc, 0xa1, 0xce, - 0xb4, 0xec, 0x44, 0x32, 0xd4, 0x67, 0x4d, 0xf1, 0xae, 0x82, 0x9a, 0xcf, - 0x24, 0xe6, 0xf3, 0x4a, 0x1b, 0xef, 0x78, 0x5f, 0x82, 0xfe, 0x35, 0x4e, - 0x50, 0x0e, 0x6d, 0xb3, 0x2b, 0xc4, 0xfc, 0x5e, 0xf8, 0xab, 0x2c, 0xdb, - 0x2b, 0xe1, 0xa3, 0xab, 0x7a, 0x1e, 0xe5, 0xfa, 0x6c, 0x55, 0xb5, 0xff, - 0xaf, 0x68, 0x8b, 0x7a, 0x47, 0x83, 0xb6, 0x41, 0x1d, 0xb6, 0xe5, 0x3c, - 0x77, 0xc3, 0x4f, 0x0e, 0xe8, 0x82, 0x1c, 0x26, 0xea, 0xf9, 0xdd, 0xbc, - 0x81, 0xdf, 0x11, 0xe2, 0x4d, 0xf0, 0x8b, 0x3c, 0x0e, 0x6b, 0x1e, 0xff, - 0x3d, 0xfa, 0x0f, 0xd6, 0xe0, 0x0e, 0x94, 0x99, 0xfa, 0x1b, 0xbc, 0x77, - 0xc2, 0x77, 0xf2, 0x9c, 0xf5, 0xf7, 0xb7, 0xf9, 0xb2, 0x46, 0x7a, 0x36, - 0xe3, 0xf9, 0x7b, 0xdb, 0xfd, 0x75, 0xd9, 0x0b, 0x7e, 0xf1, 0x1e, 0x65, - 0x9f, 0xba, 0x8f, 0x9f, 0x19, 0xdf, 0x0b, 0xd9, 0x09, 0xe6, 0xd5, 0x07, - 0x19, 0xe3, 0x39, 0x01, 0xeb, 0xd7, 0xf3, 0xc4, 0xb7, 0x7b, 0x61, 0xfa, - 0xfa, 0x0e, 0xe7, 0x0a, 0x4c, 0xf8, 0x45, 0xf5, 0xfd, 0x0d, 0xf4, 0xe4, - 0xbb, 0x57, 0xbf, 0xbf, 0xb9, 0xf2, 0x1a, 0x0f, 0xb4, 0xfb, 0x36, 0xca, - 0x04, 0x4f, 0x5a, 0x75, 0x9b, 0xbd, 0xc0, 0xa7, 0x8c, 0x7f, 0x26, 0x13, - 0x9f, 0x90, 0x60, 0x1c, 0xef, 0x36, 0xfa, 0x79, 0x43, 0x03, 0x7d, 0xf0, - 0x69, 0xd5, 0x1d, 0x95, 0x04, 0xef, 0xbc, 0x24, 0x43, 0x7b, 0xd5, 0x7d, - 0x85, 0x17, 0xd6, 0x7d, 0x43, 0x95, 0x92, 0xa7, 0xd7, 0x64, 0x65, 0xe4, - 0x47, 0x62, 0x8b, 0x75, 0x35, 0x65, 0x85, 0xfd, 0x4e, 0x72, 0x9e, 0x89, - 0x07, 0xd4, 0x3c, 0x4d, 0xf8, 0x4d, 0xbc, 0x5b, 0x60, 0x86, 0x2a, 0xf3, - 0x5c, 0x77, 0xa4, 0x4b, 0x7c, 0x0e, 0xce, 0x37, 0x95, 0x5e, 0xc1, 0xb8, - 0x2c, 0xa3, 0x6e, 0xe4, 0xfb, 0xb4, 0x3e, 0xff, 0xbc, 0xa7, 0x9d, 0x67, - 0xf0, 0x79, 0x94, 0x95, 0x97, 0x36, 0xa7, 0xed, 0xe3, 0x4a, 0x0e, 0x1e, - 0x06, 0xdf, 0xff, 0x04, 0x75, 0x1f, 0x45, 0xca, 0x39, 0xa6, 0x57, 0xd7, - 0x9d, 0xfc, 0xfe, 0xb0, 0x0c, 0x42, 0x2e, 0x98, 0x7f, 0x58, 0x8a, 0xea, - 0xee, 0x10, 0xd2, 0x32, 0x9f, 0xa9, 0xeb, 0x1d, 0x6d, 0x4f, 0x49, 0xcb, - 0x5e, 0xfd, 0xdd, 0x56, 0x20, 0x4f, 0x7b, 0x74, 0xbb, 0xf1, 0x55, 0x5e, - 0x3d, 0x70, 0x19, 0xde, 0x88, 0xae, 0xe2, 0x0d, 0x7f, 0xac, 0x62, 0x7b, - 0x80, 0x35, 0xfc, 0x39, 0xf8, 0x58, 0xc3, 0x97, 0xf3, 0x49, 0x89, 0x40, - 0x8e, 0xc3, 0x6b, 0x72, 0x0c, 0xdc, 0xe3, 0xef, 0x99, 0x29, 0x9e, 0xdb, - 0x29, 0x3e, 0x53, 0x0e, 0x29, 0xbf, 0x5c, 0xc7, 0xfa, 0xb5, 0xbe, 0xf1, - 0x97, 0xac, 0xf5, 0x85, 0xf6, 0x00, 0x3f, 0xfc, 0xd3, 0xf6, 0xc1, 0xd7, - 0xda, 0xd7, 0xf6, 0xc1, 0x35, 0xbf, 0xa1, 0x7d, 0xb0, 0x51, 0x2e, 0xeb, - 0x65, 0xca, 0x84, 0x3c, 0x71, 0xbd, 0x28, 0x4f, 0x94, 0x23, 0xf2, 0x92, - 0xfa, 0xb4, 0x91, 0xbe, 0x53, 0xe2, 0xa2, 0xfa, 0x3e, 0x62, 0x1a, 0x3a, - 0xa8, 0x3d, 0x54, 0x86, 0x5f, 0x5e, 0x5c, 0xba, 0x49, 0xc9, 0xf4, 0xd3, - 0x35, 0xea, 0xa5, 0x2b, 0xcd, 0x7d, 0xbd, 0xce, 0xcd, 0x6f, 0xd0, 0xb9, - 0xf9, 0x55, 0x9d, 0xdb, 0xa6, 0xfd, 0xa5, 0x7f, 0x8a, 0xce, 0x8d, 0xd7, - 0x9d, 0x85, 0x04, 0xe7, 0x20, 0x12, 0xca, 0xf6, 0x36, 0xcb, 0xae, 0xd9, - 0xb8, 0x8c, 0xcc, 0xec, 0x96, 0x3f, 0x9a, 0x99, 0x56, 0xf7, 0x82, 0xfe, - 0xca, 0x4d, 0x26, 0xee, 0x0f, 0x79, 0xf2, 0x61, 0xf8, 0xbb, 0x13, 0x9d, - 0x0d, 0xb2, 0xeb, 0xfd, 0xea, 0x7c, 0xcf, 0xcc, 0x86, 0x3a, 0x84, 0x91, - 0xe7, 0x9c, 0x6b, 0xbb, 0x56, 0x88, 0x77, 0xc4, 0x1a, 0x65, 0x22, 0xde, - 0x22, 0xbb, 0x81, 0x9d, 0x0a, 0x57, 0xb9, 0xea, 0x9b, 0xed, 0x8c, 0x3a, - 0x3f, 0xe9, 0xde, 0xee, 0x8f, 0x0b, 0x3e, 0xb4, 0x9a, 0xf2, 0xe7, 0xb5, - 0x6e, 0xf5, 0xfd, 0xf1, 0x0b, 0xa5, 0x3f, 0x6f, 0x5b, 0x9f, 0xe7, 0xf3, - 0x7f, 0x42, 0x9d, 0x38, 0x78, 0x55, 0x7f, 0xdf, 0x26, 0xac, 0xf8, 0x59, - 0x2c, 0x8f, 0xab, 0x7b, 0x4c, 0x17, 0xc3, 0xe4, 0x97, 0xf2, 0x9b, 0x12, - 0xd9, 0x30, 0x30, 0xce, 0x2c, 0x90, 0xb4, 0x43, 0x9f, 0x4f, 0xe3, 0x4f, - 0xe8, 0xff, 0x7d, 0xea, 0x3c, 0x75, 0x05, 0xbc, 0xf1, 0x54, 0xbc, 0x35, - 0x1f, 0x27, 0xae, 0x5f, 0xbb, 0xb3, 0x7b, 0x39, 0xbe, 0xf7, 0xbf, 0xf1, - 0xd2, 0xb1, 0x7f, 0x1d, 0x9f, 0xd1, 0x3e, 0xb8, 0x3a, 0xcb, 0xda, 0xec, - 0xff, 0x50, 0xf8, 0xdf, 0xec, 0x67, 0x4b, 0xc4, 0x76, 0xf6, 0x91, 0xb2, - 0xf4, 0x6f, 0x57, 0xb1, 0x26, 0xf2, 0xb7, 0x82, 0x75, 0x3a, 0x96, 0x08, - 0xec, 0x79, 0xa8, 0xeb, 0x6c, 0xbd, 0x1f, 0xc8, 0x3e, 0x62, 0xea, 0x0e, - 0xc4, 0xda, 0xff, 0xbd, 0x61, 0x4c, 0x25, 0x13, 0xba, 0xab, 0x34, 0x2d, - 0xe1, 0xb9, 0x31, 0x89, 0x1c, 0x63, 0xfc, 0x3a, 0x23, 0xc5, 0xb8, 0x27, - 0xf7, 0xb9, 0xeb, 0x7d, 0x93, 0x2e, 0x63, 0x23, 0xed, 0x0f, 0xcb, 0xd0, - 0xc9, 0x47, 0x25, 0x3a, 0xc7, 0x77, 0xeb, 0xce, 0x2e, 0xa0, 0x8f, 0xb6, - 0x48, 0x39, 0xce, 0x18, 0x6e, 0x54, 0x9d, 0x05, 0x9f, 0x1f, 0x5f, 0x90, - 0x22, 0xb0, 0x42, 0x5e, 0xe9, 0x16, 0xa4, 0xab, 0xbe, 0xc4, 0xf4, 0x76, - 0xee, 0x29, 0xf8, 0x98, 0xa1, 0x89, 0x72, 0x54, 0xdd, 0xc9, 0x39, 0x1f, - 0x67, 0x5d, 0xf8, 0xef, 0x73, 0xc4, 0x19, 0xd0, 0x1d, 0x63, 0x12, 0x62, - 0x3e, 0x3c, 0xb7, 0x86, 0x33, 0xa8, 0x13, 0x86, 0xdc, 0xb8, 0x44, 0x4e, - 0xf9, 0x73, 0xe7, 0x3f, 0x52, 0x32, 0x16, 0x76, 0x4b, 0xf8, 0x18, 0x9f, - 0xeb, 0xfd, 0x21, 0x62, 0x77, 0xd8, 0x86, 0xb3, 0x9f, 0x45, 0x7f, 0x7c, - 0x97, 0xd1, 0xdf, 0xc2, 0x22, 0x5f, 0xf9, 0xc7, 0xfe, 0xcf, 0x04, 0xca, - 0xfe, 0xff, 0x07, 0x3b, 0x97, 0x22, 0x9a, 0xb0, 0x4e, 0x00, 0x00, 0x00 }; + 0xcd, 0x7c, 0x0d, 0x70, 0x5b, 0xd7, 0x95, 0xde, 0xc1, 0x03, 0x40, 0x82, + 0x10, 0x45, 0x3d, 0x52, 0x30, 0x0d, 0x3b, 0x4c, 0x82, 0x47, 0x3c, 0x92, + 0xb0, 0xc9, 0x64, 0x9f, 0x64, 0x46, 0x66, 0x12, 0xac, 0x05, 0x03, 0xa4, + 0x4c, 0x27, 0xea, 0x92, 0xb6, 0x19, 0x47, 0x6d, 0x35, 0x09, 0x17, 0x92, + 0x12, 0xdb, 0x4d, 0xa7, 0x9a, 0xc6, 0xe9, 0x2a, 0x1b, 0xc7, 0x82, 0x41, + 0xca, 0x51, 0x52, 0x8a, 0x60, 0x24, 0x4a, 0xf2, 0x74, 0xb3, 0xbb, 0x0c, + 0x48, 0x4a, 0x8e, 0x03, 0x09, 0x96, 0xec, 0x75, 0xdc, 0xad, 0xb3, 0x62, + 0x68, 0xad, 0xec, 0x4d, 0xb3, 0xad, 0x9d, 0x49, 0x3a, 0x9a, 0xa9, 0xb7, + 0x55, 0x95, 0xa4, 0xf9, 0x99, 0xfe, 0xb8, 0x49, 0xa6, 0x75, 0xbb, 0xf1, + 0xbe, 0x7e, 0xdf, 0x7d, 0xf7, 0x11, 0x20, 0xc5, 0x28, 0xde, 0xec, 0x64, + 0x66, 0x39, 0x83, 0xb9, 0xef, 0xde, 0x77, 0x7f, 0xce, 0x3d, 0xf7, 0xfc, + 0x7c, 0xe7, 0xde, 0xfb, 0x78, 0x87, 0x48, 0x54, 0xf4, 0xdf, 0x46, 0xfc, + 0xfa, 0xff, 0xe9, 0x3f, 0xdb, 0xb3, 0xf5, 0xdd, 0xfd, 0xef, 0x66, 0xde, + 0x30, 0x42, 0x21, 0xa6, 0x41, 0xfc, 0x62, 0xf8, 0x6d, 0xd5, 0xcf, 0xeb, + 0xfd, 0x99, 0xf8, 0x6d, 0x0b, 0x88, 0x8c, 0xff, 0x44, 0x24, 0xb0, 0xe6, + 0x5d, 0x64, 0x9d, 0xfa, 0xae, 0xfb, 0x4b, 0x3a, 0xd2, 0x7f, 0x06, 0x7e, + 0x89, 0xeb, 0x57, 0x59, 0x19, 0xf7, 0xd7, 0xfd, 0x0b, 0xea, 0xe6, 0x1b, + 0xf5, 0x4f, 0x22, 0x46, 0x5a, 0x46, 0xb2, 0xb6, 0x44, 0x82, 0xe9, 0x9f, + 0x8f, 0xec, 0xb1, 0x45, 0x32, 0x95, 0xde, 0x44, 0x4e, 0xde, 0x74, 0x0b, + 0xb1, 0x90, 0xb0, 0xfc, 0xed, 0xe9, 0x5f, 0x1c, 0xfc, 0xfa, 0xed, 0xd6, + 0xeb, 0x73, 0x41, 0x89, 0x98, 0xe9, 0x37, 0xc4, 0xec, 0x96, 0x48, 0x07, + 0xda, 0x7c, 0xa9, 0xe7, 0x49, 0x43, 0x5a, 0xfc, 0xbe, 0xcc, 0xf1, 0x60, + 0x5a, 0x46, 0xf7, 0x4e, 0x1d, 0x74, 0x0d, 0x5b, 0x0a, 0x37, 0xa7, 0xed, + 0x44, 0x51, 0x9a, 0x07, 0x26, 0xfb, 0x6f, 0x17, 0xe4, 0x47, 0xf7, 0x56, + 0x22, 0x92, 0xad, 0x16, 0x9a, 0x0d, 0xdb, 0x46, 0x1a, 0x29, 0xbc, 0x2d, + 0x2d, 0x91, 0x86, 0xf4, 0x6c, 0xe3, 0x25, 0x9b, 0xe3, 0x0f, 0x60, 0xfc, + 0xb7, 0x49, 0xc8, 0x76, 0xdd, 0x49, 0x8c, 0xbf, 0xa3, 0xf2, 0xa6, 0xfb, + 0x58, 0xc8, 0x1b, 0xdb, 0x48, 0x1f, 0x08, 0x32, 0x0d, 0xa4, 0x33, 0x23, + 0x9d, 0x15, 0x95, 0x6f, 0xf0, 0xf2, 0x83, 0x3a, 0x1f, 0x89, 0x7a, 0xb4, + 0x4b, 0x13, 0x68, 0x8f, 0x84, 0xd2, 0xe9, 0x26, 0xf4, 0x11, 0x09, 0xa7, + 0x97, 0x7e, 0x7b, 0x51, 0xd5, 0x3b, 0xac, 0xeb, 0x3d, 0x10, 0xf6, 0xda, + 0x4d, 0x8e, 0x74, 0x57, 0x98, 0xce, 0x8e, 0x74, 0xa9, 0xf4, 0x4b, 0x23, + 0x49, 0x95, 0xce, 0xa9, 0x7a, 0x81, 0xf4, 0xc2, 0x88, 0xad, 0xd2, 0xb4, + 0x2e, 0x1f, 0x1e, 0x49, 0xa8, 0x74, 0xa7, 0x4e, 0x47, 0x75, 0x3a, 0xa6, + 0xd3, 0x5d, 0x3a, 0xdd, 0xad, 0xd3, 0x71, 0x9d, 0xee, 0xd5, 0xfd, 0x3c, + 0xa0, 0xf3, 0x9f, 0xd0, 0xe9, 0x7e, 0x9d, 0x3e, 0xac, 0xd3, 0x03, 0x3a, + 0x7d, 0x44, 0xd3, 0x55, 0xd0, 0xe9, 0x94, 0x2e, 0x9f, 0xd1, 0x74, 0x3e, + 0x01, 0x7a, 0xfe, 0x71, 0xa3, 0x96, 0x5b, 0xcc, 0x37, 0x21, 0x7b, 0xa6, + 0x22, 0x52, 0x2c, 0x05, 0x25, 0xa7, 0xd6, 0xf3, 0xe3, 0x61, 0x89, 0x46, + 0x64, 0xa2, 0x1a, 0x91, 0x2b, 0x4a, 0x5c, 0x7f, 0xe4, 0x7e, 0xbd, 0xc7, + 0x94, 0xa7, 0xab, 0x31, 0xb9, 0x50, 0x95, 0xc0, 0x68, 0x4f, 0x93, 0x18, + 0x47, 0x6f, 0x96, 0x8c, 0x19, 0x90, 0xa0, 0xe2, 0x6b, 0x42, 0xb2, 0x53, + 0xed, 0xc8, 0x5b, 0x71, 0x91, 0xc5, 0xb0, 0xb7, 0x8e, 0x11, 0x09, 0x9e, + 0xe0, 0xba, 0x3c, 0x37, 0x72, 0x69, 0x36, 0x2e, 0xa1, 0xe9, 0x04, 0xfa, + 0x6f, 0x96, 0xf0, 0x09, 0xe9, 0x08, 0x4a, 0x57, 0xfc, 0x63, 0xa8, 0x31, + 0x58, 0x09, 0xc9, 0x50, 0x25, 0x80, 0xb5, 0x8a, 0x40, 0x4e, 0x9a, 0xf1, + 0x33, 0xf1, 0x8b, 0xe1, 0x17, 0xc7, 0xef, 0xaf, 0xd0, 0x4f, 0x87, 0xe4, + 0x2a, 0xec, 0x13, 0xe3, 0x96, 0x30, 0x7e, 0xc9, 0x32, 0xc7, 0x85, 0x34, + 0xc5, 0xe5, 0xeb, 0x3d, 0x1e, 0x4d, 0x17, 0xaa, 0x91, 0x40, 0xf6, 0xa4, + 0xec, 0xcf, 0x39, 0x92, 0x30, 0xec, 0xa8, 0xe4, 0xcd, 0x40, 0x62, 0x6f, + 0xaa, 0x4d, 0x0a, 0x63, 0x78, 0x57, 0x92, 0x8c, 0x81, 0xbe, 0xf3, 0xa6, + 0x8c, 0x7b, 0xef, 0x58, 0xf6, 0x7f, 0xa1, 0xaf, 0x96, 0x49, 0xc1, 0xbd, + 0x50, 0xfa, 0xd7, 0x78, 0x66, 0x5f, 0x2f, 0x86, 0x3c, 0x9a, 0xdf, 0x40, + 0x9e, 0xe5, 0xee, 0x26, 0x2f, 0xcf, 0x67, 0xd6, 0xf5, 0xc7, 0xf4, 0xe7, + 0xca, 0xb1, 0x7b, 0x30, 0x5f, 0x8e, 0xbf, 0x32, 0x5f, 0xd0, 0xd1, 0x1c, + 0xc8, 0x9d, 0x4c, 0xc8, 0xa1, 0xd2, 0x1d, 0x92, 0x75, 0x5c, 0x77, 0x8f, + 0x23, 0x31, 0x43, 0xba, 0xcc, 0x1c, 0xde, 0x96, 0x2b, 0x12, 0xc8, 0x96, + 0x7c, 0x7e, 0xb0, 0xdf, 0x10, 0xca, 0xda, 0x51, 0xbf, 0x25, 0x30, 0x78, + 0x12, 0xb4, 0xa7, 0xc9, 0x17, 0xc8, 0xac, 0xd3, 0x15, 0xdf, 0x8b, 0xf1, + 0xe6, 0x2b, 0x5d, 0xce, 0xb2, 0x98, 0xe8, 0xb3, 0x0d, 0x75, 0xc8, 0x23, + 0xf6, 0xc5, 0x3e, 0xd9, 0x5f, 0x33, 0xda, 0xc6, 0xf0, 0x8e, 0x34, 0xb9, + 0x6e, 0xd6, 0x31, 0x99, 0x97, 0x39, 0xf0, 0x6d, 0x8e, 0x7c, 0x8b, 0x76, + 0xc8, 0xa9, 0x0a, 0xc7, 0x58, 0x8f, 0xee, 0x5b, 0xff, 0x9e, 0xd1, 0x1d, + 0x47, 0xff, 0x31, 0xa4, 0x1b, 0x02, 0xd9, 0x63, 0x2e, 0xc6, 0x8f, 0xe3, + 0x79, 0xbd, 0x39, 0x5c, 0xd1, 0x32, 0x18, 0x07, 0xed, 0x31, 0x39, 0xa7, + 0xe4, 0x70, 0x83, 0x04, 0x21, 0x87, 0x5c, 0xe3, 0xd6, 0x13, 0xef, 0x91, + 0x7c, 0xcc, 0x4a, 0xd0, 0x76, 0x76, 0x6e, 0x6d, 0xc2, 0x1c, 0xb5, 0x15, + 0x9c, 0x8e, 0x41, 0x0e, 0x97, 0x5b, 0x0d, 0x94, 0x18, 0x62, 0x99, 0xff, + 0x48, 0x0a, 0x92, 0x5b, 0xf8, 0xbd, 0x80, 0x44, 0x0d, 0xd4, 0xbb, 0x25, + 0xe0, 0xf1, 0x80, 0xfc, 0xc9, 0x80, 0x3f, 0x01, 0xd1, 0xf6, 0x41, 0x3a, + 0x2b, 0x7c, 0xdf, 0x9b, 0x30, 0xd4, 0xbb, 0x41, 0xbc, 0x0b, 0x49, 0x72, + 0xab, 0xff, 0x7e, 0x10, 0xef, 0x6f, 0x96, 0x71, 0x13, 0xb4, 0x94, 0x9e, + 0x37, 0xb2, 0xa0, 0xf1, 0xce, 0x90, 0x9a, 0x2b, 0xea, 0x8e, 0xd7, 0xf5, + 0x33, 0x8e, 0x7a, 0xff, 0x0a, 0x63, 0x81, 0xde, 0x52, 0x02, 0xb4, 0xb4, + 0x83, 0x16, 0xd2, 0x58, 0x30, 0xb2, 0xd5, 0x10, 0xf2, 0x93, 0x46, 0xee, + 0xf4, 0x61, 0x3c, 0x8b, 0x69, 0xa4, 0x9f, 0x67, 0x8a, 0xf6, 0xbb, 0xeb, + 0xda, 0xef, 0x46, 0x7b, 0x8e, 0xc1, 0xf6, 0x9e, 0xfc, 0x17, 0x94, 0x2c, + 0x26, 0xae, 0xc3, 0x8f, 0xe0, 0xaf, 0xc1, 0x8f, 0x7f, 0xa3, 0xf9, 0xf1, + 0xd7, 0xf2, 0x9b, 0xe7, 0xc7, 0x7f, 0xfa, 0x0d, 0xf1, 0x43, 0x24, 0x7f, + 0x8c, 0xcf, 0x21, 0x29, 0x28, 0xbb, 0x45, 0xbd, 0xa5, 0xbc, 0xd3, 0x66, + 0x91, 0x4f, 0x94, 0x63, 0xe8, 0x40, 0x35, 0x84, 0xf4, 0x49, 0xa4, 0x1b, + 0x02, 0xa3, 0xc7, 0xae, 0x62, 0xfd, 0x5d, 0x31, 0xb7, 0xfa, 0x7e, 0xa3, + 0x10, 0x37, 0xa5, 0x43, 0xcc, 0x77, 0xc3, 0x69, 0xb7, 0x5b, 0x66, 0x5e, + 0x7e, 0x80, 0xf7, 0x6f, 0x06, 0x7c, 0xff, 0x9e, 0x9d, 0x6a, 0x7a, 0x23, + 0xa3, 0x9e, 0xc2, 0xe4, 0x67, 0xc6, 0x48, 0x87, 0x02, 0xb9, 0x52, 0x62, + 0xdc, 0x48, 0xc7, 0x60, 0xa7, 0x98, 0x1f, 0x08, 0x78, 0x34, 0xf7, 0xa3, + 0xae, 0x6f, 0xb3, 0x7c, 0xda, 0xfb, 0x41, 0xfb, 0x5a, 0xdb, 0x95, 0x01, + 0x2d, 0xa4, 0x81, 0x74, 0x15, 0x82, 0x9a, 0xf7, 0xe8, 0xe7, 0x80, 0xea, + 0x27, 0x98, 0x1e, 0x10, 0xfa, 0xd0, 0xfc, 0x14, 0xf5, 0x80, 0xed, 0xd8, + 0x97, 0x67, 0x93, 0xf3, 0x15, 0xbf, 0x8f, 0x42, 0x7d, 0x1f, 0xa0, 0x47, + 0x36, 0x19, 0x76, 0x18, 0x6b, 0xcf, 0xae, 0x0e, 0xe3, 0xdd, 0x97, 0x24, + 0x7b, 0xfa, 0x76, 0x03, 0x73, 0x40, 0xbf, 0xe4, 0xd1, 0x28, 0x6c, 0x36, + 0xf5, 0x2c, 0x22, 0xb9, 0x18, 0xcb, 0x3e, 0xa2, 0xc7, 0x0d, 0x49, 0x46, + 0xe5, 0xbf, 0xd2, 0x52, 0xa3, 0xe3, 0x79, 0x3d, 0x9f, 0x34, 0xe6, 0x43, + 0x1a, 0xfc, 0xb9, 0xa4, 0xeb, 0xe6, 0xe2, 0xf3, 0x9a, 0xbc, 0x30, 0x61, + 0xe3, 0x23, 0xda, 0x87, 0xb0, 0xdd, 0x64, 0xdd, 0xda, 0x4d, 0xa2, 0x0d, + 0x79, 0x8f, 0x3a, 0x6b, 0xfc, 0x0a, 0x7d, 0xca, 0x20, 0xfa, 0x29, 0xce, + 0x1a, 0x92, 0x73, 0xe0, 0xab, 0x9d, 0xb7, 0x69, 0x79, 0xad, 0xc9, 0x52, + 0x78, 0x5d, 0x59, 0x3a, 0x68, 0x78, 0xf6, 0x1a, 0xbe, 0x05, 0xfe, 0x67, + 0x62, 0xd6, 0x4a, 0xf9, 0xb2, 0x54, 0x9c, 0x7a, 0x2b, 0xb2, 0xe4, 0xb7, + 0x8f, 0x40, 0x76, 0xfd, 0x31, 0xd6, 0xd2, 0xec, 0xd7, 0x01, 0x8d, 0xa5, + 0xac, 0xc6, 0x28, 0x1c, 0xc7, 0xf3, 0x0d, 0x73, 0xab, 0x7c, 0xc3, 0x61, + 0xb4, 0x95, 0x40, 0xae, 0xa7, 0x59, 0xf6, 0xcd, 0xfa, 0x7d, 0x1c, 0x56, + 0x32, 0xbb, 0x77, 0xca, 0x32, 0x87, 0x82, 0x92, 0x19, 0x9a, 0x19, 0x90, + 0xc1, 0x6a, 0x07, 0xd6, 0xf4, 0x0d, 0x17, 0xbe, 0xf3, 0xdd, 0x61, 0xb1, + 0x61, 0x17, 0x31, 0xe7, 0x7e, 0xf0, 0xb8, 0x1a, 0x16, 0x23, 0xed, 0x20, + 0xad, 0xc7, 0x58, 0xa1, 0xd0, 0xd0, 0xaa, 0x7c, 0x03, 0xea, 0xa0, 0xef, + 0xfe, 0xb5, 0xf5, 0x20, 0x9f, 0xe0, 0x6d, 0xd6, 0x79, 0xd3, 0x85, 0x1f, + 0xd6, 0x3e, 0x8b, 0xa5, 0xb4, 0x13, 0xbe, 0x8d, 0xf8, 0x10, 0xf4, 0x5b, + 0xe9, 0x42, 0xc1, 0x48, 0xef, 0x47, 0x1f, 0xa2, 0xe4, 0xb4, 0x58, 0x7d, + 0xda, 0xd7, 0x7b, 0x55, 0xbe, 0xa3, 0x9f, 0xb2, 0x37, 0x07, 0x4c, 0xc0, + 0x39, 0x2d, 0x28, 0x5d, 0xcf, 0x99, 0x31, 0x99, 0x2c, 0x29, 0x4c, 0x23, + 0xc9, 0xca, 0x1f, 0x49, 0xee, 0xb4, 0xc8, 0x37, 0xa7, 0x58, 0xef, 0x05, + 0x5d, 0xef, 0x79, 0xd4, 0x4b, 0x26, 0x06, 0x03, 0x16, 0xfc, 0x80, 0x05, + 0x35, 0xe9, 0x4d, 0x20, 0x35, 0x87, 0xf1, 0x1b, 0xa4, 0x93, 0x41, 0x3d, + 0x0f, 0x03, 0x3d, 0x0f, 0x7e, 0x88, 0xdc, 0x53, 0x6a, 0x84, 0x3d, 0xf9, + 0x2f, 0xa0, 0x35, 0x26, 0x5f, 0xc0, 0x3c, 0x2e, 0x4d, 0x11, 0x67, 0xbd, + 0x20, 0x8b, 0x53, 0xc4, 0x5d, 0xcf, 0xcb, 0xe4, 0x54, 0xd2, 0xf9, 0x26, + 0xf8, 0x7c, 0x4a, 0x38, 0x97, 0x5e, 0x07, 0x29, 0x30, 0xa0, 0x95, 0x78, + 0x1c, 0xf6, 0xac, 0x67, 0xab, 0xd7, 0x5f, 0x97, 0xee, 0xcf, 0xae, 0x58, + 0x72, 0xc5, 0xa4, 0x7d, 0xba, 0x56, 0xc7, 0xb3, 0x5a, 0xc7, 0x47, 0x9d, + 0x0e, 0x31, 0xa0, 0xd7, 0x99, 0xb1, 0x02, 0xbc, 0x1f, 0xf5, 0xfa, 0x7f, + 0x1b, 0x35, 0xfc, 0x33, 0x00, 0xac, 0x6a, 0x29, 0x7f, 0xf7, 0xb7, 0xd3, + 0xf1, 0x7a, 0xdd, 0xe6, 0xf8, 0x2d, 0x68, 0x13, 0x42, 0x7a, 0x7d, 0xbd, + 0x46, 0x1f, 0x75, 0x6d, 0x07, 0xa8, 0x17, 0x68, 0xf3, 0x07, 0xe0, 0x05, + 0xf9, 0xff, 0x56, 0xf4, 0xb9, 0x37, 0xf8, 0x96, 0xf4, 0x79, 0xec, 0x7a, + 0xfa, 0x5c, 0xaf, 0xcb, 0x67, 0xc9, 0x0b, 0x8c, 0x2d, 0x33, 0x9e, 0x6c, + 0x75, 0x81, 0xd7, 0x09, 0xc8, 0x29, 0x68, 0x28, 0xfd, 0x8d, 0x9b, 0x09, + 0x79, 0x78, 0xce, 0x93, 0x27, 0xd6, 0xf3, 0xeb, 0x78, 0xb6, 0x77, 0xb0, + 0x7a, 0x45, 0xd9, 0xd9, 0x73, 0xca, 0xce, 0x5a, 0x87, 0x0b, 0x42, 0x79, + 0xbb, 0x2d, 0x48, 0xbe, 0x3f, 0xed, 0x7c, 0x16, 0x34, 0x5a, 0x89, 0x84, + 0xd1, 0x55, 0x30, 0x8c, 0xcf, 0xca, 0xfe, 0xf9, 0x87, 0x65, 0x7f, 0x89, + 0x7d, 0xa4, 0xf1, 0xde, 0x46, 0x59, 0x13, 0x6c, 0x2d, 0x6d, 0xfa, 0x1b, + 0x01, 0x6f, 0x2c, 0x03, 0xfe, 0x6b, 0x29, 0x70, 0x4f, 0xf5, 0x62, 0x20, + 0x3b, 0x4f, 0xdd, 0x45, 0x79, 0xb5, 0xde, 0xe6, 0xfb, 0xf6, 0xbe, 0x66, + 0xff, 0x06, 0x4b, 0x93, 0xc4, 0x80, 0x46, 0xd6, 0xe1, 0x9a, 0x51, 0x37, + 0x2f, 0x98, 0xde, 0x9c, 0x3f, 0x09, 0x3e, 0x51, 0xaf, 0xc9, 0x37, 0xf8, + 0xc0, 0x10, 0x75, 0x96, 0xcf, 0xe2, 0x06, 0xd3, 0xd4, 0x3b, 0x09, 0x05, + 0x41, 0x46, 0x2e, 0xc6, 0x3a, 0x77, 0x80, 0xce, 0xb5, 0x3a, 0xcd, 0x75, + 0x14, 0x6d, 0x43, 0x58, 0x36, 0x80, 0xe7, 0x4e, 0x19, 0x9f, 0xcf, 0x60, + 0xcc, 0x3b, 0x75, 0xdf, 0xab, 0x7c, 0x0c, 0xfa, 0x48, 0xe8, 0xf5, 0xd8, + 0xe0, 0xdb, 0x41, 0x94, 0x39, 0xba, 0xac, 0xa1, 0xae, 0xcc, 0x5f, 0xb7, + 0x8f, 0x62, 0x7c, 0xfa, 0x8a, 0x61, 0x8d, 0x7f, 0x5c, 0x37, 0xc7, 0xf5, + 0xee, 0xfb, 0x87, 0x42, 0xdd, 0xb8, 0x50, 0x2a, 0x98, 0x41, 0x25, 0xa3, + 0x2f, 0xfc, 0x4e, 0x4d, 0x46, 0x81, 0x97, 0x55, 0x2f, 0xe4, 0x31, 0x69, + 0x69, 0x06, 0x4f, 0x07, 0x41, 0x2b, 0x78, 0xd7, 0x1e, 0x00, 0xff, 0x9a, + 0x25, 0x5f, 0x4d, 0xeb, 0x77, 0x2c, 0x0f, 0xc9, 0x68, 0xcc, 0xf7, 0x47, + 0xb7, 0x99, 0x1e, 0xe6, 0x45, 0x9d, 0xd2, 0x8f, 0x83, 0x9e, 0x0e, 0x98, + 0x92, 0x3f, 0x39, 0x08, 0x59, 0x23, 0x26, 0x6b, 0x80, 0xac, 0xc5, 0x94, + 0xad, 0x37, 0x6c, 0xd6, 0xc7, 0xbb, 0xd3, 0xbf, 0x17, 0xf4, 0xda, 0xb0, + 0x9e, 0xdf, 0xc6, 0x1f, 0xbb, 0x6d, 0xa5, 0xed, 0xa8, 0x63, 0x48, 0x50, + 0x8d, 0x8f, 0xb2, 0xd3, 0xab, 0xc7, 0x37, 0xda, 0xfd, 0xf1, 0x1f, 0xd1, + 0x7d, 0xb5, 0xd5, 0xf5, 0x15, 0xbb, 0xce, 0xf8, 0x78, 0x77, 0xfa, 0xa3, + 0x9b, 0xbd, 0x36, 0xb1, 0xba, 0x36, 0xed, 0x6b, 0xda, 0xb0, 0xbe, 0x3f, + 0x06, 0xde, 0x9d, 0xbe, 0xab, 0xd9, 0x6b, 0xc3, 0x7a, 0x0d, 0xf0, 0x6d, + 0x7c, 0x47, 0xd9, 0xdf, 0x5f, 0x27, 0xfb, 0xfb, 0x21, 0xfb, 0xbe, 0x4c, + 0xad, 0xc5, 0xc9, 0x7e, 0xbc, 0xc3, 0x38, 0x87, 0xd8, 0xaa, 0x16, 0xd7, + 0x84, 0x4e, 0x34, 0x03, 0xb7, 0xb4, 0x30, 0x96, 0xd1, 0xb8, 0x98, 0xb1, + 0x0d, 0x71, 0xb0, 0xd8, 0x21, 0xe9, 0x82, 0x8d, 0xea, 0x8a, 0xef, 0xa3, + 0xc2, 0x55, 0x62, 0x0a, 0x2f, 0x67, 0xf4, 0x18, 0x8c, 0x6b, 0xc8, 0x77, + 0xe6, 0x73, 0x2b, 0x71, 0x4e, 0x07, 0xe2, 0x20, 0xe2, 0x5d, 0xe2, 0x25, + 0x9f, 0x7e, 0x9f, 0x9e, 0x03, 0x46, 0x4d, 0x27, 0x32, 0xc6, 0x60, 0x75, + 0xd0, 0xf0, 0x74, 0x82, 0xef, 0x0f, 0x68, 0x9f, 0xb6, 0x96, 0xde, 0xb7, + 0xaf, 0xa1, 0x97, 0xb8, 0x2a, 0x21, 0x13, 0x90, 0x91, 0xd0, 0x09, 0xda, + 0xd8, 0xe7, 0x46, 0x16, 0x67, 0x89, 0x1f, 0xfa, 0xc0, 0x17, 0xd2, 0x4b, + 0xfe, 0x51, 0x97, 0x5b, 0x60, 0x1f, 0xba, 0x52, 0x65, 0xd4, 0x67, 0x7c, + 0x3d, 0xae, 0xe2, 0xb2, 0x66, 0xa4, 0x08, 0x9e, 0x40, 0xeb, 0x38, 0x68, + 0x1d, 0xd7, 0x31, 0xd9, 0x3e, 0xd8, 0xef, 0xd0, 0xb4, 0x4f, 0xeb, 0x8d, + 0x21, 0x7f, 0x6d, 0x56, 0xd3, 0x5e, 0xef, 0x77, 0x3c, 0xfc, 0x75, 0x4f, + 0x0f, 0x65, 0xc6, 0x2a, 0x10, 0xb3, 0x8d, 0x2b, 0xf9, 0x00, 0xf6, 0x33, + 0xc4, 0xd3, 0xa5, 0x16, 0xdf, 0xff, 0x72, 0x3e, 0xf4, 0xff, 0xd4, 0x79, + 0x7f, 0x0e, 0xcd, 0xd2, 0x79, 0x82, 0x73, 0x58, 0xa1, 0x3f, 0xc6, 0xdd, + 0x8d, 0xfd, 0xb0, 0x9b, 0x79, 0x45, 0xeb, 0x4e, 0xd9, 0x5b, 0x7a, 0xa7, + 0xa6, 0xbf, 0x19, 0xf4, 0x8f, 0x42, 0xb6, 0x6b, 0x36, 0x23, 0x5f, 0x19, + 0x43, 0xde, 0xc3, 0x62, 0xe4, 0x71, 0xbe, 0x42, 0xfb, 0xa1, 0xe7, 0x13, + 0xe5, 0x7c, 0xd6, 0xda, 0x96, 0xf5, 0xf8, 0xfa, 0x8e, 0x35, 0x7c, 0x15, + 0xcd, 0xd7, 0x88, 0x34, 0x9c, 0x50, 0x71, 0x2d, 0xfa, 0x25, 0xaf, 0xe9, + 0xbf, 0x9e, 0x1b, 0x99, 0x9c, 0x95, 0xbe, 0xb0, 0x90, 0xbe, 0x38, 0xcb, + 0xfa, 0x1b, 0xa4, 0xcb, 0xb9, 0x88, 0x79, 0xe7, 0xb1, 0xde, 0xc6, 0xb4, + 0x27, 0xdf, 0xe4, 0x6f, 0xbe, 0x12, 0x45, 0x2c, 0xcd, 0xb1, 0xc9, 0x33, + 0xd2, 0x6f, 0x2a, 0x7a, 0x56, 0xf8, 0x0d, 0xfa, 0x3e, 0x56, 0x59, 0xcb, + 0xdb, 0x7a, 0x3b, 0xe3, 0xc7, 0xec, 0xdf, 0x35, 0x3d, 0xbd, 0x58, 0x2f, + 0x66, 0x6f, 0x86, 0x7d, 0x0c, 0xd1, 0x36, 0x82, 0xf7, 0xdc, 0x5f, 0x59, + 0x0a, 0x11, 0x83, 0x5f, 0x28, 0x85, 0x95, 0xcd, 0xcb, 0x3a, 0x2d, 0x5a, + 0x3f, 0x6e, 0xd3, 0xbe, 0x23, 0xac, 0x6c, 0xb6, 0x18, 0x26, 0x71, 0x09, + 0xca, 0x90, 0x9f, 0x67, 0xde, 0xa7, 0xe3, 0xde, 0x5d, 0x61, 0xfb, 0x0f, + 0x43, 0xbe, 0x4d, 0xa8, 0xd1, 0x55, 0x1f, 0x93, 0xbb, 0xc0, 0x72, 0xef, + 0x84, 0xdc, 0xde, 0x89, 0xb8, 0x3b, 0x21, 0xf9, 0x14, 0xf5, 0x68, 0x40, + 0xc5, 0x26, 0x86, 0xbd, 0x0f, 0x65, 0x4d, 0x28, 0x83, 0x13, 0x33, 0x31, + 0x7f, 0xfb, 0x77, 0x65, 0x1c, 0x32, 0x9e, 0x4f, 0xf5, 0x82, 0x0e, 0xda, + 0x60, 0x60, 0x1c, 0x3b, 0xc5, 0xb8, 0x1d, 0x7f, 0xfd, 0x61, 0x6f, 0x5e, + 0xbb, 0x90, 0x47, 0x0c, 0x9f, 0xea, 0xd4, 0x75, 0x36, 0x08, 0xf7, 0x7f, + 0xf2, 0x66, 0x0b, 0xd2, 0xee, 0x35, 0x75, 0xdf, 0x8f, 0xfc, 0x7b, 0x75, + 0xff, 0x05, 0xbc, 0xdf, 0x86, 0xdf, 0x20, 0xca, 0x6e, 0x47, 0x99, 0x83, + 0xb2, 0xf7, 0x20, 0xff, 0x7e, 0xbd, 0x1f, 0xe0, 0xb7, 0x69, 0x41, 0xfe, + 0x31, 0xbc, 0x87, 0xad, 0x30, 0x5f, 0xc6, 0xfb, 0xf7, 0xe2, 0xf7, 0xee, + 0x35, 0x75, 0xda, 0xd6, 0xe4, 0x3f, 0xb5, 0xc2, 0x83, 0x0b, 0xa5, 0x9f, + 0x69, 0xbb, 0x46, 0x79, 0x66, 0xfe, 0x94, 0x7e, 0xf7, 0xce, 0xd0, 0xea, + 0xf2, 0x1d, 0x7e, 0xbe, 0x6e, 0x0d, 0x3b, 0xb1, 0x86, 0x3e, 0xc6, 0x7c, + 0xbb, 0xf6, 0x5d, 0x6f, 0xf7, 0xe2, 0xf4, 0x92, 0xdf, 0x8e, 0x7e, 0xed, + 0xce, 0x35, 0x63, 0x3c, 0xdf, 0x50, 0xcb, 0x37, 0x07, 0x86, 0x4e, 0xb2, + 0xec, 0x72, 0xc3, 0xea, 0x3a, 0x6f, 0xd6, 0xe5, 0x37, 0x06, 0x86, 0x94, + 0x8f, 0xbb, 0xab, 0x71, 0x75, 0x9d, 0x64, 0x63, 0x6d, 0x1e, 0x35, 0x5b, + 0x18, 0x4a, 0x2f, 0x53, 0x8e, 0xa1, 0x0b, 0xdf, 0x1a, 0xc9, 0x4e, 0xb9, + 0xee, 0x84, 0xb3, 0x14, 0x0f, 0x0a, 0x7d, 0x10, 0xb1, 0x2a, 0xcb, 0x5f, + 0x46, 0x39, 0xb0, 0x4c, 0x75, 0x54, 0x68, 0x93, 0xd6, 0xc7, 0xa4, 0x09, + 0x8d, 0x49, 0x55, 0x36, 0x94, 0x55, 0x18, 0xf2, 0xf9, 0x11, 0x60, 0x1e, + 0xfd, 0xfc, 0x02, 0x9e, 0x13, 0xf5, 0xb8, 0x17, 0xfd, 0x2e, 0x8d, 0x64, + 0x67, 0xe9, 0xf3, 0x2e, 0x8e, 0xec, 0x99, 0xa5, 0xce, 0x5f, 0x82, 0xce, + 0x07, 0x64, 0x52, 0xf9, 0x3f, 0xd2, 0xc1, 0x76, 0x4b, 0x23, 0x9d, 0x0b, + 0x4c, 0x97, 0x47, 0xec, 0x85, 0xa0, 0xec, 0x8b, 0x79, 0x6d, 0x99, 0x4f, + 0x2c, 0xf8, 0x3a, 0x10, 0x95, 0x70, 0x9a, 0x32, 0x69, 0xa5, 0x80, 0xbd, + 0x31, 0x9f, 0x27, 0x47, 0x26, 0x6d, 0xca, 0xe7, 0x87, 0x1a, 0xa4, 0x25, + 0x2a, 0x0d, 0xca, 0xde, 0x3c, 0xa5, 0xc7, 0xba, 0x84, 0xb1, 0x36, 0x29, + 0x7d, 0xca, 0xda, 0xa1, 0x38, 0xc6, 0x39, 0x68, 0xd8, 0xbd, 0x18, 0x8f, + 0x91, 0x72, 0x87, 0x4c, 0x54, 0xa9, 0x37, 0xdb, 0xc2, 0xb5, 0xf8, 0xf8, + 0x3c, 0xda, 0xf9, 0x71, 0x19, 0xc7, 0x2b, 0x03, 0x97, 0x41, 0x96, 0xd3, + 0x96, 0x99, 0x0d, 0xc2, 0xcf, 0xcf, 0xfa, 0x75, 0x48, 0xd3, 0xd9, 0x91, + 0xe4, 0x42, 0x12, 0x7d, 0x75, 0xd0, 0x86, 0xc1, 0x76, 0x05, 0xf1, 0x63, + 0xdf, 0x6c, 0x07, 0x5f, 0x34, 0x40, 0x3f, 0x72, 0x1e, 0x7e, 0xa4, 0x43, + 0x0e, 0x95, 0x54, 0x1f, 0x09, 0xf6, 0x51, 0xd4, 0x6d, 0x3b, 0x17, 0x1a, + 0x10, 0xdb, 0x24, 0xcd, 0x17, 0xa5, 0xd6, 0x76, 0x48, 0xbc, 0x76, 0x5e, + 0xdf, 0x3f, 0x77, 0x33, 0xb1, 0x7a, 0xdd, 0x8f, 0x4a, 0x10, 0x74, 0xe4, + 0xd0, 0x07, 0xc7, 0xaf, 0xf5, 0xed, 0xf7, 0x97, 0x34, 0x97, 0xaf, 0xe9, + 0x6b, 0x93, 0x8e, 0xb9, 0xac, 0x44, 0xee, 0xd7, 0x1a, 0x5b, 0xc5, 0x00, + 0x90, 0x07, 0x09, 0xe5, 0x7a, 0x60, 0x17, 0xab, 0x03, 0x5a, 0x46, 0x5e, + 0x40, 0x59, 0x7d, 0x6c, 0xe3, 0xc9, 0x57, 0x01, 0x98, 0xae, 0x08, 0x3d, + 0x0f, 0xa6, 0x33, 0xad, 0xde, 0x5e, 0xd3, 0xf5, 0xe2, 0x19, 0xc8, 0x0d, + 0xfa, 0x2c, 0xae, 0xb4, 0xe5, 0x9c, 0x5e, 0x18, 0xb9, 0x34, 0x15, 0xc7, + 0x9c, 0x3c, 0xbf, 0xe0, 0xf1, 0x9a, 0x3e, 0x27, 0x20, 0x8b, 0x76, 0x02, + 0x71, 0x33, 0x7d, 0x7c, 0x42, 0x5e, 0xb2, 0x7d, 0xff, 0x43, 0x5f, 0x84, + 0xfa, 0x55, 0xd2, 0x46, 0xda, 0xcf, 0x63, 0x6e, 0xae, 0xcc, 0x38, 0x9e, + 0x0c, 0xf6, 0xc0, 0x8f, 0x7c, 0x23, 0x64, 0x1d, 0x66, 0x7c, 0x75, 0x25, + 0x54, 0x3f, 0x1f, 0x1f, 0x2b, 0x3c, 0xaf, 0xf7, 0x7e, 0xcf, 0x6b, 0x79, + 0x59, 0x82, 0xbc, 0xf4, 0x26, 0x4c, 0xe9, 0x06, 0xed, 0xa8, 0xd3, 0xd7, + 0x85, 0x38, 0x87, 0x31, 0x74, 0x1c, 0xf4, 0x98, 0xb0, 0x1d, 0x9b, 0x34, + 0x66, 0xff, 0x77, 0x61, 0xfa, 0xb6, 0x56, 0xb5, 0xaf, 0x7c, 0x5e, 0xc9, + 0xb3, 0x27, 0xdf, 0x41, 0xfd, 0xde, 0x97, 0xa9, 0x20, 0x21, 0x8d, 0xd4, + 0xf6, 0x4f, 0x59, 0xff, 0x39, 0x5d, 0xff, 0x59, 0xd4, 0x0f, 0x60, 0x4e, + 0xae, 0xbb, 0x57, 0xd1, 0xfb, 0x1c, 0xf8, 0x1e, 0x94, 0xe2, 0x8a, 0xcc, + 0x3f, 0x07, 0x99, 0xa7, 0x7c, 0x9f, 0x87, 0xbe, 0x82, 0xf8, 0x7b, 0x29, + 0xf7, 0x65, 0x19, 0x3c, 0x9d, 0x6b, 0xe0, 0x5e, 0x67, 0xc2, 0x60, 0xec, + 0x49, 0x99, 0xec, 0x90, 0xc7, 0x4b, 0x49, 0x73, 0xa2, 0x6e, 0x2d, 0x77, + 0xac, 0x5a, 0x4b, 0xca, 0x80, 0xaa, 0x9f, 0x62, 0xfd, 0x72, 0x9d, 0x0c, + 0xcc, 0xcf, 0x5e, 0xaf, 0x1d, 0x65, 0x80, 0xed, 0xd6, 0xc3, 0xe9, 0xdc, + 0x1b, 0x74, 0xdd, 0x45, 0x87, 0xfb, 0xb8, 0x8d, 0x52, 0x50, 0x32, 0x16, + 0x90, 0xa2, 0x43, 0xbd, 0xca, 0x26, 0x42, 0x62, 0x01, 0x2b, 0x7d, 0x10, + 0x74, 0x66, 0x52, 0x61, 0xf1, 0xf6, 0x12, 0xc6, 0xb1, 0x06, 0x4b, 0xa6, + 0xeb, 0x5e, 0xb2, 0x45, 0xca, 0x88, 0x3d, 0x17, 0x91, 0x16, 0x2b, 0xd0, + 0xd9, 0x68, 0x08, 0x36, 0xc0, 0x97, 0xf1, 0x88, 0xcc, 0xa1, 0xce, 0x3c, + 0xde, 0x3d, 0x5e, 0xf1, 0x25, 0xc6, 0x75, 0x0d, 0xf0, 0x68, 0x8f, 0xfd, + 0xff, 0xdc, 0x7c, 0xac, 0xbe, 0xae, 0x8f, 0x89, 0x89, 0x65, 0x89, 0x4d, + 0x89, 0x29, 0xf9, 0x8e, 0x38, 0xf1, 0x20, 0x68, 0xa1, 0xce, 0xb6, 0x48, + 0x24, 0x6d, 0xc5, 0x87, 0xc5, 0xf7, 0xfd, 0x97, 0x21, 0x4b, 0x05, 0xb7, + 0xd1, 0xee, 0x90, 0x67, 0x20, 0x37, 0xe7, 0x57, 0x70, 0x4c, 0x02, 0x72, + 0x44, 0x3f, 0xea, 0xca, 0x39, 0xc7, 0x4e, 0x7c, 0x0e, 0xe9, 0xb7, 0x9d, + 0xdf, 0x22, 0xdf, 0x9e, 0x10, 0xe9, 0x43, 0x2c, 0x04, 0xbb, 0x3e, 0xe3, + 0x63, 0xfb, 0x16, 0xc6, 0x64, 0x5a, 0x96, 0xae, 0xa0, 0x4f, 0xcb, 0x34, + 0x00, 0x6a, 0xef, 0x42, 0x3d, 0x4f, 0x37, 0xfc, 0xb2, 0x83, 0xa8, 0x4b, + 0x1a, 0x18, 0x2f, 0x7f, 0x07, 0x3a, 0xeb, 0xba, 0xf7, 0x39, 0x8b, 0x75, + 0xb6, 0xe6, 0x39, 0xac, 0xbf, 0x92, 0xf3, 0xfe, 0x56, 0xe1, 0xfe, 0xaa, + 0xf4, 0xb5, 0xa9, 0x78, 0x8e, 0xcf, 0x90, 0xf7, 0x7e, 0x62, 0xa1, 0x84, + 0xc2, 0x9a, 0xc4, 0x0d, 0xe7, 0xc1, 0xfb, 0x4f, 0x2a, 0x4c, 0x43, 0xfc, + 0x06, 0xfa, 0x4b, 0xc4, 0x14, 0x1e, 0x96, 0xf6, 0x70, 0x1d, 0xb1, 0x45, + 0x0a, 0x6b, 0xe3, 0xe3, 0x0b, 0xb6, 0x65, 0x3d, 0xb6, 0xad, 0x5f, 0x3f, + 0xd6, 0xd9, 0x14, 0xc8, 0x1d, 0xa3, 0x3c, 0xd3, 0x3f, 0xb6, 0xca, 0xbe, + 0x54, 0x23, 0xf8, 0xde, 0xa6, 0xfd, 0xf8, 0xfb, 0x80, 0xd9, 0x80, 0xbd, + 0x4d, 0xcb, 0xa9, 0xd9, 0x9e, 0xf7, 0xa0, 0xec, 0x17, 0xe0, 0x3f, 0xcb, + 0xf6, 0x37, 0x78, 0x7e, 0xf2, 0x61, 0xe8, 0xf2, 0xdc, 0x26, 0x6f, 0xef, + 0x8a, 0xeb, 0xe0, 0xe3, 0x04, 0x1f, 0xf7, 0x99, 0x1a, 0xef, 0x73, 0x6d, + 0xbc, 0x7d, 0x2e, 0x43, 0xd5, 0x65, 0xac, 0x55, 0x1f, 0x5b, 0x52, 0x87, + 0x5d, 0xf7, 0x9c, 0xe3, 0xe3, 0xc8, 0xed, 0xf0, 0xa1, 0x21, 0xcd, 0xeb, + 0x66, 0xf0, 0x9a, 0x18, 0x25, 0x22, 0x89, 0x36, 0x62, 0x8a, 0x07, 0x1b, + 0x6a, 0x58, 0xe6, 0x6f, 0xdc, 0xa0, 0xcd, 0x78, 0x8f, 0x38, 0x86, 0xb4, + 0x6f, 0xd7, 0x78, 0x86, 0xd8, 0xe6, 0x31, 0x8c, 0x11, 0x94, 0x44, 0x3b, + 0xf3, 0x7f, 0xa9, 0xdb, 0xf0, 0xd9, 0x95, 0xee, 0xad, 0xf5, 0xf2, 0x3c, + 0x00, 0x3a, 0x39, 0x1f, 0x7f, 0xef, 0xb5, 0x43, 0xd9, 0x93, 0x9a, 0x5c, + 0xf8, 0x34, 0xf9, 0xe3, 0x92, 0xb6, 0xb8, 0xb4, 0x81, 0xb6, 0x7b, 0xe0, + 0x53, 0xb6, 0xb6, 0xb1, 0x4f, 0x7f, 0xec, 0x7a, 0x9a, 0xea, 0xf1, 0x55, + 0x02, 0x63, 0x34, 0xca, 0xd6, 0x76, 0xf2, 0xae, 0x43, 0xf9, 0x96, 0xda, + 0x7a, 0xd0, 0xf7, 0x73, 0xec, 0xb5, 0xe5, 0xef, 0xad, 0xa3, 0x6b, 0x2d, + 0xe6, 0xdb, 0x86, 0x77, 0xa4, 0xc9, 0x84, 0x5d, 0x72, 0x65, 0x87, 0xe3, + 0xe3, 0xbb, 0x7a, 0x3a, 0x88, 0xf1, 0x48, 0x33, 0x69, 0xf0, 0x31, 0x39, + 0x7f, 0x5c, 0x1b, 0xd2, 0x93, 0xd6, 0xe7, 0x44, 0xfb, 0xf5, 0xbc, 0x6e, + 0xd3, 0x75, 0x92, 0x68, 0xfb, 0xc7, 0x98, 0x03, 0x9f, 0x39, 0x0f, 0x1f, + 0x1b, 0x26, 0xbd, 0x7e, 0xa2, 0xeb, 0xc5, 0x00, 0xd4, 0x19, 0x9f, 0x4f, + 0x6d, 0x7a, 0x8d, 0xb6, 0xaf, 0x19, 0xd7, 0x72, 0x56, 0xdb, 0x91, 0xf7, + 0xd4, 0xcd, 0xaf, 0x4f, 0x0a, 0xf3, 0x94, 0x8b, 0x77, 0x21, 0xf5, 0x63, + 0xa3, 0x7e, 0xf8, 0x91, 0x0c, 0x62, 0x21, 0xc6, 0x48, 0xd7, 0xc4, 0x47, + 0x3c, 0x47, 0x1c, 0xcb, 0x23, 0x5e, 0x56, 0x7e, 0xc4, 0xf3, 0x91, 0xc8, + 0xc3, 0x9e, 0x54, 0xef, 0xa5, 0x8c, 0x8d, 0x8d, 0x57, 0x9c, 0xb1, 0xbd, + 0x95, 0xfe, 0x31, 0xc6, 0x11, 0x9e, 0xcc, 0xa1, 0x7e, 0x45, 0xc6, 0x0d, + 0xb4, 0xcb, 0xaa, 0x76, 0x6a, 0x1f, 0x68, 0x9d, 0x7e, 0x84, 0xfa, 0x38, + 0xee, 0x8d, 0x15, 0x19, 0xcb, 0xc1, 0x06, 0xcd, 0xcf, 0xc0, 0xc7, 0xd9, + 0x56, 0x86, 0x72, 0xb9, 0xc7, 0xb1, 0x86, 0x95, 0xec, 0xc5, 0xac, 0x51, + 0xae, 0x65, 0x79, 0xe6, 0x1d, 0xb0, 0xa1, 0xae, 0xdc, 0x0d, 0x5b, 0xf8, + 0x10, 0x64, 0x55, 0xce, 0xc0, 0x10, 0x9e, 0x81, 0xf1, 0x3a, 0x13, 0x13, + 0xe3, 0x78, 0x87, 0x84, 0x8f, 0xc4, 0x25, 0x74, 0x84, 0xb1, 0x58, 0xd2, + 0xbc, 0x5b, 0x04, 0x3e, 0xf1, 0xc5, 0xdb, 0x0d, 0xb1, 0x06, 0x32, 0x92, + 0x44, 0x3c, 0xd9, 0x6b, 0x96, 0x91, 0x16, 0x25, 0x99, 0x3a, 0x8d, 0xbe, + 0xc2, 0x67, 0x50, 0x17, 0xed, 0x9a, 0x16, 0x13, 0xf8, 0xb5, 0x4b, 0x74, + 0xd1, 0xd3, 0x95, 0xe8, 0xe2, 0xea, 0x3d, 0x94, 0xc1, 0x95, 0x3d, 0x14, + 0xbe, 0x7f, 0x43, 0xef, 0xfd, 0x3c, 0xab, 0xe3, 0x1a, 0xca, 0x08, 0x7d, + 0x9b, 0x8a, 0xcd, 0x60, 0xc7, 0x9f, 0x45, 0x2c, 0x6c, 0x4b, 0xae, 0x04, + 0xcc, 0x9e, 0x76, 0xe5, 0x29, 0xa7, 0xe0, 0x66, 0xfb, 0x5d, 0xb9, 0xec, + 0xd8, 0x85, 0xbc, 0x58, 0x6f, 0xd0, 0xde, 0xfd, 0x4f, 0xe7, 0xfd, 0xb2, + 0xab, 0xd5, 0xda, 0x95, 0x09, 0x14, 0xdc, 0x66, 0x3b, 0x2a, 0x37, 0xa5, + 0x0f, 0xca, 0x9e, 0x2d, 0x4b, 0x66, 0x50, 0x32, 0x37, 0x01, 0x17, 0xc6, + 0xf3, 0xca, 0x56, 0xbd, 0xa6, 0xe2, 0xeb, 0x07, 0xba, 0x0e, 0xca, 0xc6, + 0x2d, 0x96, 0x79, 0x35, 0x48, 0xcc, 0x76, 0x10, 0xb1, 0x80, 0x15, 0xcf, + 0x05, 0x6d, 0x73, 0xa7, 0x58, 0xc3, 0x9f, 0x16, 0x9e, 0xdb, 0xda, 0xd2, + 0x79, 0xc4, 0x8e, 0x7f, 0x22, 0xd0, 0xbd, 0xff, 0x13, 0x8c, 0xef, 0xce, + 0x30, 0xef, 0x4a, 0x64, 0x8b, 0x89, 0xe7, 0x98, 0x74, 0x1e, 0x4f, 0x48, + 0x12, 0x7c, 0xe9, 0x51, 0x3c, 0xe1, 0xf9, 0x51, 0x5c, 0xba, 0x8f, 0x10, + 0x43, 0x29, 0xde, 0xf4, 0x80, 0x37, 0x29, 0xf0, 0x06, 0x31, 0x55, 0xaf, + 0x79, 0x15, 0xe9, 0xb2, 0x24, 0x07, 0x7e, 0x00, 0xde, 0xf4, 0x80, 0x37, + 0xdd, 0x67, 0x12, 0x68, 0x8f, 0x3e, 0x16, 0x3b, 0x91, 0x46, 0xe5, 0x83, + 0x37, 0xb4, 0xe3, 0xd9, 0x96, 0xe4, 0x91, 0x08, 0xc6, 0x08, 0xc8, 0x8e, + 0xae, 0x82, 0x0c, 0x6d, 0x41, 0x6c, 0x16, 0x3b, 0x28, 0x17, 0xe1, 0x87, + 0x4a, 0x88, 0x11, 0x9e, 0x1a, 0xb0, 0x46, 0x97, 0x60, 0x4b, 0xab, 0xf7, + 0xb8, 0xf2, 0xf2, 0x96, 0xbf, 0x70, 0xe3, 0x37, 0x58, 0xbb, 0x24, 0xd0, + 0x2f, 0x93, 0x25, 0xe5, 0x1f, 0xe2, 0xd9, 0xa0, 0xc2, 0x65, 0x98, 0x63, + 0x01, 0x3e, 0x86, 0xe7, 0xd1, 0x36, 0x6c, 0xfd, 0xa7, 0xe5, 0xa1, 0xb9, + 0x09, 0xfc, 0x10, 0x6f, 0x4e, 0xb1, 0xee, 0x7e, 0xc4, 0x73, 0x0f, 0xcb, + 0xbe, 0x29, 0x60, 0xc7, 0x34, 0xe8, 0xee, 0xb7, 0x11, 0xcf, 0xcd, 0x37, + 0x4a, 0x0b, 0xca, 0xc0, 0xdb, 0xd1, 0xea, 0xda, 0x38, 0x6e, 0x09, 0xeb, + 0x30, 0x20, 0x7f, 0x56, 0xed, 0x97, 0xaf, 0x55, 0xfb, 0xe4, 0x4f, 0xe0, + 0x5b, 0xce, 0x57, 0x3b, 0xa0, 0x2b, 0x71, 0xac, 0x49, 0x1a, 0xeb, 0xe3, + 0xc8, 0x73, 0xd5, 0x94, 0x3c, 0x0b, 0x5e, 0x3d, 0x83, 0xdf, 0x50, 0x29, + 0x25, 0x3b, 0x4a, 0x7d, 0x7a, 0x8d, 0xb8, 0x3e, 0x36, 0xe8, 0xb1, 0x31, + 0x77, 0xeb, 0xc9, 0x02, 0xf4, 0x6f, 0xbe, 0x6a, 0xbf, 0x5e, 0x96, 0x8f, + 0x37, 0x72, 0x8f, 0xf7, 0xd4, 0x8a, 0x7f, 0x29, 0xb8, 0xa6, 0x6d, 0x1d, + 0x1e, 0xc7, 0x3a, 0x94, 0xa1, 0xa7, 0xa3, 0x8a, 0xf7, 0x35, 0xdf, 0x53, + 0xf6, 0x7c, 0x8f, 0x3f, 0xbf, 0x99, 0xbc, 0x7c, 0x5b, 0xb2, 0x47, 0x27, + 0x65, 0xcf, 0x31, 0x57, 0x3e, 0xec, 0xb8, 0x90, 0x63, 0xda, 0xe2, 0x7e, + 0xda, 0xf8, 0xc4, 0x78, 0xd0, 0x50, 0xb1, 0x94, 0x87, 0x5b, 0x7a, 0x37, + 0x43, 0x67, 0x53, 0x19, 0x63, 0x42, 0x92, 0x47, 0x27, 0xa4, 0xf3, 0x28, + 0x64, 0xc1, 0x61, 0x5f, 0x4b, 0xa6, 0x71, 0x8d, 0x3c, 0x70, 0x1c, 0x6b, + 0x20, 0x27, 0xb6, 0xf9, 0xba, 0xa4, 0x30, 0xfe, 0x01, 0xe9, 0x42, 0x1b, + 0x1b, 0x6d, 0xae, 0xaa, 0xb1, 0x9b, 0x31, 0x76, 0xa3, 0x1c, 0x8a, 0x59, + 0x90, 0x35, 0xfa, 0xf0, 0xff, 0x25, 0xd9, 0x32, 0xd3, 0x9f, 0x4a, 0xf6, + 0xd4, 0x47, 0x23, 0x12, 0xe5, 0x33, 0x4c, 0xc3, 0x09, 0x96, 0x77, 0x22, + 0x65, 0xb9, 0x8d, 0x38, 0xfa, 0xe7, 0x92, 0x3d, 0xcb, 0xb1, 0x5f, 0x47, + 0xf9, 0xcb, 0x92, 0x9d, 0xfe, 0x05, 0xf2, 0x17, 0x91, 0xbe, 0x81, 0x74, + 0x54, 0x3a, 0xa7, 0x25, 0x90, 0x3d, 0xfb, 0x2d, 0xe4, 0x43, 0x48, 0x0f, + 0xa1, 0xde, 0x76, 0xd0, 0xf7, 0xa7, 0xe8, 0x2f, 0x03, 0x9b, 0xf7, 0x3b, + 0x9a, 0x7e, 0x96, 0xb3, 0x8c, 0xef, 0x0e, 0xc1, 0xa6, 0xfd, 0x67, 0xd8, + 0x34, 0xfd, 0x3c, 0xcf, 0x3c, 0x6d, 0x1b, 0x9f, 0x27, 0xc0, 0x93, 0x03, + 0xc8, 0xbb, 0xf2, 0xb0, 0x43, 0x7f, 0xb3, 0x4d, 0xc6, 0xcc, 0x82, 0x1b, + 0x05, 0xae, 0x68, 0x86, 0x1e, 0x4c, 0x6c, 0x5d, 0x5f, 0x0f, 0x0e, 0x77, + 0x1f, 0x94, 0xa6, 0x2d, 0xfe, 0xfc, 0xfd, 0xf9, 0xda, 0xe6, 0x4f, 0x14, + 0x1f, 0xac, 0xc2, 0x27, 0x84, 0xf3, 0xb0, 0xe3, 0x5f, 0x30, 0xba, 0x77, + 0x3d, 0x04, 0x3d, 0x30, 0xce, 0x32, 0xef, 0xe9, 0x81, 0x71, 0x16, 0xb6, + 0xe1, 0x04, 0x62, 0xc4, 0x13, 0x1d, 0xd2, 0x38, 0x5d, 0xd3, 0x83, 0x86, + 0xe9, 0x5f, 0xad, 0x07, 0x8d, 0x67, 0x51, 0xef, 0x2c, 0x79, 0x86, 0x3e, + 0x4e, 0x91, 0x67, 0xed, 0x48, 0x3f, 0x8d, 0xb9, 0x92, 0xf6, 0x46, 0xd0, + 0xee, 0xe1, 0xa2, 0xdb, 0x21, 0xef, 0x0f, 0x6c, 0x39, 0xa0, 0xcb, 0xff, + 0xd2, 0x1d, 0x8e, 0x59, 0x73, 0x12, 0x20, 0x4f, 0x51, 0xb7, 0x4c, 0x1e, + 0xde, 0xdc, 0x24, 0xd1, 0xfd, 0xd2, 0x49, 0xfe, 0x95, 0x77, 0x22, 0x5f, + 0x70, 0xc3, 0x76, 0xb3, 0xe6, 0x27, 0x70, 0x52, 0x3f, 0xcb, 0x5f, 0x85, + 0xcc, 0x10, 0xaf, 0xbe, 0x26, 0x7b, 0xa6, 0x5c, 0x19, 0x73, 0x38, 0xff, + 0xef, 0x63, 0xfe, 0x99, 0x2d, 0x31, 0x59, 0x4a, 0xc4, 0xc0, 0x93, 0x79, + 0xd8, 0xf6, 0x8b, 0xe2, 0xf1, 0x81, 0xe7, 0x02, 0x3b, 0xc4, 0x8e, 0x0f, + 0x89, 0x9d, 0xfa, 0x01, 0xf8, 0x30, 0x04, 0xd9, 0xcf, 0x55, 0x29, 0x3b, + 0xaf, 0xc8, 0x20, 0x64, 0xe2, 0x7b, 0x8e, 0x95, 0x02, 0x16, 0x82, 0xbd, + 0xa0, 0x5c, 0x50, 0x26, 0x5a, 0x94, 0x4d, 0x3a, 0xe1, 0x58, 0x4f, 0x94, + 0xe5, 0x56, 0x39, 0xd1, 0x46, 0xda, 0xf1, 0x6e, 0x5a, 0xf9, 0x8b, 0xd4, + 0xb8, 0xd1, 0x05, 0x1b, 0x9d, 0x12, 0xb3, 0xbb, 0xd8, 0xe8, 0xdf, 0x21, + 0xc9, 0x1f, 0x0d, 0xc8, 0x44, 0x37, 0xd7, 0x8a, 0xfd, 0x22, 0x5f, 0x2e, + 0xb8, 0x21, 0xfb, 0x75, 0xf7, 0x64, 0x7b, 0x42, 0x3e, 0xd9, 0xbd, 0x22, + 0x97, 0x73, 0x22, 0x9e, 0x5e, 0x0c, 0xaa, 0xf5, 0xf0, 0xe9, 0xf6, 0xe7, + 0xe2, 0xbf, 0xeb, 0xab, 0x7b, 0xc7, 0xb9, 0x50, 0xd6, 0x57, 0x74, 0x27, + 0x71, 0x2d, 0xad, 0xaf, 0x41, 0x9e, 0xac, 0x27, 0x8a, 0x72, 0x19, 0xb2, + 0x07, 0x1e, 0x9e, 0x65, 0x4a, 0x1e, 0x4e, 0x40, 0xee, 0x5f, 0x95, 0x1d, + 0x47, 0xa9, 0x33, 0xaf, 0x62, 0xae, 0xca, 0x96, 0xc0, 0x46, 0xb0, 0x3f, + 0x57, 0x26, 0x9d, 0xae, 0xd4, 0x29, 0xb9, 0x35, 0xbe, 0x17, 0x31, 0xe7, + 0xb8, 0xe9, 0xca, 0xa2, 0x53, 0x90, 0xc5, 0x01, 0xb4, 0x29, 0x7f, 0x1a, + 0xbf, 0x4f, 0xe9, 0xb9, 0x3d, 0x0a, 0xbe, 0x5b, 0x89, 0x39, 0xe3, 0xf7, + 0xc1, 0xf7, 0x87, 0x25, 0x39, 0xbd, 0x62, 0x6b, 0x20, 0x77, 0x9e, 0xad, + 0x49, 0x9e, 0x35, 0xa5, 0x5c, 0xb2, 0xe5, 0x23, 0xb4, 0x21, 0x25, 0xce, + 0x0b, 0x36, 0x86, 0x67, 0xec, 0x25, 0xd8, 0x99, 0x12, 0x6c, 0x0a, 0x6c, + 0xc8, 0x9f, 0xa0, 0xfc, 0x59, 0xd4, 0x79, 0x06, 0xf1, 0xd3, 0x79, 0x60, + 0xbf, 0x73, 0xc0, 0x14, 0x4f, 0x97, 0x32, 0x3a, 0x96, 0x55, 0xf3, 0x85, + 0xcf, 0x52, 0xb1, 0x8f, 0x94, 0xe7, 0xd4, 0x7d, 0x1e, 0xb5, 0xb6, 0x59, + 0x67, 0x13, 0x71, 0x16, 0x28, 0x13, 0x99, 0x9b, 0xf3, 0x79, 0x42, 0xdb, + 0xc7, 0xf3, 0x19, 0xdf, 0x56, 0x36, 0xaf, 0xb1, 0x95, 0x22, 0x2f, 0x56, + 0x3c, 0x3c, 0x49, 0x7c, 0x5c, 0x9c, 0x4a, 0xac, 0x9c, 0x63, 0x16, 0xe1, + 0x37, 0x97, 0x11, 0x67, 0x44, 0xd2, 0xdf, 0x94, 0xc8, 0x71, 0xd7, 0xfd, + 0x21, 0xfc, 0x66, 0x01, 0x6b, 0x62, 0x04, 0x50, 0xbe, 0xc0, 0x77, 0x94, + 0x7b, 0xca, 0x76, 0x80, 0xe7, 0x19, 0xf2, 0x12, 0xca, 0xca, 0x2a, 0xfe, + 0xfa, 0x16, 0xe8, 0xd1, 0xf4, 0xa9, 0x32, 0xd6, 0x6b, 0x94, 0xdc, 0x58, + 0x0a, 0x31, 0x4e, 0xaf, 0xd9, 0x88, 0xf6, 0x73, 0x0b, 0x6c, 0x63, 0x0d, + 0xf0, 0x3a, 0xd5, 0x4b, 0x0b, 0x2c, 0xef, 0x90, 0x8b, 0x88, 0x45, 0x49, + 0x43, 0x79, 0x36, 0x2d, 0xde, 0xde, 0x31, 0xed, 0x15, 0x69, 0x45, 0x1e, + 0xfc, 0xca, 0x96, 0xe8, 0x67, 0x43, 0x52, 0x88, 0x93, 0xd7, 0x71, 0x59, + 0x9e, 0xfa, 0x4c, 0x13, 0xf7, 0x66, 0xb3, 0x36, 0x9f, 0xfd, 0xbd, 0x0e, + 0xf3, 0x2d, 0xec, 0x75, 0x70, 0x7f, 0x23, 0x04, 0x5f, 0xa6, 0xf6, 0x3c, + 0x90, 0x26, 0xea, 0xe2, 0x5f, 0xbe, 0xf7, 0xb0, 0x51, 0x0d, 0x3f, 0x12, + 0x4f, 0x72, 0xbe, 0x56, 0x61, 0x09, 0xf6, 0xa3, 0x2d, 0x7d, 0x49, 0xee, + 0x3d, 0xe1, 0xcd, 0xcf, 0x38, 0x25, 0xbc, 0x4b, 0x23, 0x57, 0x67, 0x2d, + 0xe7, 0x0a, 0x30, 0x45, 0x2e, 0xe6, 0x60, 0xbd, 0x46, 0x9b, 0x60, 0xbf, + 0x06, 0x32, 0xc6, 0x99, 0x26, 0x0f, 0x9f, 0x85, 0x64, 0x62, 0x8a, 0xe7, + 0x9e, 0xb0, 0x6d, 0xc0, 0x90, 0xbf, 0x1b, 0xc2, 0x73, 0x85, 0x79, 0xc4, + 0xa4, 0x5e, 0x3c, 0x8b, 0x67, 0xaf, 0x3f, 0xf2, 0xdc, 0x38, 0xc1, 0xb9, + 0x07, 0xe4, 0x5e, 0xa0, 0x13, 0x41, 0xff, 0x9d, 0x7a, 0xac, 0xce, 0x53, + 0x29, 0xee, 0x65, 0x4b, 0x12, 0xf6, 0x22, 0x8b, 0x58, 0x32, 0x17, 0xeb, + 0xd0, 0xd8, 0x9c, 0xef, 0xd6, 0x62, 0x4f, 0x3f, 0xc6, 0x4b, 0xc9, 0xe7, + 0x4b, 0x3e, 0xd6, 0x4b, 0xc1, 0xc7, 0x4a, 0x68, 0xb8, 0xc7, 0x95, 0x1f, + 0x3a, 0xe4, 0x57, 0x1f, 0xf2, 0x8e, 0x1c, 0xae, 0xfe, 0xb2, 0xf3, 0xcd, + 0xfa, 0xbf, 0x66, 0xd0, 0xc8, 0x1f, 0xe8, 0x03, 0x3e, 0x22, 0xed, 0x06, + 0xfc, 0x79, 0x11, 0xb8, 0xcb, 0x38, 0xd3, 0xa1, 0xde, 0x19, 0xc0, 0x06, + 0xe5, 0x29, 0xd8, 0xc6, 0x33, 0x3c, 0xf3, 0x85, 0x6d, 0x3b, 0x13, 0x96, + 0xe2, 0x0c, 0xe5, 0x52, 0xda, 0x0c, 0xac, 0x17, 0xeb, 0x97, 0xa7, 0x3a, + 0x90, 0x36, 0x23, 0x4d, 0xa8, 0x7e, 0xca, 0x53, 0xb6, 0x6a, 0x5f, 0x9e, + 0x4a, 0xa9, 0x76, 0xe5, 0xa9, 0x3e, 0xa4, 0x8e, 0x34, 0x9c, 0x41, 0xe0, + 0x74, 0xa6, 0x5b, 0x26, 0x4e, 0xc2, 0xbf, 0xf4, 0x1b, 0xea, 0xbe, 0xc4, + 0x38, 0xfc, 0x4f, 0x08, 0x51, 0xd6, 0x15, 0x73, 0x00, 0x18, 0x6b, 0x1b, + 0x30, 0xc8, 0x36, 0xb1, 0x8f, 0x73, 0xfe, 0xb4, 0xbd, 0xcb, 0xdc, 0xff, + 0x8a, 0x3f, 0x28, 0x19, 0xd9, 0x37, 0xd3, 0x08, 0x7d, 0x0d, 0x99, 0x45, + 0xe9, 0x32, 0x87, 0x90, 0xcf, 0xcf, 0x91, 0x6f, 0xf7, 0xab, 0xd8, 0x2d, + 0xeb, 0xc4, 0xa2, 0x12, 0x4d, 0x63, 0x8c, 0xb7, 0xd2, 0xbe, 0x07, 0xf2, + 0x67, 0xeb, 0x3e, 0xd2, 0xa0, 0xa7, 0x9e, 0x1f, 0x3c, 0xeb, 0xcd, 0xfc, + 0x8a, 0xb3, 0x5e, 0xca, 0x35, 0xf9, 0x7b, 0xbf, 0x2c, 0xdb, 0x69, 0x79, + 0xc9, 0x4e, 0xc9, 0x45, 0x7b, 0xab, 0xfc, 0x39, 0xfc, 0xf4, 0x25, 0x7b, + 0xba, 0x89, 0x58, 0xa0, 0xac, 0xce, 0xcf, 0xfc, 0xb5, 0xb2, 0xf5, 0x3e, + 0xfa, 0x8f, 0x64, 0x71, 0x8a, 0xd8, 0xd9, 0xdd, 0xbe, 0xc7, 0x29, 0xd0, + 0x6f, 0x81, 0x06, 0x62, 0xb5, 0x02, 0xfc, 0xdf, 0x41, 0x19, 0x72, 0xe8, + 0xf7, 0x94, 0x8f, 0x8a, 0x0f, 0x79, 0xfa, 0xec, 0xe4, 0x61, 0x57, 0x97, + 0x67, 0xa0, 0x4f, 0x42, 0xf9, 0xc7, 0xf3, 0x1c, 0xd7, 0xdd, 0x96, 0x2f, + 0x94, 0x38, 0xcf, 0xe2, 0xe6, 0xa8, 0x04, 0x65, 0x58, 0xe1, 0x85, 0x16, + 0x79, 0x71, 0x61, 0x83, 0x18, 0xf0, 0x50, 0xc6, 0x2d, 0x61, 0x75, 0xd3, + 0x84, 0xf1, 0xb7, 0xb4, 0xf2, 0xbe, 0xd8, 0x87, 0xc1, 0x1b, 0xee, 0x05, + 0x60, 0x6e, 0xad, 0x9c, 0x89, 0x9f, 0xef, 0x83, 0x7e, 0xf1, 0x39, 0x20, + 0x39, 0x3b, 0x86, 0x67, 0xa6, 0xd4, 0x39, 0xee, 0x93, 0x05, 0xc5, 0xc3, + 0xdc, 0xe3, 0xea, 0x7d, 0xa3, 0x7d, 0x07, 0x70, 0x1d, 0xe5, 0x15, 0xe9, + 0xa2, 0x37, 0x6e, 0x0e, 0x38, 0x2e, 0xdf, 0xd7, 0xa4, 0xce, 0xff, 0x0a, + 0xd0, 0x85, 0x71, 0x55, 0xbf, 0x5f, 0x2e, 0x4d, 0xed, 0x8f, 0x7a, 0xfa, + 0x31, 0xa0, 0x9f, 0xf9, 0x9e, 0xf1, 0x15, 0xf7, 0x4b, 0x5e, 0x19, 0x99, + 0xb4, 0xbf, 0xa1, 0xf5, 0x47, 0x02, 0x77, 0xf7, 0x00, 0x87, 0x1e, 0x69, + 0xc0, 0x5c, 0xac, 0x44, 0x22, 0x60, 0xb4, 0x1b, 0xc0, 0xf1, 0x43, 0xca, + 0xe7, 0xf6, 0xa8, 0xfd, 0xe8, 0x53, 0xa9, 0x16, 0x29, 0x9b, 0xb6, 0xba, + 0x17, 0xb7, 0x64, 0x6e, 0x21, 0xd6, 0xc7, 0xaf, 0x09, 0x65, 0x5d, 0x48, + 0x1b, 0x91, 0xbe, 0x4b, 0x8a, 0xc7, 0xa6, 0xf5, 0x78, 0xe1, 0x35, 0xf9, + 0x3e, 0x9d, 0x7e, 0x44, 0xc7, 0x53, 0x1c, 0x27, 0x2c, 0xf6, 0x17, 0x9b, + 0xa5, 0xeb, 0x88, 0x09, 0x6c, 0x1b, 0x07, 0xd6, 0xed, 0x90, 0xd4, 0x91, + 0x84, 0xdc, 0x72, 0xc4, 0xdf, 0x73, 0xfa, 0x0f, 0x23, 0x49, 0xb5, 0xc7, + 0xf9, 0xdd, 0x11, 0x7b, 0x8e, 0xe9, 0x6b, 0xfa, 0xfe, 0xde, 0x15, 0x7d, + 0xaf, 0xef, 0x47, 0x23, 0x3d, 0x2a, 0xfd, 0x6f, 0x23, 0x29, 0x95, 0xbe, + 0x3e, 0x72, 0x4b, 0xc5, 0x8b, 0x8f, 0x8a, 0xf3, 0x29, 0xf9, 0x5c, 0x89, + 0xf8, 0xb2, 0x1f, 0xd8, 0xd1, 0x81, 0x9d, 0xe9, 0x83, 0x9d, 0x49, 0xc1, + 0xce, 0x0c, 0xd0, 0xce, 0xc0, 0x6e, 0xbf, 0x02, 0xbb, 0xed, 0xc8, 0xf7, + 0x20, 0xaf, 0x4f, 0x3b, 0x8d, 0xc0, 0x85, 0xae, 0xeb, 0xcd, 0xd5, 0x7a, + 0x62, 0x09, 0xeb, 0x5b, 0x3e, 0x2d, 0x91, 0x56, 0xd8, 0xa0, 0x2d, 0x27, + 0x1a, 0x64, 0x3e, 0xe6, 0xba, 0x47, 0x1d, 0x5b, 0xae, 0xa2, 0x7e, 0xd6, + 0xa6, 0x1e, 0xbf, 0x14, 0x65, 0x3c, 0x76, 0x75, 0x6a, 0x2b, 0x6c, 0x12, + 0xe5, 0x3d, 0x22, 0xe5, 0xb1, 0xb8, 0x2c, 0x20, 0x3e, 0xab, 0xd5, 0x49, + 0xe1, 0x99, 0xfa, 0xff, 0x5d, 0xd4, 0x4d, 0xc1, 0x3f, 0x98, 0xb2, 0xd8, + 0x93, 0x90, 0x53, 0x3d, 0xd6, 0x40, 0xc2, 0xa0, 0xed, 0x4a, 0xc8, 0x1c, + 0x62, 0xfd, 0x72, 0x89, 0xf5, 0x59, 0x0f, 0xfa, 0x59, 0xf2, 0xda, 0x4d, + 0x96, 0x7c, 0x3b, 0xd1, 0xcf, 0x7d, 0xc8, 0x50, 0xae, 0xc7, 0xf3, 0x01, + 0x86, 0xd1, 0x08, 0x39, 0x70, 0xc0, 0xff, 0x31, 0x94, 0xf7, 0xf3, 0xbe, + 0x07, 0xca, 0x88, 0x85, 0x7e, 0x1c, 0x25, 0x46, 0xcc, 0x39, 0x63, 0x28, + 0x63, 0x1b, 0x2b, 0x9e, 0x44, 0xf9, 0xa8, 0x24, 0xe3, 0x79, 0x75, 0xf7, + 0xac, 0x1d, 0x65, 0xec, 0x23, 0xa8, 0xf7, 0x63, 0xfe, 0x8f, 0x92, 0xa3, + 0xa0, 0xed, 0x97, 0xf7, 0xaa, 0xbd, 0x81, 0x8c, 0xe9, 0x40, 0x1f, 0x58, + 0x96, 0x34, 0xd9, 0x2e, 0xe7, 0x38, 0xca, 0x16, 0xde, 0x57, 0xe1, 0x19, + 0x5e, 0x44, 0xee, 0xad, 0x34, 0x4b, 0xae, 0xd2, 0x70, 0x1d, 0xfb, 0xef, + 0xeb, 0xe4, 0x72, 0xdc, 0x14, 0xde, 0x83, 0xf0, 0xf4, 0x3c, 0xb4, 0x95, + 0x3a, 0x31, 0xc0, 0x73, 0x03, 0xf8, 0x5b, 0xac, 0x05, 0xfc, 0xef, 0x39, + 0xf8, 0xdf, 0xa7, 0x4b, 0x35, 0xfb, 0xe1, 0xf9, 0x5d, 0xda, 0x80, 0x27, + 0xb1, 0x66, 0xa3, 0xc0, 0xfd, 0x3b, 0x11, 0x0f, 0x0c, 0x03, 0xfb, 0x0f, + 0x62, 0xfd, 0xd2, 0x58, 0xbb, 0x31, 0xde, 0x17, 0xc2, 0x3a, 0x0e, 0xa8, + 0x73, 0xe6, 0x19, 0x75, 0xe7, 0xe2, 0x47, 0xca, 0xf7, 0x3e, 0x5e, 0x32, + 0xe0, 0x1f, 0x0a, 0xee, 0x66, 0xdb, 0x02, 0xfe, 0x5b, 0xd1, 0xe7, 0x81, + 0x17, 0x61, 0x57, 0x7e, 0x06, 0xba, 0xce, 0xcf, 0xd0, 0x9f, 0xa3, 0x8e, + 0x87, 0xb7, 0x1d, 0xee, 0x75, 0x41, 0x9f, 0x0f, 0x2f, 0xcb, 0x12, 0x70, + 0x47, 0x86, 0x72, 0x8c, 0xf8, 0xc1, 0x7a, 0x7a, 0x4e, 0xba, 0x69, 0x03, + 0xe7, 0xa8, 0x2b, 0xfd, 0xd3, 0x71, 0x60, 0x3d, 0x20, 0x79, 0x75, 0xae, + 0x8a, 0xe7, 0xb3, 0x1b, 0xc5, 0x20, 0xde, 0x73, 0x6e, 0x40, 0x19, 0xed, + 0x86, 0x8f, 0x91, 0x96, 0x06, 0xda, 0x24, 0xb3, 0xa5, 0x4d, 0xd9, 0x0e, + 0xcb, 0x79, 0x09, 0xe3, 0xee, 0x90, 0x46, 0x60, 0xb8, 0x02, 0xc6, 0x38, + 0x20, 0xff, 0xd5, 0xe1, 0x1e, 0x95, 0x17, 0xfb, 0x81, 0x96, 0x08, 0x78, + 0xd6, 0xb4, 0xc7, 0x36, 0x23, 0x3b, 0xaa, 0xec, 0x3f, 0xa2, 0x30, 0x56, + 0x4e, 0xd8, 0x3f, 0xfc, 0x04, 0xc6, 0x4c, 0x4e, 0x53, 0xf6, 0x7b, 0xb1, + 0x6e, 0xbf, 0x0d, 0x0c, 0x44, 0xae, 0x7e, 0x75, 0x83, 0xa7, 0x2f, 0xa4, + 0x7f, 0x89, 0x78, 0x82, 0x67, 0x00, 0x5e, 0x5c, 0xbe, 0x42, 0x5b, 0x3f, + 0xe8, 0x9d, 0xdd, 0xe0, 0x9f, 0x25, 0x77, 0x4e, 0x7b, 0xfe, 0xba, 0xf3, + 0x2c, 0x5a, 0x1d, 0x95, 0x76, 0x9e, 0x4a, 0x1b, 0x72, 0x8b, 0xdc, 0x19, + 0xf2, 0xfa, 0x31, 0x4e, 0x98, 0x90, 0x55, 0xda, 0x81, 0x76, 0xc8, 0x39, + 0xf3, 0xb4, 0x29, 0xb4, 0x09, 0x94, 0x05, 0x5b, 0x8a, 0x55, 0xd8, 0x84, + 0x96, 0x0e, 0x99, 0x23, 0xcf, 0x4e, 0xd0, 0x4e, 0xfc, 0x48, 0x26, 0xd7, + 0xd8, 0xca, 0x41, 0xf1, 0xe3, 0xda, 0x66, 0x09, 0xa7, 0x6d, 0xf3, 0x3e, + 0x35, 0x47, 0xcf, 0x5e, 0xee, 0x23, 0xfe, 0x9c, 0xc9, 0x58, 0x6d, 0xa2, + 0xb1, 0xa7, 0xc2, 0x4f, 0xdf, 0xc7, 0x5c, 0xd9, 0x87, 0xe2, 0xd3, 0xc0, + 0xa0, 0x17, 0x0b, 0xa8, 0x3d, 0x3f, 0xe0, 0xe0, 0xf8, 0xcf, 0x60, 0x6b, + 0x73, 0xc4, 0x25, 0xe0, 0x73, 0xe7, 0x51, 0xca, 0xd1, 0x66, 0xda, 0x32, + 0xe0, 0xbc, 0x14, 0xed, 0xb5, 0x2c, 0x4c, 0x03, 0x73, 0x19, 0x77, 0x48, + 0x9e, 0xf2, 0xca, 0xbb, 0x0a, 0x0b, 0x86, 0x4c, 0xce, 0xb6, 0x48, 0xd7, + 0x09, 0xee, 0xaf, 0x9e, 0x8a, 0x4a, 0x0b, 0xf7, 0x58, 0xe9, 0x83, 0xfa, + 0x25, 0x87, 0xf2, 0xce, 0x13, 0x41, 0xb5, 0x1f, 0x36, 0x67, 0x90, 0x47, + 0x7d, 0xb0, 0x07, 0x56, 0x6a, 0xc9, 0xd8, 0xd6, 0xe4, 0x61, 0x48, 0xc8, + 0x52, 0x09, 0x32, 0x56, 0x82, 0x8c, 0x95, 0x20, 0x63, 0x25, 0xc8, 0x18, + 0xb0, 0xdf, 0x79, 0xe8, 0xdf, 0xb9, 0xd2, 0x80, 0xf6, 0xeb, 0xbb, 0x94, + 0x5f, 0x3f, 0x54, 0x7a, 0xc5, 0x65, 0xfa, 0xac, 0x8a, 0x4d, 0xfb, 0x20, + 0x83, 0x8c, 0x45, 0xfd, 0x18, 0xf5, 0x15, 0x79, 0x72, 0xe6, 0x55, 0x39, + 0x35, 0x53, 0xc3, 0x81, 0x13, 0x25, 0x57, 0x5e, 0x72, 0x10, 0x7f, 0xce, + 0x13, 0x53, 0x65, 0x5a, 0x1b, 0x15, 0xb6, 0x3a, 0x28, 0x79, 0x85, 0x93, + 0x95, 0x1f, 0x01, 0xbe, 0x52, 0xb8, 0x90, 0xba, 0x29, 0x6d, 0x5b, 0x2e, + 0xcb, 0x39, 0xf8, 0xf1, 0x85, 0xea, 0x6b, 0xf2, 0x8c, 0xc2, 0xe3, 0xe4, + 0xc3, 0x3b, 0xe5, 0xa7, 0xa6, 0x77, 0x9e, 0x7f, 0x0a, 0x58, 0x63, 0xa1, + 0x87, 0xb6, 0x23, 0x04, 0x5f, 0x60, 0x15, 0x3a, 0xa1, 0xd7, 0xfb, 0x8d, + 0x1b, 0x81, 0x69, 0xf8, 0x7e, 0xa3, 0xbc, 0x38, 0x53, 0xa8, 0x93, 0x09, + 0xda, 0x07, 0xeb, 0xb0, 0x18, 0xf4, 0x53, 0xf4, 0x9b, 0x9c, 0x2f, 0xfd, + 0xd4, 0x4f, 0x37, 0xf0, 0x0e, 0x57, 0xf9, 0x58, 0x6c, 0x03, 0xf7, 0x1b, + 0x63, 0x36, 0x79, 0x7a, 0x59, 0xf6, 0x57, 0x58, 0xf6, 0x2a, 0xd6, 0x87, + 0xe9, 0x0f, 0xdc, 0x7b, 0x63, 0x1c, 0x8f, 0xfd, 0x02, 0x37, 0xb5, 0x63, + 0xae, 0xa5, 0x8f, 0x68, 0xcc, 0xdd, 0xa7, 0x70, 0xf4, 0xb5, 0x78, 0x99, + 0x7c, 0x72, 0xc0, 0xa7, 0xcb, 0x6a, 0x3f, 0x70, 0x9d, 0x7d, 0xe2, 0x27, + 0xa0, 0x57, 0x85, 0x2b, 0xc2, 0x3d, 0x4b, 0xee, 0xe7, 0x72, 0xaf, 0xb8, + 0xde, 0x62, 0xa8, 0x7b, 0x03, 0x72, 0x0f, 0xec, 0xcb, 0xbd, 0xb0, 0x2f, + 0xf7, 0x5d, 0x73, 0x07, 0xda, 0x3f, 0x03, 0xe8, 0x2a, 0x04, 0x8d, 0x0e, + 0x19, 0xad, 0xd4, 0xb7, 0xe5, 0x3e, 0xee, 0x7a, 0xfb, 0xb6, 0xdc, 0xd3, + 0x4d, 0xad, 0xd9, 0x0b, 0xa4, 0x6c, 0xb8, 0x72, 0xc9, 0xe1, 0xbe, 0x9b, + 0x7f, 0x6f, 0x7e, 0x3d, 0xfc, 0x15, 0x68, 0xf6, 0xf7, 0x9c, 0x43, 0xe9, + 0x2b, 0xc2, 0xfb, 0xf3, 0xc5, 0x29, 0xe2, 0x81, 0x98, 0xba, 0x17, 0x63, + 0xa8, 0x7d, 0x3e, 0xaf, 0x6d, 0x71, 0x4a, 0x9d, 0x31, 0x15, 0xb8, 0x77, + 0x6d, 0x6e, 0xb5, 0xcc, 0xd1, 0xa0, 0x77, 0x1f, 0x93, 0xba, 0xec, 0xd9, + 0x32, 0xc8, 0x62, 0xb5, 0x76, 0xcf, 0x71, 0x50, 0xd9, 0x8b, 0x2b, 0xd0, + 0x01, 0xae, 0x17, 0xe2, 0x05, 0xe8, 0xc9, 0x04, 0xec, 0x53, 0x5e, 0xf5, + 0x17, 0xa1, 0x5c, 0x64, 0xb2, 0x41, 0x43, 0xc2, 0xc7, 0x19, 0x0b, 0x79, + 0x7b, 0x2d, 0xb9, 0xa0, 0xa5, 0xec, 0x37, 0x68, 0x07, 0x3e, 0xa3, 0x7e, + 0x26, 0xc6, 0x1b, 0xd3, 0x0d, 0xf0, 0xab, 0x58, 0xbf, 0x2a, 0xf7, 0x04, + 0xa0, 0xbb, 0x8b, 0xdf, 0x91, 0x7d, 0xb3, 0xdd, 0xcd, 0x9e, 0xfc, 0x73, + 0x1f, 0x99, 0xf3, 0xf3, 0x69, 0x58, 0xdd, 0xb7, 0x71, 0x5c, 0x22, 0x51, + 0xf8, 0xb4, 0x0f, 0x20, 0xce, 0xd8, 0x01, 0x59, 0x59, 0x8a, 0xb1, 0x5f, + 0x4f, 0x67, 0x26, 0x4b, 0xec, 0xfb, 0x3b, 0x32, 0x34, 0x5b, 0x6a, 0xa6, + 0x2f, 0x59, 0x84, 0x1d, 0x58, 0x36, 0xe9, 0x43, 0xc7, 0xe0, 0xe3, 0xda, + 0xe5, 0xfb, 0xb3, 0xf4, 0x8f, 0x49, 0xf3, 0x94, 0xf4, 0xc6, 0x4f, 0x81, + 0xa6, 0xcf, 0x3b, 0x21, 0xc6, 0x68, 0xee, 0x20, 0xca, 0xfe, 0x5c, 0x92, + 0x66, 0x67, 0x80, 0xcf, 0xbd, 0xe6, 0x17, 0x80, 0x61, 0x33, 0x66, 0xd2, + 0xbc, 0x35, 0x40, 0x39, 0x42, 0xcc, 0xbd, 0x58, 0xa3, 0xf3, 0x07, 0xb3, + 0x2a, 0x4e, 0x52, 0x76, 0x66, 0xd1, 0xe1, 0x78, 0xa0, 0x5b, 0xd9, 0xac, + 0x5b, 0x61, 0x4f, 0x22, 0xfa, 0xfc, 0x0d, 0x6d, 0x88, 0x6d, 0x9c, 0x90, + 0xce, 0x3f, 0x2a, 0xd9, 0x93, 0x31, 0xd8, 0x33, 0xf6, 0xe5, 0xc7, 0x0e, + 0xf4, 0x91, 0x3e, 0xde, 0xa6, 0xbf, 0xbb, 0x03, 0x7e, 0xef, 0x66, 0x45, + 0xcf, 0xb0, 0xd3, 0x27, 0x13, 0xc7, 0x38, 0x76, 0x0f, 0x6c, 0x79, 0x5c, + 0xc9, 0x6d, 0xb1, 0xb4, 0x1c, 0x8f, 0xc0, 0x26, 0x47, 0xb6, 0x90, 0x9f, + 0xef, 0x93, 0xbb, 0xec, 0x31, 0xb9, 0x1b, 0xb2, 0x33, 0x68, 0x3b, 0x32, + 0x84, 0xb5, 0xd8, 0x61, 0xc3, 0xef, 0x28, 0x0c, 0xdd, 0x88, 0xb8, 0x8b, + 0x63, 0xb7, 0xeb, 0xfb, 0x17, 0x1e, 0x7e, 0xfc, 0x4a, 0xd5, 0xe3, 0x51, + 0x76, 0xf6, 0x49, 0xc5, 0x9b, 0x61, 0x67, 0x9b, 0xf6, 0xb3, 0x2d, 0x92, + 0x53, 0xf5, 0xb6, 0x29, 0x7f, 0x5c, 0x5c, 0xb8, 0x1f, 0x29, 0x7c, 0xf3, + 0x02, 0xec, 0x0d, 0x30, 0x77, 0xb1, 0xb2, 0x15, 0x79, 0xf8, 0xd0, 0x85, + 0x34, 0xd2, 0xf7, 0x21, 0x65, 0xdd, 0x07, 0x9a, 0xbd, 0xbd, 0xdc, 0xb5, + 0xf7, 0xb8, 0x24, 0xf0, 0x01, 0x85, 0x4b, 0xaf, 0xa8, 0x3b, 0x80, 0x88, + 0xa1, 0x47, 0xb2, 0xb0, 0x2b, 0xcd, 0xc0, 0x40, 0x53, 0xc7, 0xad, 0xd4, + 0x50, 0x60, 0xbb, 0x7c, 0x10, 0xb1, 0x7c, 0xd9, 0xe1, 0x5a, 0x6e, 0x95, + 0x07, 0xdf, 0x4b, 0x19, 0xd9, 0x2e, 0x7b, 0xde, 0x1b, 0x90, 0x3d, 0x7d, + 0x56, 0x86, 0x74, 0xdf, 0xf2, 0x2e, 0x3f, 0x9e, 0xee, 0x1a, 0x4e, 0x06, + 0xfa, 0xe5, 0x0b, 0x90, 0xb1, 0x02, 0xe4, 0x6b, 0xa8, 0x4a, 0x9e, 0xd3, + 0xde, 0xd3, 0xce, 0xa7, 0x80, 0x95, 0x7d, 0xec, 0x67, 0xcb, 0x54, 0xb5, + 0x41, 0x12, 0x37, 0x70, 0x3f, 0x39, 0xe1, 0x9d, 0x71, 0xdc, 0x40, 0x99, + 0x40, 0x0c, 0x72, 0x83, 0xa7, 0x9f, 0xea, 0xee, 0xdd, 0x0d, 0x9e, 0x5f, + 0x41, 0xfc, 0xeb, 0x12, 0xe7, 0x79, 0x77, 0x0d, 0xbe, 0xa1, 0x6d, 0x69, + 0x68, 0xe3, 0x0a, 0xbe, 0x6b, 0x61, 0xfc, 0xf0, 0x87, 0xcd, 0xb5, 0x6f, + 0x07, 0xd6, 0xca, 0xa2, 0xbf, 0xef, 0x36, 0x87, 0x39, 0xd3, 0xa7, 0x5b, + 0x26, 0x6d, 0x61, 0xab, 0xbd, 0x4b, 0xfe, 0x0c, 0xfe, 0xfd, 0x6b, 0x2b, + 0xfe, 0x7d, 0x37, 0xf8, 0xb1, 0x16, 0x03, 0xd8, 0xe6, 0x3d, 0x98, 0xcb, + 0x30, 0xd6, 0xf3, 0x6e, 0xfc, 0xee, 0x2a, 0xad, 0xda, 0xc7, 0x9b, 0x29, + 0x00, 0x4f, 0x36, 0xd8, 0xec, 0x6f, 0xd5, 0x7e, 0x5e, 0x21, 0x2f, 0x2b, + 0x7b, 0x85, 0x03, 0x57, 0x85, 0x7e, 0xef, 0x75, 0x09, 0x77, 0xdb, 0xaf, + 0x77, 0x06, 0xec, 0xe7, 0x8d, 0x00, 0xcf, 0xc1, 0x1d, 0x39, 0x5d, 0x25, + 0x0e, 0xbb, 0x28, 0xc6, 0x59, 0x62, 0xb0, 0x97, 0xd5, 0x1e, 0x54, 0xb9, + 0xf4, 0x2d, 0xa4, 0xa8, 0x0f, 0xfb, 0x18, 0xf4, 0xf6, 0x29, 0x14, 0x56, + 0xa1, 0x9d, 0xbd, 0x1b, 0xeb, 0x30, 0x81, 0x5f, 0xe7, 0x96, 0x5b, 0xa1, + 0xbf, 0x94, 0x53, 0xee, 0x7d, 0x75, 0x9b, 0x5b, 0x02, 0x7c, 0xb7, 0xde, + 0x3e, 0xd8, 0xb7, 0x25, 0x74, 0x14, 0xbe, 0xce, 0xa0, 0x7d, 0xe0, 0x3c, + 0xe8, 0x27, 0x4d, 0x99, 0x3f, 0x46, 0x5d, 0x5f, 0xaf, 0xbe, 0x5f, 0xd7, + 0x9f, 0x8b, 0xf2, 0x1b, 0x99, 0x3c, 0xf7, 0x38, 0x4b, 0x5c, 0x03, 0x07, + 0x6b, 0xe0, 0xca, 0x71, 0xa7, 0x95, 0x36, 0x5d, 0x82, 0xc7, 0x5d, 0x19, + 0x54, 0xd8, 0xb5, 0x17, 0x98, 0x6b, 0xa3, 0xc6, 0x0d, 0x31, 0x09, 0x1d, + 0xef, 0x90, 0x46, 0xe0, 0xea, 0x86, 0x23, 0xf4, 0x91, 0xc9, 0xc4, 0x20, + 0x84, 0x20, 0xa4, 0xee, 0x93, 0x5a, 0x03, 0xdf, 0x97, 0xde, 0xc4, 0xf7, + 0x85, 0x78, 0xe9, 0x51, 0xac, 0x9f, 0xe5, 0x5c, 0x5c, 0xa7, 0x7e, 0xb1, + 0x56, 0x1f, 0x72, 0xc4, 0xbd, 0x35, 0xb6, 0xe1, 0x5e, 0x5b, 0x72, 0xe0, + 0x7b, 0xdc, 0x63, 0x43, 0xac, 0xd9, 0x70, 0xc6, 0xa3, 0xc1, 0x58, 0x6c, + 0x93, 0xf2, 0x49, 0xea, 0x28, 0xf7, 0x59, 0x4c, 0x2f, 0x4e, 0x2d, 0x31, + 0x5e, 0xe5, 0xfb, 0x84, 0x7e, 0xdf, 0xa9, 0xdf, 0x33, 0x1e, 0x2d, 0xb8, + 0x0d, 0xe0, 0xe9, 0x0e, 0xd8, 0xcf, 0xfb, 0xb7, 0xda, 0x0a, 0x37, 0xdc, + 0xbf, 0xb2, 0x66, 0x3b, 0xd5, 0xdd, 0xa2, 0x72, 0xe9, 0xa0, 0xd8, 0x5b, + 0x96, 0x52, 0x21, 0x19, 0xc5, 0x5a, 0x30, 0x9f, 0x21, 0x3d, 0xa9, 0x43, + 0xb2, 0x5f, 0xad, 0x4d, 0xf9, 0x98, 0x75, 0x38, 0x11, 0x98, 0x10, 0xa3, + 0xcc, 0xe7, 0x4f, 0x23, 0x3d, 0x04, 0xbc, 0xe3, 0xed, 0x5d, 0x1a, 0xe5, + 0xd5, 0xbc, 0x04, 0xc6, 0x30, 0x77, 0xac, 0xda, 0xc7, 0xaa, 0xed, 0x71, + 0xf1, 0xfd, 0xa0, 0x7a, 0x9f, 0x5a, 0xb5, 0xcf, 0x95, 0x33, 0x88, 0x65, + 0xfc, 0xf7, 0x5c, 0x0b, 0xae, 0x17, 0x7c, 0xf1, 0x31, 0x7f, 0xcf, 0xab, + 0x45, 0xaf, 0x0b, 0xd7, 0x67, 0x4a, 0xce, 0x99, 0xd6, 0x30, 0xe5, 0xef, + 0xb6, 0xad, 0x37, 0xc9, 0x78, 0x3b, 0xf7, 0xdb, 0xea, 0x69, 0x58, 0xbb, + 0x8f, 0x56, 0x3f, 0xfe, 0xda, 0xfd, 0x37, 0x8e, 0xed, 0xed, 0xb1, 0x65, + 0x57, 0xed, 0xb1, 0xd5, 0x8f, 0xc7, 0xb1, 0x36, 0x22, 0x7e, 0x2a, 0xb8, + 0x31, 0x9b, 0x6b, 0xd4, 0x95, 0x98, 0x65, 0xfe, 0xcb, 0x06, 0xd6, 0x31, + 0x06, 0x3f, 0xc2, 0xb5, 0xf4, 0xcf, 0x9e, 0xb9, 0xa6, 0xc9, 0xc4, 0x21, + 0x6f, 0x3d, 0x07, 0xbc, 0x75, 0xf7, 0xd6, 0xff, 0xe2, 0xca, 0x3a, 0xd2, + 0x3f, 0x70, 0x1d, 0xdb, 0x45, 0x60, 0x67, 0x8d, 0x23, 0x5c, 0x43, 0xa6, + 0x5c, 0x43, 0xbe, 0xe3, 0x1a, 0x76, 0xea, 0x77, 0x5c, 0x3f, 0xe0, 0xb4, + 0x2f, 0x02, 0x63, 0x38, 0x59, 0xf5, 0x1d, 0x54, 0x67, 0xb7, 0xaf, 0x8b, + 0x29, 0x79, 0x66, 0x3e, 0x2a, 0x66, 0xda, 0x9b, 0xd7, 0xd8, 0xaa, 0xfd, + 0x76, 0x9e, 0x5f, 0xf5, 0x11, 0x7b, 0xfa, 0xf3, 0x8a, 0x73, 0x5e, 0xfb, + 0xe5, 0xb2, 0xe4, 0xa7, 0x42, 0x88, 0x01, 0x53, 0xc0, 0x39, 0x7d, 0xb0, + 0xb7, 0xdc, 0x1f, 0x45, 0x59, 0x85, 0x78, 0x85, 0xbe, 0x2e, 0x05, 0x5d, + 0xa1, 0x0d, 0x26, 0x1e, 0x79, 0x55, 0x72, 0x73, 0xbe, 0x8d, 0x41, 0xff, + 0x86, 0xdf, 0x3f, 0xf9, 0x9c, 0xb9, 0x65, 0xb3, 0x2c, 0x25, 0x36, 0x8b, + 0x95, 0x58, 0x90, 0xda, 0xba, 0x8e, 0xad, 0xcf, 0x77, 0xe7, 0xfe, 0x60, + 0x4d, 0x36, 0xc6, 0xd6, 0x59, 0xfb, 0xbd, 0xe2, 0xbf, 0xf7, 0xd7, 0x7e, + 0xdd, 0x75, 0x28, 0xbc, 0x22, 0x5c, 0x0b, 0xf2, 0x80, 0x78, 0x38, 0x2c, + 0x9f, 0x8a, 0x51, 0x1f, 0x0b, 0xea, 0x7c, 0x33, 0x69, 0x74, 0x2b, 0x9b, + 0x31, 0xe8, 0x78, 0xf2, 0x5a, 0xc0, 0x38, 0x91, 0xae, 0x7f, 0xe1, 0x0e, + 0xc6, 0x10, 0xe7, 0x76, 0xd1, 0xbe, 0xf8, 0x3a, 0x1d, 0x55, 0x3a, 0xfd, + 0x79, 0x27, 0x20, 0x45, 0x3b, 0x20, 0x13, 0xf6, 0x41, 0x85, 0xf1, 0x3f, + 0x84, 0xbe, 0x1e, 0xd4, 0x7d, 0x4d, 0x48, 0xb7, 0xb6, 0x3f, 0x07, 0x20, + 0xe7, 0xae, 0xdc, 0xe7, 0x6c, 0x95, 0xdb, 0x5a, 0xa9, 0x03, 0xfe, 0xfc, + 0x0f, 0x4a, 0xd7, 0xd6, 0xa5, 0x04, 0x22, 0x83, 0x5b, 0xc2, 0x2b, 0x3c, + 0xa0, 0x9e, 0xf9, 0xf2, 0xed, 0xf1, 0xc1, 0x9b, 0xff, 0xaa, 0xb9, 0xea, + 0x79, 0x72, 0xce, 0xac, 0xc7, 0xb9, 0x7a, 0x58, 0xbe, 0x36, 0x57, 0xbf, + 0x7e, 0x33, 0x64, 0xc9, 0x4a, 0x48, 0xa0, 0x9e, 0x37, 0x2b, 0x36, 0x6a, + 0x98, 0x7b, 0x24, 0x4b, 0xa6, 0x95, 0x4a, 0x04, 0xfc, 0xbd, 0x68, 0x0f, + 0xeb, 0x76, 0x02, 0x87, 0xdb, 0xdd, 0xdd, 0xa9, 0xbc, 0xda, 0x23, 0x35, + 0xd4, 0xbc, 0x26, 0x80, 0xc9, 0xe6, 0x9d, 0x57, 0xdc, 0x4f, 0x02, 0xb3, + 0x8e, 0xcb, 0xc3, 0x12, 0x5c, 0xb5, 0x97, 0x8b, 0xfc, 0x59, 0xee, 0xe7, + 0x5a, 0x89, 0x0c, 0xd6, 0xf8, 0xc3, 0x88, 0xe1, 0xcb, 0xb0, 0xfb, 0x1f, + 0xa1, 0x6f, 0x28, 0xc1, 0x5f, 0x00, 0x97, 0x7c, 0xed, 0xba, 0x18, 0x7e, + 0xbc, 0x6e, 0x2f, 0xd7, 0xc3, 0xa7, 0xe7, 0x14, 0x26, 0x25, 0x6e, 0x3f, + 0x1c, 0xb8, 0xa7, 0x27, 0x88, 0x38, 0xa3, 0xe0, 0x46, 0x6c, 0xe2, 0xb8, + 0x83, 0x72, 0x17, 0xd6, 0xe7, 0xf4, 0x7c, 0x21, 0xb0, 0xa3, 0xe4, 0xcb, + 0x2a, 0xe2, 0xca, 0xaa, 0x95, 0x5a, 0x06, 0x3f, 0x9e, 0xd4, 0x98, 0x8f, + 0xe7, 0x35, 0x65, 0x1d, 0xb3, 0x70, 0x6f, 0xa8, 0x58, 0x3d, 0x28, 0x93, + 0x0e, 0xf7, 0x76, 0xba, 0xa4, 0x18, 0xcb, 0xdc, 0xd4, 0xb8, 0xc2, 0x23, + 0xcb, 0x44, 0xcc, 0x97, 0xa2, 0xfd, 0x2e, 0xeb, 0xf3, 0x8e, 0x27, 0x95, + 0x7c, 0xf9, 0xfb, 0xc2, 0x8c, 0x8f, 0x78, 0x5e, 0xd5, 0x65, 0x0e, 0xf3, + 0x79, 0x8e, 0x32, 0xa0, 0x62, 0x26, 0xf0, 0xf2, 0x21, 0xc9, 0x8c, 0x26, + 0x14, 0x6e, 0x79, 0xbc, 0x44, 0x7d, 0x21, 0xfe, 0xbf, 0x0c, 0xec, 0x1f, + 0xc2, 0x9a, 0x31, 0x0e, 0xe0, 0xd8, 0xd4, 0x0b, 0x94, 0x55, 0xcc, 0x5f, + 0xa2, 0x17, 0xdb, 0x37, 0x11, 0x63, 0x5c, 0x28, 0x7d, 0x5c, 0xf1, 0x6f, + 0x49, 0xfc, 0xbd, 0x73, 0x85, 0x05, 0x0b, 0xd9, 0x60, 0x40, 0x92, 0x47, + 0x3f, 0x03, 0x19, 0x1a, 0x41, 0x8c, 0xc4, 0x7a, 0xa2, 0xce, 0xaf, 0x06, + 0x81, 0xb9, 0x0c, 0xfb, 0x46, 0x29, 0x9a, 0x61, 0x29, 0xaa, 0x7b, 0x80, + 0x3c, 0xcf, 0x0d, 0xaa, 0xbd, 0x9d, 0xa2, 0x49, 0xcc, 0x9f, 0xd9, 0xe4, + 0xdf, 0x03, 0x2c, 0x9a, 0x6c, 0xc7, 0x3c, 0xcb, 0x27, 0x24, 0x7c, 0xf4, + 0x80, 0x34, 0x1c, 0x7d, 0x58, 0x1a, 0xa7, 0x89, 0xf1, 0xb8, 0x77, 0x6f, + 0xdc, 0xd1, 0x28, 0xc4, 0xdc, 0x5f, 0xc5, 0xd8, 0x07, 0xe5, 0x87, 0x8e, + 0x4f, 0xd3, 0x86, 0x8d, 0xd2, 0xc2, 0x3a, 0x7e, 0xde, 0xc7, 0xe3, 0x77, + 0x80, 0x1e, 0xce, 0x3f, 0xa1, 0x71, 0xdf, 0x1d, 0x75, 0xb1, 0x6b, 0x83, + 0x8e, 0x5d, 0xd9, 0xee, 0x32, 0x7c, 0xf6, 0x31, 0x09, 0xdb, 0x7e, 0xfb, + 0xed, 0xa8, 0x17, 0xaf, 0xbb, 0x03, 0xc1, 0x3a, 0xfa, 0x4e, 0x40, 0x0b, + 0x71, 0x0f, 0xcf, 0xdb, 0x59, 0xe6, 0x9d, 0xf9, 0x1b, 0xe5, 0x74, 0x70, + 0xf5, 0xf8, 0xdb, 0xea, 0xea, 0xfa, 0x65, 0x7e, 0x9b, 0xb0, 0x17, 0xf3, + 0xf7, 0x87, 0xeb, 0xda, 0x7d, 0xd7, 0xf4, 0x52, 0x2f, 0xf6, 0xf0, 0xe2, + 0x20, 0xce, 0x21, 0x55, 0x87, 0x73, 0x56, 0x7f, 0x2f, 0x9a, 0x43, 0x79, + 0x7e, 0xd6, 0xbf, 0x3b, 0x64, 0x60, 0x2e, 0x56, 0x81, 0xf1, 0x8b, 0xc9, + 0x6f, 0x33, 0x67, 0x0b, 0xa0, 0xfb, 0x66, 0x75, 0xef, 0x88, 0x77, 0x37, + 0x50, 0x2f, 0xe1, 0xe1, 0x4f, 0xe6, 0xe3, 0x58, 0xf3, 0x77, 0x75, 0x18, + 0xe9, 0xff, 0x7e, 0x53, 0xb6, 0x9f, 0xf8, 0x66, 0x13, 0xcf, 0x21, 0x81, + 0x9b, 0x29, 0x67, 0xdf, 0x81, 0x9c, 0x35, 0xaa, 0x73, 0x9f, 0x62, 0x89, + 0xf1, 0x5c, 0x1e, 0xf2, 0xc3, 0xfb, 0x7b, 0x8c, 0xfb, 0xf2, 0x7a, 0x3f, + 0x96, 0x74, 0x12, 0xd3, 0xfb, 0xf1, 0x01, 0xfb, 0x5c, 0xef, 0x9e, 0xb2, + 0x1f, 0xb3, 0x51, 0xde, 0xe2, 0x8a, 0xe6, 0xa1, 0x35, 0xf1, 0xca, 0x21, + 0xd8, 0x82, 0x79, 0xc8, 0xf3, 0x5e, 0xd8, 0xc0, 0xc1, 0x20, 0xf5, 0x33, + 0xaa, 0x63, 0x59, 0x9b, 0x71, 0x7b, 0x60, 0x14, 0x7d, 0x18, 0xd3, 0xaf, + 0xc9, 0x04, 0xec, 0xff, 0x64, 0x35, 0xa9, 0xbe, 0xe9, 0xc9, 0xc4, 0x79, + 0x9f, 0x8c, 0xe5, 0x5f, 0x83, 0xbc, 0xbe, 0x06, 0x3c, 0xbc, 0x01, 0xfc, + 0x34, 0xf4, 0x5a, 0xfd, 0x96, 0xde, 0x8b, 0x8a, 0x70, 0x2f, 0x1e, 0x76, + 0xb3, 0xe8, 0x61, 0xcd, 0xd8, 0x24, 0xd2, 0x7f, 0x1e, 0xf5, 0xe4, 0xf5, + 0xdf, 0x6a, 0x79, 0x6b, 0x42, 0xf9, 0x63, 0x6a, 0x0f, 0xd2, 0x9b, 0x93, + 0xa5, 0x63, 0x95, 0x30, 0x64, 0x8e, 0xf3, 0xfa, 0x53, 0xd4, 0xa3, 0xac, + 0xf5, 0xe8, 0xb3, 0xd9, 0xa8, 0xb2, 0x8f, 0x39, 0xc8, 0x52, 0x5e, 0xc5, + 0x11, 0xc0, 0xf7, 0x0e, 0xdb, 0x3d, 0xb7, 0x89, 0x67, 0x9f, 0x0d, 0xb6, + 0x8a, 0x2d, 0xda, 0x83, 0xe2, 0x97, 0xdd, 0x89, 0x32, 0xca, 0xd9, 0x8d, + 0x58, 0x1b, 0x96, 0x65, 0x91, 0xe7, 0x58, 0x37, 0xe9, 0x71, 0x38, 0x46, + 0x77, 0xf3, 0x6a, 0x9a, 0x38, 0x97, 0xf6, 0x35, 0xdf, 0x35, 0xb0, 0xec, + 0x46, 0x5d, 0x16, 0xd2, 0xf3, 0x1b, 0xd2, 0xdf, 0xd2, 0x5a, 0x87, 0x33, + 0x2b, 0xd8, 0x98, 0xf4, 0x45, 0x54, 0xbb, 0x8c, 0xe9, 0xc9, 0xce, 0x21, + 0xac, 0x47, 0x28, 0x1d, 0xe4, 0x99, 0x2c, 0xf8, 0xeb, 0xeb, 0x44, 0x5c, + 0xc5, 0x9d, 0x09, 0xc3, 0xbb, 0xbb, 0x74, 0xee, 0x9a, 0xfb, 0xd9, 0xde, + 0x5d, 0xf7, 0xa1, 0x9e, 0x26, 0x99, 0x9f, 0x89, 0xe8, 0x7b, 0x93, 0x71, + 0xa5, 0xb3, 0xf9, 0x31, 0xe6, 0xff, 0xc7, 0x26, 0x7e, 0xc7, 0x6c, 0xd8, + 0x2c, 0x6f, 0xd7, 0xfc, 0xbd, 0x51, 0xdd, 0x33, 0xa2, 0x2e, 0x14, 0xe7, + 0xde, 0x50, 0xef, 0x4f, 0xcf, 0x36, 0xa8, 0xfa, 0xa7, 0x67, 0xd7, 0xde, + 0x15, 0x62, 0xd9, 0xdb, 0xb8, 0xbf, 0x21, 0x0b, 0x53, 0x0d, 0xb2, 0x38, + 0x1b, 0x60, 0xbc, 0x96, 0x6e, 0xac, 0x7d, 0x0b, 0xa3, 0xbf, 0x5b, 0x73, + 0x65, 0x08, 0xeb, 0x37, 0x3f, 0x30, 0x29, 0xe5, 0x01, 0xc6, 0x23, 0xea, + 0x3e, 0x20, 0x64, 0xa4, 0x01, 0x58, 0xb4, 0xe0, 0x96, 0x6d, 0xee, 0x03, + 0xb7, 0x68, 0xbd, 0x7e, 0x45, 0xc7, 0x7c, 0xe4, 0x91, 0x21, 0xb9, 0xbe, + 0x09, 0x45, 0x57, 0x59, 0xf1, 0xca, 0xff, 0xd6, 0x88, 0xfd, 0xf3, 0x7b, + 0xa3, 0xa0, 0xc6, 0xb2, 0xfb, 0x35, 0xcf, 0xff, 0x4a, 0xa7, 0x8f, 0xca, + 0x9e, 0x63, 0xbf, 0x0f, 0x5a, 0x9b, 0xbc, 0x3b, 0x4f, 0x52, 0xff, 0x3d, + 0x49, 0x48, 0x7d, 0xcf, 0x12, 0xb2, 0x1f, 0x45, 0x19, 0xf7, 0xc1, 0x1e, + 0x55, 0xf3, 0xe0, 0xbd, 0xba, 0x82, 0xfc, 0xaa, 0xfb, 0x21, 0x7e, 0x2c, + 0xc6, 0xbb, 0x4b, 0x51, 0xdd, 0xdf, 0x0e, 0xbd, 0x8e, 0x63, 0xb2, 0x07, + 0xbe, 0x26, 0x0f, 0x4c, 0xca, 0xfb, 0x5e, 0xe3, 0xc1, 0xfa, 0x31, 0x7d, + 0x59, 0xf6, 0xe2, 0x7c, 0xff, 0xde, 0x41, 0x50, 0xc5, 0x23, 0x2b, 0x7b, + 0x06, 0xba, 0x7c, 0x4c, 0xf6, 0x95, 0xd4, 0xde, 0x81, 0x3a, 0x2f, 0x9c, + 0x84, 0x4e, 0x0e, 0x2a, 0x7f, 0x12, 0x09, 0x0c, 0x55, 0xd2, 0x92, 0x3f, + 0xb9, 0x13, 0xe3, 0x70, 0x1f, 0x2e, 0xa3, 0xcf, 0xe5, 0x76, 0xcb, 0x9e, + 0xaa, 0x37, 0xf6, 0xde, 0x12, 0xdf, 0x27, 0xe1, 0xa3, 0xf9, 0x3e, 0x17, + 0x0f, 0xaa, 0x93, 0x85, 0x5b, 0xd1, 0xb6, 0x41, 0xf3, 0x96, 0xf7, 0xfc, + 0xd9, 0x9e, 0xfa, 0xf7, 0x4f, 0x4c, 0x89, 0xe6, 0xf0, 0x9e, 0x6d, 0xfc, + 0xfe, 0xf6, 0xc2, 0x67, 0x30, 0x36, 0x7e, 0x44, 0x96, 0xe6, 0x26, 0x65, + 0x79, 0xce, 0x97, 0x33, 0xde, 0xb9, 0x26, 0xed, 0x77, 0xeb, 0x3b, 0xd7, + 0x19, 0xac, 0xc3, 0x6a, 0x5e, 0xe5, 0x56, 0x7d, 0x8f, 0xf4, 0x75, 0xd3, + 0xfb, 0x26, 0x70, 0xbb, 0xba, 0x3f, 0xb5, 0x5a, 0xde, 0xd9, 0xcf, 0x57, + 0x4c, 0x9e, 0x33, 0x78, 0x77, 0xc0, 0xda, 0xeb, 0xde, 0xc7, 0xf4, 0xbd, + 0xab, 0xaf, 0xe9, 0xbb, 0xfa, 0xe4, 0xe7, 0xa8, 0xa6, 0xf7, 0x56, 0xe8, + 0x1e, 0xfb, 0x7c, 0x4c, 0xaf, 0x1b, 0xd2, 0x79, 0x3e, 0xab, 0xbb, 0xa6, + 0xfa, 0xec, 0xd5, 0xd4, 0x63, 0xd4, 0xdf, 0x7b, 0x6b, 0xa8, 0x1b, 0x97, + 0xed, 0xe9, 0x1b, 0xfc, 0x3b, 0xe0, 0x2c, 0x3b, 0xa6, 0xef, 0xd7, 0xf9, + 0x77, 0xbe, 0x59, 0xe6, 0xdf, 0x03, 0x23, 0xbf, 0xb8, 0x9f, 0x88, 0xb4, + 0x3a, 0xaa, 0x9f, 0x47, 0xeb, 0xbe, 0x1d, 0xf2, 0xfb, 0x0c, 0xa1, 0x8f, + 0x3b, 0x83, 0xd7, 0xde, 0x11, 0xe7, 0xb7, 0x54, 0x94, 0x45, 0x83, 0xdf, + 0x78, 0x33, 0x06, 0x03, 0x6e, 0xda, 0x28, 0x7b, 0x15, 0x3d, 0x05, 0x75, + 0x57, 0x22, 0xeb, 0x34, 0xc9, 0xa0, 0xe9, 0xe5, 0xf7, 0xce, 0xaf, 0x95, + 0x53, 0x96, 0x6f, 0x8a, 0x48, 0x94, 0xdf, 0x70, 0xf1, 0xfd, 0x7a, 0xdf, + 0x2e, 0x84, 0xf5, 0xf7, 0x53, 0x0e, 0xda, 0x7c, 0x9e, 0xf2, 0x5e, 0x28, + 0xac, 0xdc, 0xd1, 0x2c, 0xa8, 0x3d, 0x52, 0x00, 0x73, 0x7d, 0x57, 0x92, + 0xdf, 0xb0, 0x8b, 0x3c, 0x5d, 0xe1, 0xb7, 0x5c, 0xdb, 0xd5, 0x1d, 0x16, + 0xef, 0x5c, 0x90, 0x74, 0x75, 0x29, 0x9b, 0x5c, 0xae, 0x14, 0xc9, 0x53, + 0xed, 0x57, 0xc3, 0xda, 0xaf, 0x92, 0xc7, 0xc3, 0xe0, 0xf1, 0x5f, 0xeb, + 0x75, 0x61, 0xfb, 0x8c, 0xba, 0x0b, 0x9e, 0x89, 0xf1, 0x6c, 0xea, 0x31, + 0x35, 0x17, 0xda, 0x68, 0xb4, 0x7d, 0x47, 0x50, 0xe9, 0xae, 0xfa, 0x46, + 0x1e, 0xf2, 0xc9, 0x6f, 0xde, 0x61, 0x5f, 0x4b, 0xfc, 0xb6, 0x7d, 0x58, + 0x7d, 0x67, 0x52, 0xae, 0x70, 0x5d, 0xf9, 0x4d, 0xfb, 0x68, 0x9d, 0x3c, + 0x06, 0xf5, 0x58, 0x9b, 0x5a, 0x25, 0xea, 0xad, 0x3b, 0xbf, 0x51, 0x29, + 0x57, 0xfc, 0xfb, 0x9d, 0x1b, 0x96, 0xa8, 0x13, 0xa2, 0x62, 0x6c, 0xef, + 0x3b, 0x9b, 0xb2, 0xfa, 0x6e, 0x25, 0xc1, 0xef, 0x2e, 0xe1, 0x3b, 0x76, + 0xe1, 0x99, 0x67, 0xba, 0xbb, 0x91, 0xc2, 0xe6, 0x54, 0xc6, 0x91, 0x3e, + 0x2c, 0x39, 0xb5, 0xe7, 0xd6, 0x8c, 0xfc, 0x5e, 0x35, 0x76, 0xb1, 0xf2, + 0x80, 0xec, 0x39, 0xf9, 0x10, 0xbf, 0xed, 0x51, 0xdf, 0xe5, 0x67, 0x1d, + 0xd2, 0x18, 0x93, 0x09, 0x35, 0xef, 0x42, 0xed, 0x9b, 0x11, 0xc5, 0xfb, + 0x5c, 0x2b, 0xd7, 0xb4, 0x50, 0x69, 0x06, 0x8d, 0x01, 0x7d, 0xc7, 0x93, + 0x58, 0xdc, 0x9f, 0x7f, 0x94, 0xf7, 0x06, 0x5d, 0x9e, 0xdd, 0xed, 0x29, + 0xf1, 0x0e, 0x67, 0x52, 0xc7, 0xe8, 0xdc, 0xb7, 0xe3, 0xd9, 0x00, 0x65, + 0xdc, 0x4a, 0x8d, 0xc3, 0xfa, 0x87, 0x25, 0xce, 0x73, 0x65, 0x3d, 0x97, + 0xe6, 0xba, 0xb9, 0xf0, 0xde, 0xaa, 0x37, 0x1f, 0x7e, 0x0b, 0x93, 0x2f, + 0xd5, 0x7f, 0xc7, 0xa3, 0xbe, 0x11, 0x57, 0xdf, 0xcd, 0x8c, 0x57, 0x3e, + 0x21, 0x1f, 0x2b, 0x6d, 0xd4, 0xdf, 0xf0, 0x44, 0xe4, 0x63, 0x95, 0xd7, + 0x14, 0x4f, 0xf3, 0xea, 0xfb, 0xa3, 0xb0, 0x5e, 0xb3, 0x98, 0xea, 0xa3, + 0xf6, 0x1d, 0x92, 0x55, 0xf7, 0x4d, 0x4a, 0x58, 0xc6, 0xe7, 0x7f, 0xd9, + 0xb7, 0x48, 0x8f, 0x08, 0xbf, 0x47, 0xb9, 0xe4, 0x4c, 0xca, 0xe3, 0x73, + 0xae, 0x7b, 0x97, 0x43, 0x5c, 0xb7, 0x41, 0x96, 0x63, 0xa3, 0x3b, 0xbe, + 0x67, 0xb7, 0x05, 0xca, 0x33, 0x8d, 0xb0, 0xd7, 0xc4, 0x12, 0x12, 0x65, + 0x7e, 0x7e, 0x86, 0x7a, 0x1a, 0xc2, 0x1c, 0x2d, 0xf3, 0xaa, 0x7c, 0xa6, + 0x95, 0x7b, 0x5e, 0x77, 0x21, 0x8e, 0xfc, 0xb8, 0xe3, 0xd9, 0xe5, 0xcf, + 0x2d, 0xec, 0x94, 0xcf, 0x55, 0x22, 0x81, 0xf2, 0x14, 0xef, 0xfa, 0x59, + 0xc3, 0x73, 0x92, 0x44, 0x3d, 0xf6, 0x0f, 0x79, 0x89, 0x6f, 0x96, 0xa7, + 0x8e, 0xfd, 0xc2, 0xbd, 0x6a, 0xe3, 0x3d, 0x6c, 0xcd, 0xb2, 0xe3, 0xef, + 0xeb, 0x21, 0x86, 0x3f, 0xc2, 0x7a, 0x9b, 0x21, 0x07, 0xf0, 0xdb, 0xd0, + 0x39, 0xc6, 0x98, 0x57, 0xb5, 0xdd, 0x32, 0x8e, 0xdc, 0x2c, 0x57, 0x57, + 0xee, 0x0a, 0x5f, 0x86, 0x6c, 0x27, 0x3c, 0xfe, 0xab, 0x7d, 0xf0, 0x03, + 0x12, 0xfc, 0x22, 0xfc, 0xc4, 0x17, 0x1b, 0x94, 0x6d, 0xa7, 0x3f, 0x43, + 0xfc, 0x81, 0x18, 0x23, 0x84, 0x7e, 0x1e, 0x6c, 0xf5, 0x64, 0x76, 0x52, + 0xe4, 0xcb, 0x4d, 0x92, 0x69, 0x65, 0x0c, 0x2b, 0xbf, 0xc2, 0x7e, 0xd5, + 0xeb, 0x59, 0x4a, 0xbe, 0x42, 0x1d, 0xaf, 0x72, 0x2e, 0xc9, 0xf8, 0x8f, + 0xe5, 0x93, 0x32, 0x1e, 0xe7, 0x5c, 0x1e, 0x91, 0xc2, 0xdc, 0x63, 0xf8, + 0x71, 0x9e, 0xa4, 0xfb, 0x1f, 0xe8, 0x7b, 0x04, 0xa3, 0x52, 0x9c, 0x4a, + 0xcb, 0xc4, 0xec, 0x5e, 0x7e, 0xa3, 0x3b, 0x7c, 0x97, 0x3a, 0x5f, 0xb3, + 0xe2, 0xc9, 0x40, 0x6f, 0x62, 0x82, 0xf7, 0x26, 0xd4, 0x7c, 0xf6, 0x62, + 0x3e, 0xdf, 0x6a, 0xe5, 0xdd, 0xf3, 0xab, 0xb0, 0xbf, 0xc6, 0x71, 0xca, + 0xa1, 0x65, 0x76, 0x06, 0x98, 0xdf, 0x8d, 0xd8, 0x99, 0x65, 0xbb, 0x25, + 0x78, 0x64, 0xc5, 0xce, 0xa3, 0x5c, 0x9f, 0xf3, 0xaa, 0xf6, 0xff, 0x11, + 0x6d, 0x51, 0xef, 0x88, 0xdf, 0xd6, 0xaf, 0xc3, 0xb6, 0x9c, 0xe7, 0x4e, + 0xc4, 0xec, 0x3e, 0x5d, 0x90, 0xc3, 0x78, 0x3d, 0xbf, 0xa3, 0x6b, 0xf8, + 0x1d, 0x22, 0xde, 0x04, 0xbf, 0xc8, 0xe3, 0xa0, 0xe6, 0xf1, 0x9b, 0xe8, + 0xdf, 0x5f, 0x83, 0xbb, 0x50, 0x66, 0xea, 0x6f, 0x03, 0xdf, 0x0a, 0xdf, + 0xc9, 0x73, 0xd6, 0x7f, 0xb0, 0xd5, 0x93, 0x35, 0xd2, 0xb3, 0x1e, 0xcf, + 0x3b, 0xdb, 0xbc, 0x75, 0xd9, 0x0d, 0x7e, 0xf1, 0x4e, 0x67, 0xaf, 0xfa, + 0x4e, 0x20, 0x33, 0xb6, 0x1b, 0xb2, 0xe3, 0xcf, 0xab, 0x17, 0x32, 0xc6, + 0x33, 0x0b, 0xd6, 0xaf, 0xe7, 0x89, 0xe7, 0xf7, 0x82, 0xdc, 0x77, 0xb0, + 0x39, 0x57, 0x60, 0xc2, 0x2f, 0xab, 0xef, 0x82, 0x60, 0x27, 0xdf, 0xb6, + 0xf2, 0x5d, 0xd0, 0xf5, 0xd7, 0x78, 0xa0, 0xcd, 0xf3, 0x51, 0x26, 0x78, + 0xd2, 0xa2, 0xdb, 0xec, 0x06, 0x3e, 0xe5, 0x5e, 0x6c, 0x32, 0xfe, 0xa0, + 0xf8, 0xe3, 0xb8, 0xdb, 0x19, 0x73, 0x0e, 0xf6, 0xf7, 0x22, 0xbe, 0x56, + 0xf7, 0x65, 0xe2, 0xbc, 0x7f, 0x93, 0x0c, 0xec, 0x56, 0x77, 0x27, 0x2e, + 0xac, 0xfa, 0xb6, 0x2b, 0x25, 0x4f, 0xd5, 0x64, 0x65, 0xf8, 0x27, 0x62, + 0x49, 0xe2, 0x26, 0xca, 0x0a, 0xfb, 0xdd, 0xcb, 0x79, 0xc6, 0x1f, 0x52, + 0xf3, 0x34, 0x11, 0xc3, 0xf1, 0x9e, 0x83, 0x19, 0x28, 0xcf, 0x72, 0xdd, + 0x91, 0x2e, 0xf0, 0xd9, 0x3f, 0x6b, 0x55, 0x76, 0x05, 0xe3, 0xb2, 0x8c, + 0xb6, 0x91, 0xef, 0xd3, 0xfa, 0x2c, 0xf6, 0xc3, 0x6d, 0xbc, 0x0f, 0x90, + 0x47, 0xd9, 0xdc, 0xc2, 0xfa, 0xb4, 0x7d, 0x5c, 0xc9, 0xc1, 0x23, 0xe0, + 0xfb, 0x1f, 0xa3, 0xee, 0x63, 0x48, 0x39, 0xc7, 0xf4, 0xca, 0xba, 0x93, + 0xdf, 0x1f, 0x90, 0x01, 0xc8, 0x05, 0xf3, 0x8f, 0x48, 0x51, 0xdd, 0x63, + 0x42, 0x3a, 0xc7, 0x67, 0xda, 0x7a, 0x5b, 0xfb, 0x53, 0xd2, 0xb2, 0x5b, + 0x7f, 0x4f, 0xe6, 0xcb, 0xd3, 0x2e, 0xdd, 0x6e, 0x6c, 0x85, 0x57, 0x0f, + 0x5d, 0x83, 0x37, 0xc2, 0x2b, 0x78, 0xc3, 0x1b, 0xeb, 0xf1, 0x36, 0x1f, + 0x6b, 0x78, 0x73, 0xf0, 0xb0, 0x86, 0x27, 0xe7, 0x7b, 0x25, 0x04, 0x39, + 0x0e, 0xd6, 0xe4, 0x18, 0xb8, 0xc7, 0xd3, 0x99, 0x09, 0x9e, 0x21, 0x2a, + 0x3e, 0x53, 0x0e, 0x29, 0xbf, 0x5c, 0xc7, 0xfa, 0xb5, 0x7e, 0xcf, 0x2f, + 0x59, 0xeb, 0x97, 0xdb, 0x7c, 0xfc, 0xf0, 0x77, 0xd3, 0x83, 0x0b, 0x6d, + 0x35, 0x3d, 0xb8, 0xf9, 0x37, 0xa4, 0x07, 0x6b, 0xe5, 0xb2, 0x5e, 0xa6, + 0x4c, 0xc8, 0x13, 0xd7, 0x8b, 0xf2, 0x44, 0x39, 0x22, 0x2f, 0x69, 0x4f, + 0x1b, 0x19, 0x3b, 0xc5, 0xaf, 0xa8, 0xef, 0x36, 0x26, 0x61, 0x83, 0xda, + 0x02, 0x73, 0x73, 0x31, 0x29, 0x2e, 0xbc, 0x4f, 0xc9, 0xf4, 0x53, 0x55, + 0xda, 0xa5, 0xeb, 0xcd, 0x7d, 0xb5, 0xcd, 0xcd, 0xaf, 0xb1, 0xb9, 0xf9, + 0x15, 0x9b, 0xdb, 0xaa, 0xe3, 0xa5, 0xbf, 0x8b, 0xcd, 0x8d, 0xd5, 0x9d, + 0xcb, 0xf8, 0x67, 0x32, 0x12, 0xc8, 0xf6, 0x44, 0x65, 0x07, 0xfc, 0xc8, + 0xf0, 0xd4, 0x4e, 0xf9, 0x97, 0x53, 0x93, 0xea, 0x8e, 0xd2, 0x5f, 0x38, + 0xc9, 0xf8, 0x03, 0x01, 0x57, 0x3e, 0x80, 0x78, 0x77, 0xbc, 0xa3, 0x41, + 0x76, 0xbc, 0x4b, 0x9d, 0x35, 0x9a, 0xd9, 0x40, 0xbb, 0x70, 0x17, 0x3c, + 0xe7, 0x58, 0x4e, 0x22, 0xc0, 0xfb, 0x6a, 0x8d, 0x32, 0x1e, 0x6b, 0x96, + 0x9d, 0xc0, 0x4e, 0x85, 0x1b, 0x1c, 0xf5, 0x2d, 0x79, 0x46, 0x9d, 0xe5, + 0xdc, 0xb2, 0xd9, 0x1b, 0x17, 0x7c, 0x68, 0x31, 0xe5, 0xab, 0xd5, 0x5b, + 0xd4, 0x77, 0xd1, 0x17, 0x4a, 0xd5, 0xd6, 0xd5, 0x79, 0x3e, 0xff, 0x7b, + 0xd4, 0x89, 0x81, 0x57, 0xf5, 0x77, 0x7f, 0x82, 0x8a, 0x9f, 0xc5, 0xb9, + 0x31, 0x75, 0xa7, 0xea, 0x4a, 0x90, 0xfc, 0x52, 0x71, 0x53, 0x3c, 0x1b, + 0x04, 0xc6, 0x99, 0x01, 0x92, 0xb6, 0x19, 0xf3, 0x69, 0xfc, 0x09, 0xfb, + 0xbf, 0x47, 0x9d, 0xed, 0x2e, 0x81, 0x37, 0xae, 0xda, 0xfb, 0xcd, 0xc7, + 0x88, 0xeb, 0x6b, 0xf7, 0x87, 0xaf, 0xc5, 0xf7, 0xde, 0xb7, 0x67, 0xfa, + 0x1c, 0x42, 0xef, 0x15, 0xe9, 0x18, 0x5c, 0x9d, 0xab, 0xad, 0xf7, 0x7f, + 0x29, 0x88, 0xf5, 0xf8, 0x7f, 0x0f, 0x88, 0xed, 0xac, 0xc3, 0x73, 0xe2, + 0xa8, 0x38, 0x30, 0x43, 0xfe, 0x96, 0xb1, 0x4e, 0xd3, 0x71, 0xdf, 0x9f, + 0x07, 0x3a, 0xcf, 0xd6, 0xc7, 0x81, 0xec, 0x23, 0xa2, 0xee, 0x63, 0xd4, + 0xfe, 0x0f, 0x0e, 0xf7, 0x77, 0x32, 0x81, 0x7b, 0x4a, 0x93, 0x12, 0x3c, + 0x3a, 0x2a, 0xa1, 0x69, 0xee, 0xa5, 0x67, 0xa4, 0x18, 0x73, 0xe5, 0x63, + 0xce, 0xea, 0xd8, 0xa4, 0xd3, 0x58, 0x4b, 0xfb, 0x23, 0x32, 0x78, 0xf2, + 0x31, 0x09, 0x1f, 0xe5, 0xbb, 0x55, 0xe7, 0x28, 0xb0, 0x47, 0x1b, 0x64, + 0x2e, 0xc6, 0xfd, 0xe4, 0xb0, 0x3a, 0x97, 0x5e, 0x1e, 0x7b, 0x2d, 0x5c, + 0x04, 0x56, 0xc8, 0x2b, 0xdb, 0x82, 0x74, 0x25, 0x96, 0x38, 0xbc, 0x99, + 0x3a, 0x85, 0x18, 0x33, 0x30, 0x3e, 0x17, 0x56, 0xf7, 0x83, 0x96, 0x63, + 0xac, 0x8b, 0xf8, 0xfd, 0x28, 0x71, 0x06, 0x6c, 0xc7, 0xa8, 0x44, 0x99, + 0x0f, 0x1e, 0xad, 0xe1, 0x0c, 0xda, 0x84, 0x41, 0x27, 0x26, 0xa1, 0x53, + 0xde, 0xdc, 0xf9, 0x8f, 0x95, 0x8c, 0x13, 0x3b, 0x25, 0x38, 0xcd, 0xe7, + 0xfa, 0x78, 0x88, 0xd8, 0x1d, 0xbe, 0xe1, 0xec, 0x67, 0xd1, 0x1f, 0xdf, + 0x65, 0xf4, 0x37, 0xba, 0xc8, 0x97, 0xff, 0xb6, 0xff, 0x43, 0x81, 0xb2, + 0xff, 0xff, 0x01, 0xe6, 0x8e, 0x9a, 0x21, 0xc0, 0x4e, 0x00, 0x00, 0x00 }; static const u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 }; static const u32 bnx2_COM_b06FwRodata[(0x14/4) + 1] = { - 0x08000f04, 0x08000f4c, 0x08000f80, 0x08000fcc, 0x08001000, 0x00000000 + 0x08000e7c, 0x08000ec4, 0x08000ef8, 0x08000f44, 0x08000f78, 0x00000000 }; static struct fw_info bnx2_com_fw_06 = { - /* Firmware version: 4.0.5 */ + /* Firmware version: 4.4.2 */ .ver_major = 0x4, - .ver_minor = 0x0, - .ver_fix = 0x5, + .ver_minor = 0x4, + .ver_fix = 0x2, .start_addr = 0x080000f8, .text_addr = 0x08000000, - .text_len = 0x4eac, + .text_len = 0x4ebc, .text_index = 0x0, .gz_text = bnx2_COM_b06FwText, .gz_text_len = sizeof(bnx2_COM_b06FwText), @@ -872,15 +872,15 @@ static struct fw_info bnx2_com_fw_06 = { .data_index = 0x0, .data = bnx2_COM_b06FwData, - .sbss_addr = 0x08004ee0, + .sbss_addr = 0x08004f00, .sbss_len = 0x38, .sbss_index = 0x0, - .bss_addr = 0x08004f18, + .bss_addr = 0x08004f38, .bss_len = 0xbc, .bss_index = 0x0, - .rodata_addr = 0x08004eac, + .rodata_addr = 0x08004ebc, .rodata_len = 0x14, .rodata_index = 0x0, .rodata = bnx2_COM_b06FwRodata, @@ -902,1231 +902,1232 @@ static const struct cpu_reg cpu_reg_com = { .mips_view_base = 0x8000000, }; - static u8 bnx2_CP_b06FwText[] = { - 0x9d, 0xbc, 0x0d, 0x78, 0x13, 0xe7, 0x99, 0x2e, 0x7c, 0xcf, 0x48, 0xb2, - 0x65, 0x5b, 0xb6, 0xc7, 0xb6, 0x0c, 0x22, 0x65, 0x41, 0x83, 0x47, 0x20, - 0x62, 0x27, 0x1d, 0x81, 0x49, 0x94, 0xac, 0x36, 0xa8, 0xc6, 0x01, 0x93, - 0x90, 0xc6, 0x34, 0xb4, 0x75, 0x7a, 0xd2, 0x8d, 0x62, 0x0c, 0x21, 0x84, - 0x10, 0x67, 0x9b, 0x9e, 0xe3, 0x7c, 0x5f, 0xce, 0x5a, 0x35, 0x06, 0x0c, - 0xc8, 0x96, 0x31, 0x0e, 0x90, 0xfd, 0x7a, 0x9d, 0x18, 0x6c, 0x30, 0x49, - 0x65, 0x8b, 0x34, 0x74, 0x97, 0xf4, 0xa3, 0x45, 0x07, 0xf2, 0xe3, 0xfc, - 0x35, 0xa4, 0xed, 0x76, 0xdb, 0x3d, 0x39, 0x89, 0x0f, 0x25, 0x84, 0xb4, - 0xdd, 0xfc, 0xb4, 0xdd, 0x2d, 0x69, 0x9b, 0xcc, 0x77, 0x3f, 0x23, 0x09, - 0x0c, 0x4d, 0x7f, 0xf6, 0xf3, 0x75, 0xcd, 0x65, 0xcd, 0xcc, 0xfb, 0xf3, - 0xbc, 0xcf, 0xfb, 0x3c, 0xf7, 0x73, 0x3f, 0xef, 0xbc, 0x33, 0xb3, 0x80, - 0x62, 0xe4, 0xfe, 0x4a, 0x79, 0x5c, 0x5d, 0xdf, 0xbe, 0x1a, 0x8b, 0xae, - 0x36, 0xe5, 0xdc, 0xe9, 0x82, 0x13, 0x7f, 0xe1, 0x9f, 0xff, 0x2f, 0x2d, - 0x38, 0xe5, 0xcf, 0x01, 0x68, 0xf9, 0x7e, 0xe5, 0x80, 0x5b, 0x8d, 0x3c, - 0xf3, 0x5f, 0x1a, 0x0c, 0xb8, 0x1d, 0x91, 0x9e, 0xd6, 0xd5, 0x06, 0x10, - 0x4d, 0xd5, 0xfa, 0x97, 0xe0, 0x23, 0x2b, 0xee, 0x75, 0x42, 0xae, 0xff, - 0x55, 0xe4, 0xf7, 0x9d, 0xdf, 0xb9, 0x56, 0x7f, 0x7f, 0xc8, 0x01, 0xb7, - 0x16, 0xe9, 0x80, 0x36, 0x17, 0xee, 0x99, 0xac, 0xf3, 0xf5, 0x79, 0xdb, - 0x15, 0x94, 0xe5, 0xdb, 0x3a, 0x67, 0x7d, 0x67, 0x9e, 0x2f, 0x56, 0x14, - 0xd1, 0x70, 0x3c, 0x8d, 0xe6, 0xba, 0xde, 0x4e, 0xab, 0xd4, 0x08, 0xc1, - 0x6d, 0x18, 0x2d, 0xbd, 0x8a, 0x27, 0xbc, 0x7e, 0x11, 0x3c, 0x85, 0x06, - 0xe2, 0x57, 0x44, 0xd0, 0x7c, 0xe5, 0x58, 0x71, 0xdc, 0x19, 0x71, 0xa3, - 0x29, 0xed, 0x8e, 0x7f, 0x2a, 0x62, 0x60, 0x59, 0xfa, 0xfa, 0x62, 0x94, - 0xb9, 0xd1, 0x9d, 0xfe, 0xa8, 0x28, 0xdb, 0x5e, 0x73, 0xee, 0xff, 0xec, - 0xaa, 0xec, 0xff, 0x69, 0x31, 0x67, 0x04, 0xd8, 0x9c, 0xb0, 0xac, 0x82, - 0xc8, 0x6d, 0xb7, 0xa9, 0x11, 0xc3, 0x77, 0x10, 0x8b, 0xd1, 0xaa, 0xe1, - 0xe1, 0x2d, 0xf5, 0xbf, 0x54, 0x4e, 0x0c, 0xb2, 0xe1, 0x51, 0x07, 0xa2, - 0xda, 0x33, 0xfc, 0x3f, 0x6b, 0x56, 0x4b, 0xd8, 0xc0, 0xde, 0xd1, 0xf3, - 0xbc, 0xee, 0xb4, 0xaf, 0x6d, 0xda, 0x33, 0x6b, 0xd6, 0xed, 0xe1, 0x67, - 0xf0, 0xe8, 0xa8, 0xfc, 0xbe, 0x1b, 0x9d, 0x75, 0x0a, 0x26, 0x6f, 0x5b, - 0x0b, 0x87, 0x61, 0xa0, 0x7b, 0x8f, 0xe2, 0xec, 0xaa, 0x53, 0x11, 0xf5, - 0xea, 0xc1, 0x18, 0x95, 0xef, 0x34, 0x10, 0x2b, 0x8c, 0x84, 0x9d, 0xef, - 0x24, 0x22, 0x9a, 0xc3, 0xb0, 0xac, 0x60, 0x68, 0x3a, 0x1c, 0x15, 0x96, - 0xf5, 0xb4, 0xe9, 0x81, 0xff, 0x8b, 0xcf, 0x21, 0x3e, 0xdc, 0x0c, 0xd5, - 0x78, 0x0e, 0x5d, 0xc3, 0xcf, 0xe1, 0xb1, 0x5d, 0xc5, 0x98, 0xac, 0xe2, - 0x78, 0x93, 0x3e, 0x7c, 0x67, 0x9e, 0xf4, 0x2d, 0x72, 0xd4, 0xf1, 0x70, - 0x63, 0xd2, 0xf1, 0x06, 0xff, 0x4b, 0x99, 0xf3, 0xd6, 0xe4, 0xf4, 0x8b, - 0x65, 0x36, 0xb3, 0x4c, 0xf7, 0x65, 0x65, 0xe2, 0xc3, 0x11, 0xbc, 0x94, - 0x50, 0xb0, 0x3e, 0x54, 0x86, 0x68, 0x85, 0x8c, 0xd7, 0xb2, 0x46, 0xcd, - 0xb3, 0xd6, 0xa4, 0x26, 0x7d, 0x4d, 0xe0, 0x65, 0xde, 0xdb, 0x12, 0x3a, - 0x63, 0x65, 0xbc, 0xd2, 0x5e, 0x3b, 0x6d, 0x67, 0x25, 0xaf, 0x3b, 0x91, - 0x4c, 0x20, 0x56, 0x16, 0xb9, 0x8d, 0xe7, 0xba, 0xf9, 0xae, 0xe2, 0x76, - 0xbf, 0x97, 0x70, 0x7f, 0xb1, 0xd4, 0x50, 0x1f, 0x2c, 0xa7, 0x01, 0xbd, - 0x42, 0x99, 0x8f, 0x9a, 0x6b, 0xe1, 0x32, 0x1e, 0x10, 0x5b, 0xe3, 0xb8, - 0x7e, 0x68, 0x61, 0x7a, 0xbe, 0xbe, 0xb4, 0xeb, 0xc6, 0x96, 0xa4, 0x65, - 0x6d, 0x33, 0xa3, 0xd7, 0x15, 0xd1, 0x20, 0x4e, 0x26, 0x9a, 0xe1, 0x8e, - 0x04, 0xfc, 0xe7, 0x10, 0xc6, 0x92, 0xb4, 0x17, 0xcf, 0x26, 0xe0, 0x6c, - 0x98, 0xe7, 0x45, 0x57, 0x3a, 0x82, 0x1b, 0xd3, 0x26, 0x1a, 0xd3, 0x7f, - 0xde, 0xb2, 0x6e, 0x4e, 0xfa, 0x39, 0x86, 0x8f, 0xac, 0xec, 0x18, 0x64, - 0x7c, 0xd9, 0xff, 0xdd, 0xc9, 0x2b, 0xb0, 0x9d, 0x73, 0xb4, 0x95, 0xf3, - 0xb7, 0x3c, 0x94, 0x89, 0x16, 0x41, 0x37, 0xcf, 0x21, 0x82, 0xa5, 0x69, - 0x83, 0x73, 0x1a, 0xc1, 0x92, 0x64, 0x8d, 0x36, 0x8c, 0xf9, 0x88, 0xfa, - 0xb2, 0x36, 0xbd, 0x83, 0xe3, 0x6d, 0x0d, 0x34, 0xa3, 0x94, 0x36, 0x92, - 0x5a, 0x14, 0x46, 0x03, 0xfb, 0x5f, 0xf1, 0x17, 0xf4, 0x7f, 0x2b, 0xfb, - 0x7f, 0x97, 0xfd, 0x67, 0xec, 0xfe, 0xe1, 0xbc, 0x89, 0xe7, 0x6e, 0xda, - 0xe3, 0xf6, 0x94, 0xd3, 0xb9, 0x3c, 0xe9, 0xc5, 0xb6, 0x94, 0x49, 0x9b, - 0x93, 0x5b, 0x3e, 0x6c, 0x19, 0x9c, 0x89, 0xad, 0x83, 0xba, 0xef, 0x79, - 0xfe, 0xde, 0x34, 0x72, 0x05, 0x36, 0x0f, 0x2a, 0xd8, 0x6f, 0x5c, 0x81, - 0x2e, 0xfe, 0xde, 0x3b, 0x38, 0x0b, 0x8f, 0x0e, 0x3a, 0x10, 0xae, 0xba, - 0x74, 0x1c, 0x93, 0x8e, 0x2b, 0x10, 0x1f, 0xf1, 0xa3, 0x2b, 0xf1, 0xa2, - 0xad, 0xc3, 0xd2, 0xc8, 0xff, 0x9b, 0xf7, 0x63, 0xfa, 0x8e, 0x1f, 0xab, - 0x13, 0x1a, 0xba, 0x92, 0x0e, 0xb1, 0x4b, 0xfe, 0xfd, 0x92, 0xf7, 0x34, - 0x6c, 0x4a, 0xe7, 0xeb, 0x8b, 0x9f, 0xf9, 0xd1, 0x90, 0x98, 0xa0, 0x9f, - 0xd4, 0xd3, 0x47, 0x4c, 0x7c, 0x37, 0x5d, 0x87, 0x7f, 0x4a, 0x07, 0xf1, - 0x8f, 0xd4, 0xc3, 0xb7, 0xd2, 0x7e, 0x1c, 0x49, 0xcf, 0xc4, 0x53, 0x69, - 0x1f, 0xbe, 0x49, 0xfd, 0x3f, 0x99, 0x6e, 0xa6, 0xed, 0x6a, 0x38, 0x9c, - 0x16, 0xfd, 0x15, 0x50, 0xde, 0x62, 0x6c, 0x1a, 0xac, 0x09, 0x9e, 0xa4, - 0x6d, 0xfc, 0xa3, 0x79, 0x13, 0x32, 0x95, 0xf5, 0xb6, 0x4d, 0x6d, 0xe3, - 0xf5, 0xed, 0x83, 0x35, 0xd1, 0x2b, 0x15, 0xcb, 0x52, 0x43, 0xb5, 0xe1, - 0x13, 0xaa, 0x8a, 0x49, 0xaf, 0xee, 0xcf, 0xa8, 0xba, 0x3f, 0x0a, 0x17, - 0x12, 0xb4, 0xed, 0x78, 0xb5, 0x3e, 0x14, 0xa7, 0x4d, 0x78, 0x8d, 0x7d, - 0x40, 0x99, 0xee, 0x8f, 0xab, 0x6e, 0x6c, 0x4d, 0xea, 0x7b, 0xe3, 0xaa, - 0x07, 0xf1, 0x74, 0x31, 0xfe, 0x6d, 0x50, 0xef, 0x89, 0xab, 0x9f, 0x45, - 0xbc, 0xd2, 0xb2, 0xbe, 0x19, 0x42, 0xfb, 0xf4, 0x08, 0xa2, 0xd5, 0x11, - 0xc4, 0x66, 0x45, 0xbc, 0x48, 0x26, 0x81, 0x77, 0x7b, 0x0d, 0xdf, 0xbf, - 0x28, 0xcd, 0xf8, 0x6a, 0xb3, 0xee, 0xf7, 0xab, 0xb5, 0xf1, 0x61, 0x75, - 0x11, 0x5d, 0x12, 0x7e, 0x5f, 0x64, 0x19, 0x3a, 0xec, 0x6b, 0x0a, 0x34, - 0xc3, 0x83, 0x4d, 0xc9, 0xeb, 0x10, 0xf3, 0xd6, 0xb4, 0xec, 0x54, 0x6b, - 0xce, 0x9b, 0xaa, 0x3e, 0xd1, 0xac, 0x5a, 0xd6, 0x07, 0x0b, 0xdf, 0xb5, - 0xfc, 0xd3, 0x2c, 0x6b, 0xc1, 0x42, 0xe9, 0xd3, 0x8f, 0x8a, 0x88, 0x89, - 0x95, 0xf6, 0x1c, 0x14, 0xe3, 0xec, 0x60, 0x25, 0xfb, 0xd0, 0xf0, 0xcf, - 0xd7, 0xea, 0xc1, 0xb5, 0x6a, 0x31, 0xde, 0x1a, 0x29, 0xc6, 0x69, 0x8e, - 0xe7, 0x97, 0x83, 0x3e, 0xfc, 0x7a, 0xd0, 0xb2, 0xbe, 0x68, 0xfe, 0x35, - 0x06, 0x2a, 0xfb, 0xf1, 0x4f, 0xe3, 0x5e, 0xfc, 0x1b, 0x75, 0x7b, 0x26, - 0x11, 0x7d, 0xa0, 0x0a, 0x7a, 0x74, 0x5c, 0x39, 0x79, 0x67, 0x19, 0x6a, - 0x9b, 0xcb, 0x14, 0xbd, 0x69, 0x07, 0x74, 0xdf, 0x95, 0x8a, 0x17, 0xe7, - 0x52, 0x1a, 0x7e, 0x9a, 0xaa, 0x09, 0xff, 0x80, 0x7d, 0xfe, 0x87, 0xf9, - 0xb4, 0x95, 0x99, 0x26, 0x7a, 0x13, 0x1d, 0x51, 0xcf, 0x49, 0xea, 0x39, - 0x49, 0x3d, 0x27, 0xa9, 0x67, 0xca, 0x70, 0x24, 0x49, 0x3d, 0x53, 0x77, - 0xdf, 0xa4, 0x4d, 0x3c, 0x99, 0xa4, 0x8e, 0x93, 0x32, 0x47, 0x61, 0xfa, - 0xe7, 0xa7, 0xf0, 0xf7, 0xf6, 0xdc, 0xbd, 0x6c, 0xfd, 0x37, 0xaf, 0x8c, - 0xe9, 0xfe, 0x69, 0x59, 0xfc, 0x91, 0xb1, 0xbd, 0x64, 0xc5, 0x34, 0x19, - 0x97, 0x8c, 0xcf, 0xd6, 0x9f, 0xbf, 0x5d, 0xf9, 0xaa, 0x82, 0x62, 0xcb, - 0xda, 0x65, 0xe6, 0xee, 0x7b, 0xf3, 0xe3, 0xfb, 0x8c, 0x92, 0xb5, 0x8b, - 0x7f, 0x72, 0x53, 0xdf, 0xc1, 0xa8, 0xba, 0x88, 0xe7, 0x7a, 0x3c, 0x8a, - 0x9b, 0x0a, 0x2f, 0x3d, 0xbf, 0xb6, 0x5a, 0xe6, 0xc3, 0x7f, 0xe1, 0x9c, - 0xf6, 0x64, 0xf7, 0xf7, 0x45, 0x9e, 0xcb, 0x58, 0x04, 0x53, 0xc5, 0x06, - 0xbc, 0xb4, 0x97, 0x45, 0xb9, 0x7b, 0x88, 0xab, 0x91, 0x76, 0x34, 0xd7, - 0xef, 0xb5, 0xfb, 0x28, 0xe8, 0x13, 0xbb, 0x57, 0xf0, 0xee, 0x75, 0x0a, - 0x4e, 0x84, 0x0c, 0xda, 0xcc, 0x10, 0xfd, 0x1a, 0x28, 0xec, 0x83, 0xdb, - 0x13, 0x89, 0x20, 0xd1, 0x0b, 0x77, 0x51, 0x24, 0x8c, 0xf9, 0xbd, 0x35, - 0xeb, 0xce, 0x42, 0x0f, 0xf6, 0x2a, 0x7a, 0x33, 0x50, 0x6b, 0x8e, 0x51, - 0x8f, 0x57, 0x2a, 0xba, 0xbf, 0x40, 0x81, 0x5b, 0x61, 0xb9, 0x40, 0x6a, - 0x08, 0x5b, 0xd3, 0xf2, 0x3b, 0x0c, 0x23, 0xf5, 0xeb, 0x7c, 0x5f, 0xb4, - 0xeb, 0x76, 0xda, 0xf5, 0x59, 0x8e, 0x5d, 0xf7, 0x13, 0x1f, 0xdd, 0xae, - 0xc8, 0x3a, 0x1c, 0x48, 0xc0, 0x5d, 0x10, 0xd9, 0x80, 0xe7, 0x12, 0x1f, - 0x57, 0xe7, 0xcb, 0x29, 0x2c, 0xe7, 0x4f, 0x4d, 0x95, 0xe5, 0x0d, 0x2b, - 0xea, 0xcd, 0xca, 0x52, 0xdc, 0x37, 0x84, 0x1d, 0x49, 0xa9, 0x1b, 0xb1, - 0xeb, 0x3a, 0xd9, 0x47, 0x77, 0xa2, 0xa6, 0xe9, 0x66, 0x45, 0x0f, 0x3f, - 0x8e, 0xda, 0xe8, 0x3b, 0x9c, 0xc3, 0x2e, 0xe8, 0xe7, 0xd7, 0x21, 0x2b, - 0xcb, 0xbc, 0x54, 0x56, 0x8e, 0xc5, 0x29, 0x28, 0xb7, 0x27, 0xe1, 0xf1, - 0x19, 0x55, 0x39, 0x5f, 0x84, 0x72, 0x0b, 0xe7, 0x4f, 0x35, 0xfc, 0xb8, - 0x85, 0x36, 0xb4, 0x61, 0x97, 0x85, 0x4d, 0xa1, 0x4a, 0xfa, 0x5b, 0x33, - 0xca, 0x88, 0x87, 0x1b, 0x35, 0x44, 0xcb, 0x23, 0x61, 0xe5, 0xd6, 0xf4, - 0xce, 0x9c, 0xfe, 0x9f, 0xae, 0xa4, 0x7c, 0x4a, 0x63, 0xf2, 0xf2, 0xeb, - 0x1f, 0xe5, 0xc7, 0x77, 0xd9, 0xf5, 0xb9, 0x05, 0x9f, 0x5c, 0xbe, 0x56, - 0x1b, 0x81, 0xc2, 0x78, 0x51, 0x44, 0xfd, 0xea, 0x8c, 0xd2, 0xd1, 0xa0, - 0xcb, 0xbe, 0xe6, 0xc0, 0x90, 0x33, 0xea, 0x73, 0xe0, 0xf7, 0x56, 0x74, - 0x95, 0x5c, 0x2b, 0x46, 0xac, 0xb9, 0xd6, 0xe7, 0x44, 0x6d, 0x78, 0x33, - 0xfd, 0x6d, 0x72, 0x55, 0x03, 0xef, 0x05, 0xcc, 0x93, 0xa8, 0xf1, 0x6f, - 0x86, 0xfc, 0xfe, 0x90, 0x36, 0xd2, 0x20, 0x75, 0x59, 0x46, 0x6c, 0x4e, - 0xd7, 0x4e, 0xc2, 0x8b, 0xcd, 0xb4, 0xbf, 0xc2, 0x88, 0x6e, 0x2e, 0x73, - 0x38, 0x71, 0x88, 0x38, 0xec, 0x30, 0x7a, 0x50, 0xc8, 0x31, 0x32, 0x3e, - 0xe2, 0xf1, 0x04, 0xf0, 0x62, 0xbf, 0x85, 0x86, 0x90, 0x07, 0x4b, 0x6c, - 0xdb, 0x3c, 0xaa, 0xdc, 0x98, 0xfc, 0xd8, 0x1a, 0x72, 0x16, 0x45, 0xd5, - 0x48, 0xc0, 0x77, 0x9a, 0xd1, 0xbc, 0x20, 0x52, 0xab, 0x39, 0x11, 0x57, - 0x9a, 0xd2, 0xdd, 0xca, 0xf2, 0x74, 0x8f, 0xb2, 0xc4, 0xc6, 0x9c, 0xa3, - 0xca, 0xd2, 0xb4, 0x07, 0xa9, 0x7e, 0x05, 0x3b, 0x42, 0x94, 0xab, 0x3a, - 0x6b, 0xc7, 0xe9, 0x7e, 0x95, 0x18, 0xf9, 0x2e, 0x31, 0x52, 0x0f, 0x83, - 0x7d, 0x3f, 0x9d, 0xa8, 0xc4, 0x51, 0x62, 0xe1, 0x4f, 0x52, 0xe5, 0x2a, - 0x8a, 0xaf, 0xc0, 0x8f, 0x47, 0xca, 0x30, 0x36, 0x38, 0x8b, 0xbf, 0xeb, - 0xf0, 0xca, 0x88, 0x65, 0x75, 0x9b, 0x96, 0x75, 0xc0, 0x3c, 0xaa, 0x34, - 0xb0, 0xcf, 0xa8, 0x33, 0x1e, 0x2d, 0x8c, 0x04, 0xcc, 0xad, 0xec, 0xd3, - 0x11, 0x89, 0x2b, 0x51, 0xf6, 0x77, 0x23, 0xfb, 0x5b, 0x9a, 0xeb, 0x2f, - 0xdb, 0xaf, 0xc8, 0x22, 0xf5, 0xf2, 0x75, 0xc2, 0xac, 0x03, 0x1c, 0x4c, - 0x04, 0x82, 0xf9, 0x7a, 0x4b, 0x59, 0xe7, 0xc6, 0x0b, 0x75, 0x80, 0xe1, - 0x44, 0x90, 0x73, 0x2a, 0xb6, 0xee, 0x67, 0xec, 0xf9, 0x1a, 0x9c, 0x46, - 0x3d, 0x5a, 0x87, 0x85, 0x47, 0x84, 0xd5, 0xec, 0x3c, 0x49, 0xfc, 0x74, - 0xdb, 0x31, 0x6b, 0xd2, 0x21, 0x71, 0x34, 0x88, 0x5e, 0xfa, 0x75, 0x57, - 0x52, 0x6c, 0xbc, 0xfe, 0xcb, 0x89, 0x80, 0x82, 0x6f, 0x04, 0x32, 0xcd, - 0xa5, 0x28, 0xc7, 0xba, 0x90, 0xd8, 0xa6, 0xf9, 0xe5, 0xe7, 0x0c, 0x3d, - 0xbc, 0x42, 0xe1, 0x9c, 0x05, 0xf4, 0xa6, 0xa5, 0x0a, 0x10, 0x18, 0x03, - 0xce, 0xa4, 0xca, 0xb1, 0xda, 0x74, 0x40, 0xad, 0x08, 0xa2, 0x27, 0x3d, - 0x15, 0xd7, 0x4d, 0xe2, 0xb4, 0xb4, 0x17, 0xa4, 0x5f, 0x97, 0x60, 0x99, - 0x96, 0xb5, 0x69, 0x37, 0xdb, 0x76, 0x07, 0x32, 0x41, 0x95, 0xf1, 0xea, - 0x10, 0x2f, 0x9c, 0x64, 0x5c, 0x6a, 0x30, 0x5c, 0x68, 0xd3, 0xca, 0xd1, - 0x60, 0xfe, 0xd6, 0x5a, 0xb6, 0x4a, 0xee, 0x5d, 0xc4, 0xf7, 0x42, 0xf6, - 0xfb, 0xb6, 0xa1, 0xfb, 0x47, 0x79, 0x92, 0x49, 0x65, 0xaf, 0xc7, 0x19, - 0x73, 0x36, 0xb1, 0xdd, 0x2d, 0x6c, 0x77, 0xad, 0xa6, 0x47, 0xe3, 0x17, - 0xca, 0x65, 0x82, 0x0e, 0xe8, 0x9a, 0x94, 0x6d, 0x64, 0xbb, 0xab, 0xd9, - 0x6e, 0x8f, 0x26, 0xf2, 0xfd, 0xd6, 0x5a, 0xbb, 0x4a, 0xee, 0x65, 0xed, - 0x23, 0xdb, 0x6e, 0xbd, 0xb4, 0x6b, 0x8e, 0xe6, 0xfa, 0x3a, 0x91, 0x40, - 0xbf, 0x23, 0xc2, 0x18, 0x59, 0x1f, 0xf0, 0x77, 0x31, 0x5e, 0x36, 0x32, - 0x76, 0x64, 0x6d, 0x62, 0x6a, 0xbc, 0x42, 0xfc, 0x62, 0x19, 0xb9, 0x26, - 0xe5, 0xc4, 0xd6, 0x26, 0xa9, 0x67, 0x89, 0x2f, 0x3e, 0xea, 0x57, 0xb0, - 0xc5, 0x89, 0xc3, 0x09, 0xe2, 0x3f, 0xbe, 0x46, 0xbb, 0xf3, 0xa3, 0x39, - 0x5d, 0x83, 0xb6, 0x5d, 0x8c, 0x63, 0x66, 0x05, 0x6d, 0x3d, 0x6b, 0x6f, - 0xcb, 0xd8, 0xf6, 0xa4, 0xdd, 0x76, 0x5c, 0x69, 0x4e, 0xd7, 0x6a, 0x15, - 0x8c, 0x99, 0xc7, 0x2f, 0x60, 0xe7, 0xec, 0x68, 0x71, 0x24, 0xd0, 0xb4, - 0x9e, 0x93, 0xe4, 0x66, 0x7c, 0xfb, 0xce, 0xbc, 0x6e, 0xda, 0x45, 0x0f, - 0xed, 0x30, 0x3b, 0xbf, 0x4d, 0x62, 0x70, 0xc4, 0x38, 0xa8, 0x35, 0x58, - 0xbb, 0x4b, 0xfe, 0x93, 0x6b, 0xd4, 0x3f, 0xca, 0x6b, 0x35, 0x58, 0x3d, - 0xfc, 0x0d, 0xda, 0x99, 0xee, 0x13, 0x3b, 0xec, 0xba, 0x20, 0x97, 0xc8, - 0x24, 0xb2, 0x89, 0x4c, 0xff, 0x37, 0xcb, 0xcd, 0xa4, 0x7e, 0x04, 0x1b, - 0x2b, 0x29, 0xcf, 0x36, 0xf2, 0x99, 0xa3, 0xca, 0x67, 0x29, 0x4f, 0xc6, - 0xe5, 0xc5, 0x63, 0x49, 0x91, 0x47, 0x89, 0xce, 0x88, 0xcc, 0xc4, 0xf9, - 0x64, 0x20, 0xfe, 0x34, 0x44, 0xb6, 0x6e, 0xa5, 0x45, 0xea, 0x27, 0x7b, - 0x78, 0x2f, 0x2f, 0x23, 0xb4, 0x72, 0x5b, 0xb6, 0xac, 0x4c, 0xb7, 0x72, - 0xae, 0x5d, 0xc6, 0xfd, 0xa5, 0x28, 0x73, 0xd2, 0xd6, 0xa4, 0xed, 0x9f, - 0x59, 0x51, 0x6d, 0x13, 0xaf, 0x79, 0x39, 0x4f, 0x6e, 0xc6, 0x75, 0x3d, - 0x78, 0x8b, 0x43, 0x69, 0xf6, 0x48, 0xbc, 0xa6, 0x7d, 0xa6, 0x52, 0x4e, - 0x3c, 0x93, 0x58, 0xba, 0xb4, 0xc4, 0xb8, 0x1a, 0xdf, 0x18, 0xf1, 0x61, - 0x84, 0x73, 0xfb, 0x62, 0x42, 0xe2, 0xeb, 0x4c, 0x3c, 0x91, 0xf2, 0xe0, - 0x85, 0x84, 0x1f, 0x8f, 0x33, 0xfe, 0x4c, 0x24, 0x0c, 0x1c, 0x4a, 0x79, - 0xf1, 0x3c, 0xed, 0x79, 0x34, 0xe5, 0xa3, 0xbd, 0xd4, 0x61, 0x38, 0xd5, - 0x6c, 0x8f, 0xe1, 0xd9, 0xc4, 0xab, 0x32, 0xd6, 0xa0, 0x8c, 0x75, 0x8b, - 0x3d, 0xd6, 0x7c, 0x9c, 0x9f, 0x79, 0x61, 0x1e, 0x4e, 0x25, 0x6c, 0x1c, - 0xe8, 0x59, 0xe6, 0x90, 0x79, 0xa0, 0xcd, 0x0e, 0x08, 0x16, 0xe8, 0xfd, - 0x71, 0x58, 0xd8, 0x6f, 0xce, 0xa0, 0xff, 0xf7, 0x50, 0x5e, 0xea, 0x94, - 0xe3, 0x87, 0xab, 0x2c, 0x5a, 0x1a, 0x09, 0xc4, 0x7a, 0xa9, 0x77, 0x67, - 0x44, 0xf4, 0x90, 0xd5, 0xfb, 0x8a, 0xf4, 0x51, 0x45, 0xb8, 0xda, 0x95, - 0x03, 0x71, 0xab, 0xc4, 0x10, 0x7d, 0x07, 0x88, 0xb3, 0xc0, 0xfc, 0xfd, - 0x4e, 0x8e, 0x6f, 0x25, 0xc7, 0x6c, 0xa2, 0xc0, 0xa8, 0xd5, 0x2a, 0x29, - 0xfb, 0xf1, 0x3f, 0x88, 0x81, 0xa2, 0xa3, 0x35, 0xb9, 0xf9, 0x2a, 0x77, - 0x50, 0x5e, 0x3f, 0x90, 0x9f, 0x17, 0xcb, 0xda, 0x69, 0xe6, 0xe7, 0xa6, - 0x1a, 0xfe, 0x4a, 0x3d, 0x3e, 0x44, 0x8b, 0x18, 0x49, 0x54, 0x21, 0xae, - 0xa9, 0xb9, 0xb6, 0xa3, 0x4a, 0x01, 0xf3, 0x07, 0x8c, 0x8b, 0xef, 0x97, - 0x22, 0xea, 0x94, 0xfa, 0x88, 0x16, 0x44, 0x02, 0xc1, 0xb9, 0xea, 0x54, - 0x9b, 0x11, 0x1c, 0x90, 0xbe, 0xe2, 0x94, 0xf5, 0x52, 0x2c, 0x18, 0x49, - 0xe4, 0x71, 0xe3, 0x3f, 0x53, 0xcf, 0x4b, 0x1f, 0x9b, 0xaa, 0x53, 0x91, - 0x53, 0xf4, 0xaa, 0xa2, 0x75, 0x50, 0xf4, 0xe7, 0xc4, 0x4a, 0x73, 0x51, - 0x4e, 0xe6, 0x99, 0x68, 0x4b, 0xa8, 0xd8, 0x30, 0xc8, 0xbe, 0x52, 0x0a, - 0x36, 0x87, 0x96, 0x60, 0xc8, 0x6b, 0xd3, 0x45, 0xb4, 0x26, 0x1a, 0x69, - 0x63, 0xc4, 0x99, 0x71, 0x3b, 0x7e, 0xda, 0xfe, 0x33, 0x9b, 0x3e, 0xb1, - 0x2c, 0xfd, 0x20, 0xd6, 0x26, 0x03, 0xfe, 0x93, 0x78, 0x10, 0x6d, 0x69, - 0x17, 0x62, 0xc3, 0x1e, 0x74, 0xb2, 0x6f, 0xb5, 0x4f, 0xfc, 0x49, 0x43, - 0xe7, 0xe8, 0x89, 0x17, 0x54, 0xda, 0x67, 0xe7, 0xa8, 0x97, 0xc7, 0x34, - 0x1e, 0x6e, 0x3c, 0xc4, 0xe3, 0x28, 0xe7, 0xbf, 0x83, 0x18, 0x9c, 0x4e, - 0x98, 0xb8, 0x9f, 0x32, 0x8d, 0x27, 0xea, 0xb1, 0x91, 0xf2, 0x8d, 0x25, - 0x1c, 0xf0, 0x4f, 0x0b, 0xe3, 0x3e, 0xea, 0xf2, 0xc9, 0x44, 0x58, 0x79, - 0x80, 0xff, 0x0f, 0x51, 0x26, 0xc9, 0x47, 0xd6, 0xd1, 0x0e, 0xa2, 0xd3, - 0x68, 0x27, 0x6a, 0xad, 0xc3, 0x9e, 0x07, 0x88, 0x7f, 0x5c, 0x3e, 0x57, - 0xba, 0x16, 0x43, 0x7e, 0xbe, 0x80, 0xa1, 0x14, 0x62, 0xee, 0x48, 0x5d, - 0x63, 0x41, 0x6f, 0xeb, 0x86, 0xc2, 0x48, 0xfb, 0x43, 0x3f, 0xad, 0x9f, - 0x85, 0x93, 0x9c, 0x13, 0xa7, 0x6d, 0xe3, 0x51, 0xc5, 0x65, 0x18, 0xb6, - 0x2f, 0xab, 0xe3, 0xed, 0xb9, 0xbc, 0x4a, 0x97, 0x38, 0xc6, 0x3e, 0x44, - 0x6f, 0xa2, 0x0b, 0xd1, 0xc3, 0x71, 0x6b, 0xc8, 0xf6, 0x77, 0xf1, 0x39, - 0x27, 0x75, 0xf4, 0x5d, 0xc6, 0x6f, 0xd1, 0x85, 0x94, 0xdb, 0xca, 0xb6, - 0x44, 0x1e, 0x3b, 0x16, 0xfa, 0xfe, 0xd0, 0x76, 0xa6, 0xca, 0x53, 0x87, - 0xed, 0x7b, 0x0c, 0xec, 0xd8, 0x53, 0x4b, 0xbb, 0xfb, 0xa5, 0xe5, 0xaf, - 0x18, 0x60, 0xdd, 0xa9, 0xb2, 0x08, 0x2f, 0x40, 0xae, 0x5d, 0x69, 0x73, - 0x13, 0xef, 0x1d, 0xa6, 0xad, 0x49, 0xbb, 0x96, 0xb5, 0xe5, 0x42, 0xdc, - 0x28, 0x88, 0x16, 0x31, 0x6e, 0x1c, 0x4a, 0x04, 0xc2, 0x2f, 0xd8, 0xb1, - 0xcd, 0x49, 0xdb, 0x90, 0xf9, 0xef, 0xb6, 0xe7, 0x7e, 0xd9, 0x85, 0xb9, - 0x9f, 0xbc, 0xc0, 0x91, 0xfa, 0x93, 0x53, 0x7d, 0x2a, 0x3b, 0xef, 0xce, - 0x3e, 0xbd, 0xc7, 0xb6, 0xd3, 0x94, 0xe0, 0x9f, 0x03, 0x8e, 0x01, 0xce, - 0xb3, 0x79, 0x15, 0xc7, 0x5f, 0xc9, 0x78, 0x52, 0xc0, 0x83, 0x79, 0xe4, - 0xf0, 0xa7, 0x50, 0x3c, 0x90, 0xb1, 0x8a, 0xf8, 0xbb, 0x29, 0x14, 0x08, - 0x17, 0x29, 0x37, 0xe0, 0xee, 0x61, 0x07, 0x0a, 0x06, 0x14, 0x3c, 0x6b, - 0xd6, 0xe5, 0xec, 0x43, 0xe6, 0xfb, 0x2a, 0xdb, 0x3e, 0xe6, 0x8c, 0xcb, - 0x7c, 0xcb, 0x1c, 0x7b, 0xe0, 0xeb, 0x53, 0xe0, 0x21, 0x6e, 0x94, 0x18, - 0x32, 0xd7, 0x1a, 0xca, 0xfb, 0x64, 0xae, 0x49, 0x1b, 0x77, 0x87, 0xb1, - 0x91, 0xf6, 0x50, 0xba, 0xfb, 0x7a, 0xdc, 0xc7, 0x72, 0x1b, 0x78, 0x6f, - 0xc3, 0x68, 0x25, 0x0f, 0x2f, 0x8f, 0x69, 0x3c, 0xea, 0x71, 0xef, 0x70, - 0x0d, 0xa2, 0x95, 0x7a, 0xd0, 0xaf, 0x3a, 0x50, 0x39, 0x20, 0x3a, 0x55, - 0xb1, 0x72, 0x81, 0x02, 0xf3, 0xea, 0x42, 0xa8, 0x73, 0x3f, 0xc9, 0x37, - 0xff, 0x9c, 0xac, 0x3f, 0x9a, 0x32, 0x87, 0x6e, 0x8e, 0xfd, 0x9f, 0xed, - 0x39, 0x9c, 0x33, 0x2e, 0x7d, 0x48, 0x2c, 0xb5, 0xe7, 0xf1, 0x4f, 0xf8, - 0xfe, 0x73, 0x9c, 0x8f, 0x2e, 0x96, 0xf9, 0xc3, 0xf9, 0xc5, 0x85, 0xf9, - 0x9d, 0xca, 0x49, 0x25, 0xae, 0xeb, 0xe1, 0x21, 0x9b, 0xc3, 0xf8, 0x99, - 0xcf, 0xe9, 0x71, 0xd1, 0x39, 0x39, 0x8b, 0x5b, 0x35, 0xe0, 0x2f, 0x30, - 0xee, 0xc0, 0x3d, 0x9c, 0xa7, 0x03, 0x09, 0x75, 0xa9, 0x0b, 0xea, 0x4c, - 0x17, 0x13, 0xdb, 0x11, 0x53, 0xc7, 0xba, 0x61, 0xe6, 0x4a, 0xc3, 0xa5, - 0xe8, 0xd2, 0x14, 0xf7, 0xf6, 0xba, 0x45, 0x92, 0xf3, 0xfa, 0xcb, 0x0d, - 0xa8, 0x25, 0x8c, 0xef, 0x3b, 0x34, 0x38, 0x0b, 0x0c, 0x45, 0x4d, 0xd4, - 0x35, 0x22, 0x5e, 0x01, 0x67, 0x99, 0x01, 0x85, 0x39, 0x2d, 0x7a, 0x35, - 0x08, 0xb6, 0x44, 0x0b, 0x8c, 0x07, 0x71, 0x4f, 0x12, 0x56, 0x71, 0x84, - 0xf9, 0x4e, 0xc4, 0x20, 0x87, 0x0d, 0xf8, 0x0a, 0x94, 0x07, 0xb1, 0x9a, - 0xbc, 0x61, 0xcd, 0xb0, 0xc8, 0xe1, 0x21, 0x9f, 0x30, 0xfc, 0xad, 0x60, - 0x8e, 0xdd, 0xac, 0x07, 0x27, 0x99, 0x67, 0xae, 0xa6, 0xee, 0x47, 0x12, - 0x0f, 0xa2, 0x21, 0x79, 0xdc, 0xf2, 0x90, 0x27, 0x16, 0x18, 0x35, 0xe7, - 0xbb, 0x10, 0xa3, 0x0f, 0x0b, 0xff, 0x69, 0xc3, 0x43, 0xf4, 0xbf, 0x74, - 0x42, 0x7d, 0x86, 0xec, 0x01, 0x1d, 0xa3, 0xeb, 0x71, 0xff, 0xe8, 0x4c, - 0xfa, 0xea, 0x06, 0xfa, 0x2a, 0xb9, 0x50, 0xff, 0x0d, 0xb8, 0x6f, 0xf8, - 0x06, 0xdc, 0xbb, 0xcb, 0x08, 0x6e, 0xa0, 0xae, 0xd7, 0x0c, 0x33, 0x10, - 0x4e, 0x93, 0x76, 0xf3, 0xba, 0x12, 0x3e, 0x48, 0x5d, 0xe4, 0xf4, 0x94, - 0x41, 0x9e, 0xa3, 0xfc, 0xb3, 0xc5, 0x4b, 0xf1, 0x82, 0x7a, 0xc5, 0xbf, - 0xb7, 0xee, 0xfb, 0xcc, 0xbd, 0x45, 0x76, 0x44, 0x67, 0x18, 0xaf, 0x5a, - 0x8f, 0x6a, 0x0a, 0x0a, 0x22, 0x88, 0xcf, 0xae, 0x7f, 0xd9, 0x7a, 0x6c, - 0x95, 0x5c, 0xbf, 0xd5, 0x89, 0x62, 0x95, 0xd7, 0xa4, 0xcd, 0x1d, 0x32, - 0x47, 0x44, 0xda, 0x4f, 0x6a, 0x33, 0x63, 0xf5, 0x5d, 0x28, 0x4f, 0xde, - 0x47, 0xac, 0x7d, 0x3a, 0xe1, 0x45, 0x4f, 0x32, 0xcb, 0x9d, 0x6e, 0x4f, - 0x0b, 0x67, 0x72, 0xa3, 0xb8, 0x57, 0xe2, 0x46, 0x14, 0xeb, 0xf9, 0xbb, - 0xa8, 0x57, 0x6f, 0x8e, 0x83, 0xc9, 0xbc, 0xd1, 0xc8, 0xb9, 0xa0, 0xbd, - 0xf6, 0x3a, 0x50, 0x64, 0x34, 0x65, 0x6d, 0xb5, 0x77, 0x85, 0x8d, 0x4b, - 0x65, 0xbd, 0xdd, 0x36, 0x2e, 0x95, 0xb2, 0x9e, 0x60, 0x92, 0xa7, 0x77, - 0x15, 0xed, 0x75, 0x26, 0x4a, 0x7a, 0x5b, 0x70, 0x2f, 0xe7, 0x78, 0x2d, - 0x79, 0xf6, 0x09, 0xb3, 0x3c, 0xc7, 0x3f, 0x9b, 0x70, 0x77, 0x32, 0x8a, - 0xd6, 0x64, 0x4d, 0xf4, 0xb4, 0xac, 0x25, 0xb9, 0xb2, 0xd8, 0x19, 0xad, - 0x16, 0x5d, 0x3c, 0x97, 0xc3, 0x08, 0xbd, 0x29, 0xcb, 0xd9, 0x74, 0xcd, - 0xaf, 0xe4, 0x65, 0xef, 0x46, 0x8c, 0xf9, 0xc5, 0xec, 0x48, 0x33, 0xac, - 0xa4, 0xc8, 0x1d, 0xb7, 0x7c, 0xcc, 0x19, 0x3d, 0x11, 0xbd, 0x7d, 0xb1, - 0xc3, 0xe8, 0xf8, 0xb1, 0x12, 0xc4, 0xad, 0x94, 0xa1, 0xa4, 0xb7, 0x13, - 0xaf, 0x84, 0x74, 0xdf, 0xb7, 0x15, 0xfd, 0xfc, 0x06, 0xfc, 0x18, 0x3f, - 0xe7, 0xb5, 0x82, 0xde, 0x09, 0x3c, 0x96, 0x7e, 0x1d, 0x67, 0x29, 0xab, - 0xda, 0xfb, 0xb1, 0xb5, 0xcc, 0x20, 0x18, 0x14, 0xbb, 0x95, 0xb7, 0xd3, - 0x53, 0x6d, 0xf1, 0x06, 0xac, 0xde, 0x25, 0xf6, 0xa7, 0x07, 0xe3, 0xa0, - 0x7c, 0x66, 0x99, 0x60, 0x9c, 0xc4, 0x1f, 0xca, 0xdf, 0x4c, 0xd9, 0x2c, - 0xfa, 0x07, 0xed, 0xc0, 0x1e, 0xc3, 0x43, 0x36, 0x0e, 0x3a, 0xfb, 0xe4, - 0xc8, 0xeb, 0x39, 0xa2, 0xb4, 0x8e, 0x5e, 0x53, 0x8c, 0x62, 0x5f, 0xce, - 0x0f, 0xb2, 0x6b, 0x0a, 0x17, 0xeb, 0xfe, 0xd2, 0x1a, 0xf1, 0x5e, 0x5a, - 0xb7, 0x8c, 0x39, 0x56, 0x39, 0xc7, 0xf3, 0x5e, 0x6f, 0xdc, 0x2a, 0xce, - 0x8e, 0xa5, 0xe9, 0x55, 0x45, 0x6c, 0x32, 0x48, 0xee, 0xde, 0x89, 0xab, - 0x42, 0x7a, 0xcb, 0xb7, 0x15, 0x29, 0xab, 0x87, 0x37, 0x28, 0xf9, 0x7e, - 0x7e, 0x84, 0xd3, 0x23, 0xd2, 0x87, 0xf4, 0x35, 0xc1, 0x9c, 0xeb, 0x52, - 0x7f, 0x4a, 0xd9, 0xf3, 0xa9, 0x9b, 0x43, 0xe4, 0x75, 0x2b, 0x38, 0xcc, - 0x92, 0x5e, 0x19, 0x93, 0xa9, 0xdc, 0x3b, 0x2a, 0xf3, 0xba, 0x40, 0x59, - 0x4f, 0x2c, 0x29, 0xea, 0xad, 0x57, 0xee, 0x21, 0x96, 0x14, 0xee, 0xac, - 0x51, 0xee, 0xb6, 0x6d, 0xbe, 0x0a, 0x23, 0xfd, 0xd7, 0x28, 0x6d, 0xc3, - 0xa2, 0x03, 0x37, 0xc7, 0x3e, 0x8d, 0x63, 0xf7, 0xa2, 0x8f, 0xfe, 0xfb, - 0x4a, 0x6f, 0x9d, 0x72, 0x1f, 0x7d, 0xa3, 0x73, 0x97, 0x8a, 0xc9, 0x2a, - 0x85, 0x78, 0x47, 0xfe, 0x6b, 0xf8, 0x94, 0xd6, 0xe1, 0xef, 0x3b, 0x25, - 0xbe, 0x64, 0x70, 0x03, 0x5a, 0x79, 0x6f, 0xa9, 0xe9, 0x42, 0x46, 0xab, - 0xd5, 0x34, 0xac, 0xc0, 0xea, 0xe4, 0x2a, 0xb4, 0x25, 0x8b, 0xc9, 0x73, - 0x65, 0xbc, 0x79, 0xb9, 0xf3, 0xf3, 0xf8, 0x20, 0x5a, 0x92, 0x88, 0xcf, - 0x88, 0x04, 0x3a, 0x66, 0x38, 0xe8, 0xd2, 0xc5, 0x75, 0xca, 0xfd, 0xe9, - 0x1a, 0x65, 0xcd, 0xae, 0x72, 0x64, 0xb1, 0xe7, 0x61, 0x34, 0xed, 0xa9, - 0x57, 0xee, 0xde, 0x53, 0x85, 0x49, 0xcd, 0xb2, 0x9c, 0xa1, 0x7a, 0xa5, - 0x75, 0x8f, 0x65, 0xdd, 0x64, 0x46, 0x9b, 0x8a, 0xc9, 0x77, 0xb7, 0xb1, - 0xbd, 0xd6, 0x51, 0xe9, 0xe7, 0xf2, 0x76, 0x4d, 0x65, 0xe3, 0x9e, 0x87, - 0xb1, 0x82, 0x65, 0x5f, 0x09, 0x45, 0x5b, 0x4a, 0x59, 0x56, 0x74, 0xd6, - 0x3a, 0xfa, 0x19, 0xf6, 0x21, 0xe5, 0x17, 0x4c, 0x69, 0x67, 0x31, 0xaf, - 0x49, 0x5b, 0x59, 0xdd, 0x89, 0xde, 0x1e, 0xcf, 0xea, 0x2d, 0x2c, 0x7a, - 0x5b, 0x4e, 0x5d, 0xba, 0x7a, 0x7d, 0x3c, 0x5c, 0xf4, 0x75, 0x1f, 0xd6, - 0xa4, 0x65, 0x4c, 0x33, 0x89, 0x03, 0xcd, 0xb4, 0xdb, 0x76, 0xb4, 0x52, - 0xaf, 0x71, 0x2d, 0x6b, 0x9f, 0x17, 0x7d, 0x4b, 0xf7, 0x4f, 0x72, 0xec, - 0xad, 0x49, 0xd1, 0x4b, 0x33, 0xcb, 0xdb, 0xf7, 0xe9, 0xdb, 0x53, 0xcb, - 0x5c, 0x3a, 0x57, 0xfb, 0x13, 0xc2, 0x27, 0x0a, 0xc8, 0x7d, 0x0a, 0xd8, - 0x5e, 0x96, 0x2b, 0x8a, 0xbd, 0x38, 0x68, 0x2f, 0xcf, 0x98, 0xc5, 0xd8, - 0xe4, 0x95, 0x31, 0x66, 0xf5, 0x0c, 0x15, 0x58, 0xc7, 0x7b, 0x2e, 0xde, - 0x2b, 0x0c, 0x15, 0xe2, 0x2d, 0x5b, 0x57, 0x59, 0x3e, 0x98, 0xf7, 0xf3, - 0xa1, 0x0b, 0xfd, 0x1c, 0xab, 0xce, 0xda, 0xd8, 0x26, 0x57, 0x96, 0x33, - 0xe6, 0xb9, 0x8d, 0x65, 0x0d, 0x98, 0x79, 0x6e, 0x23, 0x71, 0xee, 0x53, - 0xc2, 0x15, 0x6c, 0x1e, 0xd6, 0x96, 0xeb, 0xb7, 0xcb, 0x0c, 0xd0, 0x4f, - 0x85, 0xfb, 0x45, 0x94, 0xb6, 0x3d, 0xa7, 0x68, 0xab, 0x92, 0x8b, 0x01, - 0x1b, 0x79, 0xbf, 0x94, 0xf7, 0x5f, 0x0b, 0xb9, 0x70, 0xd5, 0x34, 0xe9, - 0xfb, 0x06, 0x74, 0xec, 0x8a, 0xa2, 0x7c, 0x61, 0x00, 0x93, 0xf6, 0x7a, - 0x59, 0x9e, 0xa7, 0xbb, 0x70, 0xdf, 0xae, 0x8f, 0xad, 0x32, 0x9b, 0x3b, - 0x1a, 0xb1, 0x71, 0x45, 0xc5, 0x8e, 0x45, 0xc2, 0xd7, 0x5d, 0x8c, 0x57, - 0xe4, 0xce, 0x92, 0x0b, 0xb8, 0x4a, 0xc8, 0xb9, 0x85, 0x73, 0x06, 0x32, - 0xb7, 0xab, 0xd0, 0xb4, 0x88, 0x70, 0xcf, 0x99, 0x36, 0xe7, 0x16, 0xee, - 0xfd, 0xcd, 0xe4, 0xd1, 0x29, 0xdc, 0xfb, 0x02, 0x4f, 0x61, 0xae, 0xd6, - 0x8c, 0x44, 0xaf, 0x07, 0xee, 0x88, 0xde, 0xbc, 0x59, 0xe9, 0xc4, 0xf2, - 0x90, 0x61, 0xca, 0x1a, 0xc0, 0xf5, 0x8a, 0x1e, 0x3c, 0x87, 0x20, 0xe3, - 0xc7, 0x8f, 0x30, 0x32, 0xf8, 0x0f, 0x2e, 0xf1, 0x8b, 0xcd, 0xe9, 0x8b, - 0xf2, 0xdc, 0x4d, 0x79, 0xdc, 0x59, 0x79, 0xcc, 0x73, 0x54, 0xe4, 0xb3, - 0xf5, 0x2e, 0xe2, 0xf0, 0x7f, 0xb7, 0xed, 0x76, 0x89, 0x9d, 0x4b, 0xfc, - 0x77, 0xc6, 0x93, 0x70, 0x71, 0x5e, 0xcf, 0x9d, 0xc4, 0xab, 0x0f, 0x17, - 0x16, 0x21, 0x44, 0x7b, 0xaf, 0x30, 0x3a, 0x98, 0xcf, 0x7f, 0x6c, 0xc5, - 0x9d, 0xa4, 0xdf, 0x06, 0xb4, 0xa2, 0x48, 0x94, 0xb2, 0x35, 0x2a, 0x37, - 0x0d, 0x8f, 0xb3, 0x9f, 0x0e, 0xe6, 0x29, 0x1e, 0x3c, 0x40, 0x5c, 0x79, - 0x80, 0xfe, 0xf4, 0x00, 0x63, 0xf3, 0x03, 0xa3, 0xff, 0x8b, 0xd7, 0xa7, - 0xd9, 0xbf, 0x37, 0x27, 0xf3, 0xf6, 0xe5, 0x64, 0x9c, 0x13, 0xfd, 0x6e, - 0x21, 0x16, 0x48, 0x9c, 0x03, 0x65, 0xb2, 0x70, 0xda, 0x2c, 0xa4, 0xae, - 0xf5, 0x60, 0x06, 0x09, 0xd7, 0xc5, 0x3c, 0x35, 0x1f, 0x2b, 0x65, 0x1e, - 0x5d, 0xb8, 0x87, 0x32, 0x06, 0x43, 0xbf, 0xb1, 0x50, 0x21, 0x58, 0x74, - 0xf9, 0xfd, 0xec, 0xbc, 0x1e, 0xbf, 0xc0, 0x59, 0x15, 0xc9, 0x91, 0xe8, - 0xef, 0xfd, 0x36, 0x07, 0x7b, 0x8d, 0x3e, 0xd9, 0xb6, 0xeb, 0xc4, 0x7c, - 0x31, 0x95, 0x35, 0xa3, 0x51, 0x6c, 0xe2, 0xb8, 0x57, 0x0f, 0x3f, 0x9a, - 0xd3, 0x4b, 0x7e, 0xbc, 0xe2, 0xd3, 0x1e, 0xda, 0x74, 0x36, 0xb7, 0x6a, - 0x1d, 0x15, 0x2e, 0x5e, 0xc9, 0xff, 0xc2, 0xc5, 0xc5, 0x7f, 0x84, 0x97, - 0x4f, 0xe3, 0x7f, 0x27, 0x39, 0xa7, 0x70, 0xe9, 0x3a, 0xf4, 0xd0, 0x8f, - 0x0a, 0x03, 0x75, 0xd8, 0x3a, 0x7a, 0xf9, 0x1c, 0x5d, 0x2e, 0x8f, 0x3d, - 0x07, 0xcc, 0xc3, 0x5c, 0x82, 0xad, 0x7e, 0xbf, 0x2a, 0x7d, 0x5b, 0x68, - 0x37, 0x6f, 0xc8, 0x72, 0xa7, 0x4a, 0xb9, 0x36, 0x95, 0x9f, 0xe7, 0xdb, - 0x99, 0x7a, 0x4d, 0x2d, 0x40, 0x71, 0x9e, 0x37, 0x78, 0x73, 0xb9, 0x0e, - 0xf3, 0x9b, 0xa4, 0xe8, 0x4b, 0xc6, 0x90, 0xcd, 0x5f, 0xc5, 0x5e, 0x2e, - 0xc5, 0x83, 0xf8, 0xb4, 0x22, 0x43, 0x6c, 0x25, 0x48, 0x7f, 0xd6, 0xc3, - 0x4d, 0x0c, 0x35, 0x67, 0x13, 0x88, 0x39, 0x22, 0x4d, 0x8d, 0x6b, 0x12, - 0x73, 0xb5, 0x67, 0x72, 0xf9, 0xf1, 0x7e, 0xc6, 0x1e, 0xd5, 0x90, 0xb5, - 0x19, 0xda, 0xc3, 0xb0, 0xe8, 0xa7, 0x43, 0xb9, 0x98, 0x0b, 0x47, 0xc9, - 0x15, 0x19, 0x57, 0x0d, 0xc9, 0x91, 0x1a, 0x95, 0xa5, 0xc3, 0x52, 0x87, - 0xf6, 0x70, 0x19, 0x67, 0xcc, 0x8e, 0xb7, 0x0c, 0x9e, 0x01, 0xe1, 0x8a, - 0x3a, 0x36, 0x90, 0x9b, 0x94, 0x0c, 0xf8, 0x69, 0xef, 0x95, 0x28, 0xde, - 0x1d, 0xc1, 0xfa, 0x51, 0x0d, 0x45, 0xbb, 0x2d, 0x6b, 0x6e, 0xa8, 0x1b, - 0x6b, 0xd3, 0xcb, 0x0b, 0x24, 0x9f, 0x73, 0xf6, 0x11, 0x2b, 0x88, 0x2b, - 0xeb, 0x92, 0x0a, 0x6e, 0x24, 0x07, 0x88, 0xa2, 0x99, 0xdc, 0x5d, 0xf0, - 0xc5, 0xea, 0x9c, 0x1d, 0x71, 0xd1, 0x4e, 0x56, 0xf1, 0x7e, 0x0b, 0xb1, - 0xa7, 0x85, 0x58, 0x62, 0x59, 0x1f, 0x5e, 0x8b, 0xce, 0x92, 0xc8, 0x1d, - 0xc4, 0xa0, 0x1a, 0xe6, 0x0f, 0xc2, 0x39, 0xae, 0x45, 0x1b, 0xb1, 0xbb, - 0xb0, 0xcf, 0xce, 0xf1, 0xa8, 0x47, 0xc6, 0xd5, 0x34, 0xe3, 0x32, 0x65, - 0x7f, 0x9e, 0x7c, 0xbd, 0x83, 0x7e, 0x54, 0xde, 0xb7, 0x81, 0xf1, 0xd9, - 0x83, 0xb2, 0x81, 0x6b, 0xb0, 0x91, 0xd8, 0x7e, 0xdf, 0x2e, 0x3f, 0x52, - 0x8b, 0x6e, 0xa0, 0x7c, 0x0f, 0x62, 0x7d, 0xd2, 0x90, 0xbc, 0x2e, 0x1a, - 0x5c, 0xf4, 0x20, 0xfb, 0xa5, 0x7d, 0xec, 0x92, 0x1c, 0xb1, 0x04, 0x4b, - 0x9a, 0x81, 0x60, 0x9f, 0x60, 0x8e, 0x8c, 0xff, 0x36, 0x59, 0xcf, 0x82, - 0xd1, 0x37, 0x75, 0x3e, 0xa6, 0x72, 0x39, 0x59, 0x1b, 0x6c, 0xc6, 0x7c, - 0xc6, 0x2f, 0xb1, 0x21, 0x8d, 0x79, 0x6f, 0x91, 0x62, 0xf8, 0xf6, 0xd3, - 0x17, 0x25, 0x17, 0xbb, 0xae, 0x2f, 0x1f, 0xaf, 0xf5, 0xcc, 0x62, 0x47, - 0x27, 0xb1, 0x42, 0x6f, 0xff, 0xad, 0xa2, 0xaf, 0x3b, 0xa5, 0xfc, 0x18, - 0x07, 0xc7, 0x5e, 0xc7, 0xd0, 0x98, 0x5b, 0x19, 0x1d, 0x93, 0xbe, 0x26, - 0xd0, 0x9b, 0xfe, 0x73, 0x7d, 0x4d, 0x5d, 0x13, 0x5a, 0x74, 0xc9, 0x3a, - 0xd2, 0x8d, 0xb9, 0xdc, 0x75, 0xe9, 0x25, 0x9c, 0x5e, 0xe6, 0x44, 0x6c, - 0xcf, 0x8b, 0xee, 0xe4, 0xc5, 0xb5, 0x8a, 0xfe, 0xc4, 0x76, 0xdb, 0x07, - 0x9b, 0xd3, 0x62, 0x93, 0xcc, 0xef, 0xcc, 0x39, 0xf6, 0xb3, 0x1b, 0x59, - 0x5f, 0x58, 0xb3, 0xab, 0xd7, 0xbe, 0x77, 0xd0, 0xfc, 0x2b, 0x64, 0xec, - 0x6b, 0x8b, 0xe9, 0x7f, 0x8c, 0x93, 0xc4, 0xbd, 0x60, 0xc8, 0x87, 0xc2, - 0x0a, 0x59, 0x5b, 0xba, 0xb8, 0x1e, 0xb1, 0x61, 0x17, 0x69, 0x84, 0x8d, - 0x2b, 0x0d, 0xc4, 0xb8, 0x1a, 0xce, 0x77, 0x16, 0x4b, 0xd6, 0xd3, 0x86, - 0x6e, 0x11, 0x1b, 0x72, 0x65, 0x6d, 0xe8, 0x0f, 0xd7, 0x3c, 0x54, 0x90, - 0xaf, 0x6a, 0x65, 0x76, 0x2e, 0xda, 0xa8, 0xdc, 0x9a, 0xb3, 0xab, 0xcf, - 0xa6, 0xbf, 0x53, 0x90, 0xcb, 0x91, 0x2e, 0x2b, 0xff, 0x49, 0x3a, 0xb8, - 0xe6, 0x2f, 0xd0, 0x81, 0x60, 0xbe, 0xe4, 0x31, 0xa2, 0x83, 0x99, 0x53, - 0xfc, 0xf2, 0x93, 0xf4, 0x50, 0x9b, 0xd3, 0xc3, 0x62, 0x62, 0x48, 0x25, - 0x71, 0x4f, 0x38, 0x4b, 0x00, 0x4f, 0x6a, 0x79, 0x3d, 0x38, 0x73, 0x7a, - 0xd0, 0xff, 0x40, 0x0f, 0xf7, 0x13, 0x5f, 0x4b, 0xd9, 0x56, 0x31, 0x8f, - 0x77, 0xa9, 0x87, 0x8d, 0xc3, 0x8b, 0xf1, 0x00, 0x7d, 0x69, 0x83, 0xbd, - 0x5e, 0x23, 0xcf, 0xef, 0x5c, 0x97, 0xe8, 0x66, 0x25, 0xe5, 0xf7, 0x17, - 0xa8, 0x98, 0x41, 0x1d, 0xf8, 0x6c, 0x3c, 0x95, 0x3e, 0x1a, 0x95, 0xdb, - 0x87, 0x05, 0xe3, 0x3e, 0xa6, 0x0e, 0x3a, 0x18, 0x07, 0xfe, 0x54, 0x9e, - 0x21, 0xfd, 0x7f, 0x7c, 0x41, 0x57, 0x7f, 0xbc, 0xdc, 0x8f, 0xa9, 0x03, - 0x79, 0x26, 0x22, 0x6b, 0xec, 0xf2, 0x7c, 0x44, 0xf4, 0x61, 0x4c, 0xd1, - 0x83, 0x65, 0x1d, 0x31, 0xe7, 0x21, 0x56, 0xa9, 0xf7, 0x4b, 0x1c, 0xed, - 0x27, 0xa6, 0x38, 0x98, 0xb7, 0x17, 0x44, 0xa2, 0x14, 0x5b, 0xbd, 0x81, - 0x4c, 0xa7, 0xce, 0x81, 0x4e, 0x9c, 0x31, 0x8d, 0x9e, 0xb5, 0xf8, 0x2b, - 0x74, 0x79, 0x2d, 0x1c, 0x60, 0x3b, 0x9b, 0x92, 0x45, 0x58, 0x57, 0x47, - 0xd3, 0x5c, 0xe9, 0xc1, 0xce, 0x64, 0xbc, 0x85, 0xd0, 0xc2, 0xd8, 0x74, - 0xe6, 0xf6, 0x44, 0x40, 0x6f, 0xde, 0x40, 0xbe, 0xb6, 0xbc, 0xd7, 0x0d, - 0xbf, 0x92, 0x8d, 0xcf, 0x03, 0xaa, 0xac, 0x7f, 0x5e, 0xc9, 0xb1, 0x77, - 0xdb, 0x79, 0xac, 0x7f, 0x9a, 0xf4, 0xe3, 0x47, 0x3c, 0x2d, 0x75, 0xa9, - 0xb3, 0xb9, 0x0a, 0x96, 0xcf, 0xd5, 0xe3, 0x51, 0xc5, 0xb2, 0x16, 0x84, - 0x9c, 0xf6, 0xfd, 0xed, 0xe9, 0xda, 0x96, 0xdb, 0xd4, 0xd7, 0xad, 0xec, - 0x9a, 0xab, 0xae, 0x45, 0x99, 0x0c, 0x1d, 0xff, 0xa3, 0xcf, 0x1d, 0x82, - 0x90, 0xe7, 0x41, 0x6e, 0x63, 0x25, 0x0e, 0xe5, 0xd6, 0x1d, 0x5d, 0x91, - 0xc3, 0x5f, 0x3e, 0x60, 0x48, 0xbe, 0x26, 0x7a, 0x92, 0xfe, 0xc4, 0x9e, - 0x1e, 0x28, 0x14, 0x1c, 0xed, 0x4a, 0x2f, 0xe4, 0x3c, 0xfe, 0x87, 0x35, - 0xea, 0x9d, 0x5a, 0x76, 0x89, 0x9a, 0x7d, 0x8e, 0x20, 0x65, 0xf3, 0xe5, - 0xe6, 0x10, 0x57, 0x1a, 0x30, 0x7c, 0x49, 0x9b, 0x92, 0x6f, 0xe7, 0xdb, - 0xec, 0x2d, 0x14, 0x5e, 0x55, 0x81, 0x42, 0xe2, 0xe3, 0x6f, 0xac, 0x83, - 0x97, 0xb4, 0xb7, 0xd1, 0x95, 0x6d, 0x6f, 0x0f, 0xcb, 0x48, 0xd9, 0x02, - 0xd6, 0x79, 0x37, 0xc7, 0x7f, 0xf3, 0x65, 0x3e, 0x77, 0x59, 0x19, 0x66, - 0x78, 0xc6, 0x5b, 0xd6, 0xfe, 0x4b, 0xca, 0x7c, 0xda, 0x79, 0x69, 0x19, - 0x27, 0x66, 0x1b, 0xaf, 0x5b, 0xc7, 0x2f, 0x29, 0x33, 0x70, 0x59, 0x99, - 0x6b, 0x31, 0x56, 0xf7, 0xb8, 0x35, 0x94, 0x9d, 0x9b, 0x0c, 0x5d, 0xd0, - 0x3d, 0x23, 0xe2, 0xfe, 0xd2, 0x75, 0xf3, 0x74, 0xf2, 0x4d, 0x79, 0x16, - 0xe5, 0x46, 0x26, 0x3b, 0x37, 0x71, 0x99, 0x1b, 0xd7, 0x82, 0xfc, 0xdc, - 0x3c, 0x90, 0xab, 0x9f, 0x6f, 0x37, 0x56, 0x70, 0x69, 0xbb, 0xf9, 0xeb, - 0x8e, 0xcb, 0xe4, 0x9e, 0xb8, 0xac, 0x5c, 0x51, 0xe1, 0x27, 0xd7, 0xfb, - 0x81, 0xe3, 0xd2, 0xeb, 0xff, 0x43, 0xbd, 0xf4, 0xfc, 0x9a, 0xdc, 0x79, - 0x5e, 0xff, 0xd6, 0x65, 0xf7, 0x1d, 0x97, 0x9d, 0x3f, 0xa3, 0x7e, 0x72, - 0x3f, 0xab, 0x2e, 0xeb, 0xc7, 0x5e, 0x83, 0xc7, 0x73, 0x17, 0x70, 0x03, - 0x8d, 0x05, 0x08, 0x98, 0x4e, 0x05, 0x7e, 0xe2, 0x87, 0xff, 0xf9, 0xcb, - 0xd6, 0xe2, 0x1b, 0x2f, 0xe0, 0xc7, 0x25, 0x5c, 0x35, 0x56, 0x18, 0x91, - 0x38, 0x28, 0x3c, 0x55, 0xf8, 0xe2, 0x27, 0xf1, 0xef, 0xb2, 0x58, 0x51, - 0xa4, 0x1e, 0xfe, 0xb1, 0x99, 0xfe, 0xb7, 0x12, 0xb2, 0x1e, 0xfb, 0x7b, - 0x72, 0x2e, 0xc3, 0x77, 0x08, 0x33, 0xfd, 0x3f, 0x4d, 0x95, 0xb8, 0x51, - 0xe6, 0xc1, 0x8d, 0x89, 0x4f, 0xae, 0xa7, 0x46, 0xa0, 0x2c, 0xab, 0xf7, - 0x31, 0xaf, 0x84, 0xf3, 0xa6, 0x79, 0x98, 0xf2, 0xd7, 0x2c, 0x79, 0xae, - 0x7a, 0xb2, 0x3e, 0xcc, 0x18, 0x9f, 0x7d, 0x8e, 0xbc, 0x24, 0xad, 0xfb, - 0xa2, 0x4a, 0xf6, 0x59, 0xf1, 0xba, 0xd0, 0x47, 0xe4, 0x45, 0x9d, 0x94, - 0xcb, 0x62, 0x5f, 0xc0, 0x86, 0x84, 0x65, 0x3d, 0xc7, 0xfc, 0x5c, 0xf6, - 0x20, 0xfc, 0x22, 0xf5, 0x3b, 0x6b, 0xc2, 0xeb, 0xc4, 0xdb, 0xc6, 0xd4, - 0xf6, 0xfc, 0x28, 0x8f, 0x98, 0xcc, 0x13, 0xed, 0x13, 0x75, 0xcc, 0xa8, - 0x6d, 0x3f, 0x40, 0xbf, 0x9b, 0x1f, 0xd0, 0xfd, 0x7d, 0xf8, 0x3f, 0x96, - 0xbf, 0x5a, 0x0f, 0x0e, 0x29, 0xf9, 0xf5, 0xef, 0xcb, 0xd7, 0xb9, 0xcb, - 0x62, 0x2e, 0x8e, 0x6f, 0xbf, 0xbd, 0xd6, 0x5d, 0x40, 0xac, 0x44, 0xcc, - 0x19, 0x99, 0xe9, 0xdf, 0x9a, 0xb0, 0xc7, 0x49, 0x5e, 0xa9, 0xe0, 0x64, - 0xfd, 0x4c, 0xff, 0xa6, 0x94, 0x17, 0x3b, 0x18, 0xd3, 0x8b, 0x8c, 0x7a, - 0x3c, 0x9e, 0x52, 0x71, 0xcf, 0x23, 0x5e, 0xac, 0x21, 0x67, 0x6d, 0xef, - 0xfd, 0x1a, 0x8c, 0xab, 0x9c, 0xb8, 0x9b, 0xf6, 0xb7, 0x96, 0xae, 0x23, - 0xf9, 0xc3, 0xfa, 0x5e, 0x27, 0xea, 0xae, 0x2a, 0x43, 0xbc, 0xba, 0x10, - 0xdf, 0x33, 0x1d, 0xcc, 0xf7, 0x4a, 0x30, 0x64, 0x73, 0x69, 0xc9, 0xe1, - 0x05, 0x13, 0x45, 0x6f, 0x0e, 0x7b, 0xbd, 0xf5, 0x93, 0xe3, 0xc1, 0x7f, - 0x58, 0x99, 0xea, 0x1d, 0x36, 0x8e, 0x3b, 0x22, 0xa6, 0x1d, 0x73, 0x81, - 0x2c, 0x9f, 0xeb, 0xba, 0xe4, 0x79, 0x77, 0xb3, 0x32, 0x3b, 0x12, 0x98, - 0x58, 0xac, 0x38, 0x10, 0x0e, 0x94, 0xc5, 0xca, 0x23, 0x61, 0x2c, 0x4b, - 0x77, 0xf9, 0x7c, 0xf6, 0x33, 0xf4, 0x08, 0xce, 0x2d, 0x32, 0x99, 0xfb, - 0xc3, 0xb9, 0x8c, 0xba, 0x6f, 0xa4, 0x5e, 0xb7, 0x98, 0x1f, 0x59, 0x19, - 0xdb, 0xef, 0xdd, 0x88, 0x31, 0x07, 0x5b, 0x4b, 0xfd, 0x3a, 0xa8, 0xc7, - 0x9f, 0xe7, 0xf4, 0x2b, 0x3a, 0x2d, 0x19, 0xfb, 0x9d, 0x75, 0x92, 0xfa, - 0x75, 0xb3, 0x3d, 0x37, 0xdb, 0x2b, 0x1a, 0xbb, 0x54, 0xcf, 0x85, 0x94, - 0x67, 0x99, 0x2d, 0xc3, 0x42, 0x79, 0x86, 0xe9, 0x8f, 0x2a, 0x32, 0x1e, - 0xc1, 0xf7, 0x3f, 0x37, 0xa6, 0x1f, 0x4f, 0xc9, 0x55, 0x44, 0xff, 0x7e, - 0xea, 0x5f, 0x30, 0x5c, 0xe6, 0xa0, 0x4e, 0xd6, 0xbb, 0x7a, 0x80, 0x97, - 0x98, 0xcc, 0x2a, 0xa8, 0x32, 0x22, 0x78, 0xaa, 0xd9, 0x83, 0xb7, 0x12, - 0xa5, 0xf6, 0xb8, 0xaf, 0x9a, 0x6b, 0x59, 0x4f, 0x86, 0xfc, 0xf8, 0x85, - 0x51, 0x1b, 0x5e, 0xa0, 0xea, 0xcc, 0x1f, 0xbd, 0x48, 0x10, 0x67, 0xbb, - 0x92, 0xb3, 0x38, 0x5f, 0x5e, 0x6c, 0x4d, 0xa2, 0x9d, 0xf6, 0xe4, 0x77, - 0x44, 0x80, 0x33, 0x09, 0x23, 0xb8, 0x85, 0xfd, 0x0f, 0x7b, 0xeb, 0xc9, - 0xd3, 0xd5, 0x46, 0xd2, 0xbd, 0x78, 0x51, 0xc4, 0x88, 0x6f, 0xc3, 0xcf, - 0xac, 0x21, 0xe2, 0x7c, 0x41, 0x48, 0xd6, 0x1c, 0x67, 0xe3, 0x19, 0xcd, - 0x81, 0x17, 0x83, 0xcc, 0x87, 0x2b, 0x1c, 0x28, 0x31, 0xde, 0xb6, 0x7e, - 0xe0, 0x95, 0x7e, 0x64, 0x2c, 0x33, 0x38, 0x0e, 0xc5, 0xc6, 0xc2, 0xad, - 0xc9, 0x7a, 0xea, 0xfb, 0xf2, 0xfe, 0xff, 0x8f, 0x35, 0xe9, 0x95, 0xfe, - 0x75, 0xcd, 0xaf, 0x72, 0x0c, 0x7f, 0x14, 0xbb, 0xbf, 0x6f, 0xbd, 0x64, - 0xb7, 0x79, 0xbb, 0x3b, 0x1b, 0x4f, 0xa5, 0xbd, 0xb7, 0x38, 0x3e, 0x69, - 0x33, 0xdf, 0x8f, 0xe8, 0xed, 0x8c, 0x5b, 0xfc, 0x79, 0x6b, 0x52, 0xf4, - 0x27, 0x78, 0x75, 0xd2, 0xc2, 0x34, 0x39, 0x7f, 0xd6, 0x2e, 0x1b, 0xa7, - 0xbe, 0xba, 0x68, 0x43, 0x8c, 0xe1, 0x3e, 0xd8, 0xbb, 0x3b, 0x34, 0x3b, - 0x9f, 0xdb, 0xcc, 0x1c, 0x60, 0xc8, 0x5b, 0x8e, 0xad, 0x26, 0xed, 0xce, - 0x50, 0xe7, 0x38, 0x61, 0xe1, 0xa4, 0x29, 0xe7, 0x2e, 0x4c, 0x7a, 0x1d, - 0xd8, 0x66, 0x3a, 0xb1, 0xce, 0x50, 0x75, 0xb9, 0xee, 0x08, 0xc9, 0xb9, - 0x0b, 0xfe, 0x6a, 0x05, 0x3b, 0x18, 0x3e, 0xd6, 0x1b, 0x5d, 0x7e, 0xb9, - 0xbe, 0x24, 0x24, 0xe7, 0x0a, 0xda, 0xa8, 0x93, 0xb8, 0xa6, 0x60, 0x83, - 0x21, 0xcf, 0x4d, 0xb3, 0xfc, 0x39, 0x06, 0xcb, 0xda, 0x61, 0x36, 0x5c, - 0x57, 0xc2, 0x72, 0x67, 0x4d, 0xe1, 0x83, 0x87, 0xef, 0x98, 0x1f, 0x88, - 0x47, 0x0b, 0xa0, 0xc7, 0x8a, 0xe8, 0xa7, 0x5b, 0x7b, 0x67, 0xb3, 0x9e, - 0x42, 0x6e, 0xe0, 0xf4, 0x6d, 0x87, 0xc4, 0xcf, 0x80, 0xff, 0xa7, 0x4c, - 0xb2, 0x86, 0xbc, 0xf3, 0xa8, 0x59, 0xc3, 0x7f, 0x9a, 0xf3, 0x56, 0x6e, - 0x38, 0xdb, 0x5f, 0x85, 0xbe, 0xae, 0x48, 0x99, 0x17, 0x2c, 0x63, 0xae, - 0x10, 0x27, 0xbe, 0x8f, 0x8c, 0x39, 0xb1, 0x25, 0x69, 0x68, 0x07, 0x6d, - 0xfe, 0xe7, 0xa4, 0x2e, 0x9c, 0xcc, 0xcf, 0x03, 0xda, 0x84, 0x92, 0x3f, - 0x9f, 0x2d, 0xd8, 0x40, 0x3e, 0x2f, 0xf8, 0x16, 0xb7, 0x9e, 0xad, 0x17, - 0xaa, 0xe1, 0xf6, 0xc7, 0x52, 0x1e, 0x1e, 0x1a, 0x0f, 0xaf, 0x7f, 0x4d, - 0xca, 0xe7, 0x6f, 0x4b, 0xc1, 0xdf, 0x9a, 0xca, 0xdb, 0x65, 0xde, 0xb7, - 0x05, 0xdb, 0x2c, 0x72, 0xd6, 0x6c, 0x6e, 0xd6, 0x25, 0xb9, 0x0f, 0xe4, - 0xb9, 0xdf, 0xe1, 0x3b, 0x9e, 0xa3, 0xad, 0xbb, 0x98, 0x0f, 0x6c, 0x33, - 0xe2, 0x51, 0x79, 0x0e, 0x69, 0x84, 0x74, 0x5f, 0x81, 0xe2, 0xc7, 0xd6, - 0xba, 0xdf, 0x72, 0x3e, 0xc9, 0x93, 0x53, 0x9f, 0x29, 0xca, 0xce, 0x87, - 0xf8, 0x99, 0x60, 0x80, 0x9f, 0xf9, 0x92, 0xcf, 0xdf, 0xc5, 0x7e, 0x36, - 0xa7, 0xa6, 0xfa, 0x80, 0x82, 0x9b, 0xd8, 0x56, 0x43, 0x08, 0xce, 0xa5, - 0x75, 0xbf, 0xb1, 0x32, 0xde, 0xec, 0x33, 0xc8, 0x2c, 0xe6, 0x81, 0x36, - 0x67, 0xf7, 0xe9, 0xdc, 0x5f, 0x27, 0xfb, 0x8e, 0x14, 0x0c, 0xd3, 0xa7, - 0x36, 0xa5, 0xc5, 0x9e, 0xb2, 0x7a, 0x8d, 0xff, 0x01, 0xfe, 0x98, 0xb8, - 0x37, 0x89, 0x58, 0x41, 0x44, 0xf0, 0xc7, 0xed, 0x7f, 0x29, 0x55, 0x47, - 0x0e, 0x2f, 0xcf, 0xf2, 0xdd, 0x9c, 0x67, 0x8f, 0xff, 0xc5, 0xd4, 0xf5, - 0xb8, 0x67, 0x4f, 0x18, 0xeb, 0xf6, 0xa0, 0xae, 0x88, 0x72, 0x17, 0x86, - 0x02, 0xfe, 0x51, 0x68, 0xfe, 0x67, 0xa8, 0x87, 0x13, 0x94, 0xed, 0xe4, - 0x25, 0xb2, 0x89, 0xde, 0xe0, 0xbf, 0x2f, 0xe1, 0x46, 0x2a, 0xf4, 0xa1, - 0x15, 0xb7, 0x79, 0x86, 0xd7, 0xbf, 0x31, 0xe1, 0x47, 0xc6, 0xe6, 0xac, - 0xae, 0x22, 0xc9, 0x1f, 0xbb, 0x93, 0xf1, 0x28, 0xd3, 0xe1, 0xdc, 0x9c, - 0xea, 0x61, 0x99, 0xcf, 0x33, 0x09, 0xb9, 0x17, 0xfd, 0x9a, 0x0a, 0xdd, - 0xaf, 0x32, 0x7e, 0xf6, 0x9b, 0x62, 0xb3, 0x35, 0xa2, 0x93, 0x20, 0x2b, - 0xc6, 0x3d, 0x91, 0x40, 0x4b, 0x1d, 0xaf, 0x6b, 0x0b, 0x10, 0xab, 0x88, - 0x08, 0x27, 0xf4, 0xfa, 0x6b, 0xc7, 0x7d, 0x7e, 0x73, 0x1c, 0xfe, 0x2b, - 0xc7, 0xa7, 0x8a, 0x40, 0x6e, 0xff, 0x89, 0xb9, 0x9f, 0xd7, 0xbf, 0x36, - 0x31, 0x1b, 0x6a, 0x24, 0x6e, 0x2d, 0xa9, 0x3f, 0x67, 0xcd, 0x8e, 0x18, - 0x99, 0x93, 0x94, 0xe1, 0xc3, 0x6b, 0xf5, 0xf8, 0x0c, 0xc7, 0x89, 0x87, - 0xb4, 0x29, 0x7d, 0xbc, 0x1f, 0xfa, 0xff, 0xdb, 0x47, 0x3e, 0xb6, 0x89, - 0xfc, 0x12, 0xdf, 0x72, 0x73, 0xaa, 0xe6, 0xc7, 0xa2, 0x70, 0x4e, 0x39, - 0x1f, 0xc9, 0x7c, 0xac, 0xb2, 0xac, 0x56, 0xc3, 0x97, 0x7b, 0xfe, 0x07, - 0xda, 0xcb, 0x89, 0xeb, 0x9c, 0x58, 0x4c, 0x7b, 0x6f, 0xf8, 0x6b, 0x27, - 0xa2, 0xbe, 0x42, 0xc6, 0x50, 0xd9, 0x53, 0xf0, 0x4c, 0xdd, 0xa4, 0x35, - 0x61, 0xd4, 0xa1, 0x21, 0x2d, 0xcf, 0x63, 0x1d, 0xb4, 0x63, 0x0b, 0x8f, - 0x9b, 0x72, 0x5f, 0xf0, 0x24, 0x1e, 0x73, 0xd0, 0x26, 0xdc, 0x86, 0xde, - 0xf2, 0x0f, 0x4a, 0x19, 0x8a, 0x23, 0xce, 0xe0, 0x04, 0xf4, 0xf0, 0x7a, - 0x72, 0x63, 0x7f, 0xc5, 0x3c, 0x53, 0xd4, 0xfe, 0x4e, 0x22, 0x60, 0x06, - 0x72, 0xf1, 0xe7, 0x2c, 0xe7, 0xeb, 0xdd, 0x84, 0xb1, 0xee, 0xb9, 0xdc, - 0xf9, 0xbf, 0xa5, 0xa6, 0xe6, 0xbf, 0x62, 0x77, 0x6e, 0xf7, 0xe6, 0x04, - 0xde, 0x77, 0xd4, 0xe3, 0xfd, 0xfd, 0x66, 0x01, 0xf3, 0x36, 0xb1, 0x47, - 0xb7, 0x7b, 0x6b, 0x02, 0x93, 0x4e, 0x5e, 0x3b, 0x6b, 0xce, 0x22, 0x76, - 0xa9, 0xbc, 0x16, 0x96, 0x58, 0x10, 0xd3, 0x18, 0x47, 0x8b, 0x23, 0x5e, - 0x77, 0xf1, 0x38, 0xb4, 0x22, 0xa3, 0x8c, 0x79, 0x31, 0x1a, 0x1d, 0x7d, - 0xba, 0xbf, 0xc9, 0x51, 0xc7, 0xfc, 0xd8, 0xaf, 0xb8, 0x8c, 0x6f, 0x31, - 0xcf, 0x97, 0xf5, 0xaa, 0x30, 0xc7, 0xed, 0x64, 0x85, 0x9d, 0xd3, 0xd4, - 0x88, 0x42, 0xcc, 0x2b, 0xc3, 0xbd, 0xda, 0x86, 0xc5, 0x6a, 0xa4, 0x1f, - 0xb7, 0xd6, 0xbb, 0x1b, 0xcb, 0xc7, 0xf3, 0x3a, 0x41, 0xcc, 0x13, 0x61, - 0x0e, 0x63, 0x40, 0x2d, 0x8d, 0x88, 0x6e, 0xfc, 0x8d, 0x7d, 0x63, 0x22, - 0xab, 0xe6, 0xee, 0x1d, 0xf3, 0x14, 0xa3, 0x38, 0x4c, 0x4c, 0xfa, 0x57, - 0xdf, 0x7f, 0xae, 0xde, 0x64, 0x91, 0xe0, 0xba, 0xcb, 0x90, 0xff, 0xb6, - 0x3d, 0xb9, 0xdd, 0x91, 0x63, 0x31, 0x77, 0xc0, 0xb2, 0x18, 0x0f, 0x7d, - 0x50, 0x66, 0x71, 0x3c, 0xf4, 0x29, 0xce, 0x4d, 0x5b, 0xea, 0x23, 0xeb, - 0x33, 0x4e, 0x3b, 0xd6, 0xbb, 0x0b, 0x23, 0xe1, 0xbb, 0xde, 0x36, 0x7e, - 0x6f, 0xbd, 0x95, 0x60, 0x5e, 0x4d, 0xdf, 0x2d, 0x20, 0x6e, 0x6f, 0x37, - 0x9d, 0x4d, 0x4b, 0x15, 0x05, 0xdd, 0xc6, 0x3c, 0xad, 0x88, 0xf1, 0x68, - 0x13, 0xfd, 0x37, 0xe6, 0x35, 0x82, 0xfb, 0xc1, 0x72, 0xa9, 0xb5, 0x6b, - 0x5d, 0x91, 0x8d, 0x77, 0x8d, 0xd4, 0x8b, 0xcf, 0x9f, 0xbf, 0xeb, 0x39, - 0xa3, 0x19, 0xdd, 0xe9, 0x41, 0xf4, 0xa4, 0xb3, 0xfd, 0x64, 0x30, 0xfb, - 0x13, 0xfa, 0x59, 0xbb, 0xb6, 0x30, 0x22, 0x1c, 0xeb, 0xe8, 0x5d, 0x07, - 0x8c, 0x28, 0xb6, 0xa4, 0x37, 0xde, 0x75, 0xb6, 0xbe, 0x9f, 0xff, 0xb3, - 0x75, 0x86, 0x50, 0xfe, 0x89, 0x75, 0x4a, 0x22, 0xd2, 0x47, 0x98, 0x7d, - 0x6c, 0xbc, 0x6b, 0xdd, 0xa2, 0xaf, 0x63, 0x73, 0x7a, 0xdd, 0x9f, 0xed, - 0xa7, 0x94, 0x75, 0x8a, 0x23, 0x1d, 0xad, 0x37, 0x05, 0x36, 0xde, 0x95, - 0x5a, 0xd4, 0xc3, 0x3e, 0x56, 0x31, 0x8e, 0x64, 0xeb, 0x44, 0x15, 0xc7, - 0x27, 0xea, 0xa0, 0x28, 0xd2, 0xd3, 0x3a, 0x3f, 0xf0, 0x7b, 0x6b, 0x5e, - 0x6f, 0x81, 0xad, 0x03, 0x17, 0x75, 0xf0, 0xa8, 0xe9, 0xcc, 0x04, 0x1c, - 0xb6, 0x0e, 0x3a, 0x7c, 0xd4, 0x41, 0x1f, 0x75, 0x90, 0xa9, 0x36, 0xc2, - 0xef, 0x51, 0x07, 0xf3, 0xc6, 0xd6, 0xae, 0x2d, 0x8a, 0xc0, 0xe9, 0x30, - 0x5e, 0x77, 0x38, 0x39, 0x17, 0x2e, 0x63, 0x2d, 0xf5, 0xb6, 0xf1, 0xae, - 0x39, 0x8b, 0x6c, 0x9d, 0x7f, 0xd9, 0x1d, 0xd8, 0x60, 0xef, 0xdd, 0xdb, - 0x94, 0x6e, 0xe3, 0xd1, 0xc4, 0xe3, 0x61, 0x1e, 0xdd, 0xcc, 0x4d, 0xee, - 0xa0, 0xae, 0x1a, 0x39, 0x8e, 0x15, 0x94, 0xab, 0x9d, 0xbf, 0x5b, 0xf8, - 0xbb, 0x83, 0xbf, 0x65, 0x7e, 0xd4, 0x0b, 0xb2, 0xc5, 0x2e, 0xc8, 0xe6, - 0xa0, 0x3c, 0x1e, 0x62, 0x94, 0x8c, 0x69, 0xe2, 0xcb, 0x37, 0x05, 0x62, - 0x6c, 0xe3, 0xa9, 0x62, 0xd9, 0xf7, 0xe4, 0x32, 0xe2, 0x3e, 0x27, 0x44, - 0x3e, 0xbd, 0x65, 0x1d, 0x32, 0xc4, 0xd8, 0xdf, 0x65, 0x31, 0x96, 0xb2, - 0x95, 0x71, 0x7e, 0x5e, 0x59, 0x34, 0x34, 0xdd, 0x63, 0xc0, 0xe7, 0x36, - 0xe2, 0xe8, 0x4d, 0x27, 0xa8, 0x03, 0xb1, 0x93, 0x07, 0xa9, 0xbf, 0x4e, - 0x74, 0x19, 0x27, 0xf4, 0xec, 0xde, 0x89, 0xbd, 0x94, 0x21, 0x48, 0x7e, - 0xe8, 0x81, 0x33, 0xa2, 0xfb, 0x1b, 0x1d, 0x5d, 0x41, 0x17, 0x68, 0xcb, - 0xc5, 0x62, 0xcb, 0x71, 0xc6, 0x35, 0xc1, 0x3a, 0xb7, 0xd6, 0x66, 0xe3, - 0x5f, 0x7c, 0xbe, 0x0b, 0x1e, 0x6d, 0x4d, 0x2a, 0x1f, 0x0b, 0x3c, 0x5a, - 0x6b, 0x42, 0xfc, 0x4a, 0xd6, 0xfc, 0xc3, 0x76, 0x2c, 0x3f, 0x9e, 0x7e, - 0xb1, 0x18, 0x65, 0xb6, 0x8f, 0x95, 0x39, 0x8d, 0x6c, 0xbb, 0x1a, 0xdb, - 0x6d, 0x76, 0x68, 0xb8, 0xe8, 0x23, 0xba, 0xd6, 0xec, 0x90, 0x7d, 0xae, - 0xf4, 0xfe, 0x54, 0xae, 0x5e, 0x16, 0x27, 0x16, 0xbb, 0x6c, 0x9c, 0x60, - 0x1b, 0xc5, 0xc0, 0x92, 0xc4, 0xe5, 0xfd, 0x4b, 0x7f, 0xd2, 0x6f, 0x57, - 0x85, 0x8a, 0x09, 0xfb, 0x99, 0xcb, 0x91, 0x74, 0x0c, 0x83, 0xc9, 0xa9, - 0x7b, 0xf9, 0xf4, 0xa3, 0x6c, 0xff, 0x70, 0x9c, 0xfa, 0x98, 0x65, 0xc8, - 0x3e, 0x3f, 0xd9, 0xdb, 0x37, 0x75, 0x5f, 0x9f, 0xc8, 0x56, 0x58, 0x42, - 0x00, 0xc1, 0x01, 0xe2, 0x4c, 0xb4, 0x59, 0xea, 0x5b, 0xd6, 0x1b, 0xf3, - 0x82, 0xc8, 0x54, 0x39, 0x31, 0x38, 0x17, 0x18, 0xe8, 0x93, 0x7d, 0x57, - 0x47, 0x63, 0xab, 0x99, 0x97, 0x45, 0x2b, 0x6b, 0xb5, 0x4d, 0xaa, 0xec, - 0x99, 0x3a, 0xf6, 0xe5, 0x6e, 0xa3, 0x46, 0xeb, 0x56, 0x33, 0x87, 0x88, - 0xdd, 0x7b, 0x81, 0x69, 0x25, 0xe2, 0x6b, 0x15, 0x46, 0xb4, 0xa7, 0x02, - 0x73, 0xe1, 0xaf, 0xb4, 0xf1, 0x32, 0xfe, 0x94, 0x6a, 0x04, 0x57, 0xda, - 0x38, 0xf8, 0xa1, 0x35, 0xc4, 0xb8, 0xf4, 0x95, 0xb9, 0x3f, 0x28, 0xce, - 0xe6, 0xd9, 0xd1, 0x75, 0xd3, 0x38, 0x57, 0xbf, 0x58, 0xa0, 0xfb, 0x53, - 0x8a, 0xe8, 0x48, 0xb8, 0x49, 0x02, 0xdb, 0xc8, 0x75, 0x7f, 0x33, 0x37, - 0x82, 0x83, 0xfc, 0xff, 0xf3, 0xeb, 0x65, 0x0f, 0xaa, 0x65, 0x05, 0x03, - 0xf3, 0xc2, 0x15, 0x1c, 0xc3, 0x8b, 0xbc, 0xdf, 0x93, 0x7e, 0xdb, 0x3a, - 0x3b, 0xcd, 0xe8, 0x5f, 0xc6, 0x40, 0x32, 0x30, 0xae, 0x6b, 0x93, 0xea, - 0x7f, 0x76, 0x4f, 0x1d, 0xdc, 0x65, 0x1c, 0xcb, 0xf7, 0x02, 0xb5, 0x5a, - 0x9f, 0xaa, 0x96, 0x88, 0x5e, 0x07, 0xc6, 0x7f, 0x3c, 0x65, 0xaf, 0x47, - 0x9e, 0x1f, 0xda, 0x6b, 0x1d, 0x3d, 0x43, 0xf4, 0xa9, 0x21, 0x2d, 0x1a, - 0xa7, 0xde, 0xdd, 0x55, 0x1c, 0xf3, 0x57, 0xe6, 0xde, 0x6a, 0x8f, 0xb3, - 0xd2, 0x98, 0xc1, 0x31, 0x2a, 0xd0, 0xe6, 0xfe, 0x2c, 0xb7, 0xee, 0xd9, - 0x40, 0x36, 0x33, 0x64, 0x35, 0xd2, 0x06, 0x0b, 0x58, 0xe7, 0x46, 0x73, - 0xdf, 0xf4, 0xae, 0x3a, 0xdd, 0xf7, 0x15, 0xc6, 0xce, 0xd0, 0xdc, 0x5f, - 0x5b, 0x51, 0xcd, 0x69, 0x7e, 0x93, 0xa3, 0xbe, 0x27, 0x21, 0x65, 0x65, - 0x5e, 0x8d, 0xe8, 0x5c, 0xe5, 0x5d, 0x0b, 0xd5, 0x81, 0xf0, 0x5c, 0x7b, - 0xfc, 0xc0, 0xdd, 0xa9, 0x04, 0xb6, 0x27, 0xa5, 0x4d, 0x05, 0xcb, 0x02, - 0xef, 0x58, 0xfe, 0x69, 0x09, 0x6c, 0x4d, 0xff, 0x29, 0xae, 0x37, 0x28, - 0x71, 0xbf, 0x25, 0x0e, 0x3d, 0x9a, 0x7d, 0xc6, 0x35, 0x5b, 0xd6, 0x94, - 0x65, 0x0f, 0xd2, 0x5d, 0x89, 0x00, 0xdc, 0xa5, 0xc4, 0xba, 0xb1, 0x80, - 0x3c, 0x13, 0xf5, 0x22, 0xd3, 0x2c, 0x65, 0x6a, 0xb4, 0x31, 0x64, 0xc8, - 0xc4, 0x64, 0x7d, 0xb2, 0xa7, 0x24, 0xbb, 0x9f, 0x82, 0x86, 0x57, 0xad, - 0x6b, 0x67, 0xc8, 0x9d, 0x9a, 0x0c, 0x69, 0x43, 0xc1, 0xfc, 0x40, 0x15, - 0x6a, 0x57, 0xbe, 0xfe, 0x66, 0x41, 0xa0, 0x80, 0xb8, 0x2d, 0xfe, 0x64, - 0xb4, 0x9f, 0xc4, 0xbf, 0xd3, 0xd7, 0x65, 0x6f, 0xd9, 0x16, 0xa9, 0xc7, - 0xb6, 0xe6, 0x22, 0xa5, 0x39, 0xc9, 0x33, 0x64, 0x9f, 0xb2, 0x65, 0xdd, - 0x14, 0x78, 0xcb, 0x8a, 0x56, 0x53, 0x1e, 0xf2, 0x9f, 0x6c, 0x5d, 0x29, - 0x93, 0xdb, 0x33, 0xa4, 0x34, 0xdc, 0x25, 0x3a, 0x79, 0xd6, 0x8c, 0x93, - 0x5d, 0x0b, 0xbe, 0x1e, 0x8b, 0xbd, 0x6d, 0x28, 0xf6, 0xb3, 0xca, 0x65, - 0x4a, 0x39, 0xe3, 0x95, 0xd3, 0x3f, 0x62, 0xe7, 0xdf, 0x61, 0x62, 0xa1, - 0xf0, 0x35, 0xc9, 0xa1, 0x9c, 0x78, 0xce, 0xa8, 0xc0, 0xb3, 0x5a, 0x96, - 0xfb, 0x10, 0x53, 0xf0, 0x6a, 0x62, 0x5e, 0x86, 0x1e, 0x42, 0x0e, 0x69, - 0xac, 0x3b, 0xaf, 0xfc, 0x3b, 0xf3, 0x2b, 0xe0, 0x95, 0x54, 0x3b, 0x1e, - 0x95, 0x75, 0x3d, 0xa5, 0xa6, 0xa9, 0xd6, 0x21, 0xfd, 0xb5, 0x63, 0x5b, - 0x5a, 0xda, 0x3a, 0x16, 0x3b, 0x60, 0xf4, 0xe7, 0x64, 0x15, 0xcc, 0x3c, - 0x16, 0x7b, 0xce, 0x78, 0xdc, 0x9e, 0x3b, 0x79, 0x7e, 0xd6, 0x63, 0x0a, - 0xb6, 0x14, 0x43, 0x25, 0x0f, 0x77, 0x18, 0x77, 0xc0, 0x51, 0xf1, 0x75, - 0xda, 0x9e, 0xec, 0xbf, 0xb9, 0x13, 0xce, 0x0a, 0x17, 0x7d, 0xf3, 0x6e, - 0xb8, 0x2a, 0x84, 0xfb, 0xe6, 0x79, 0x69, 0x94, 0xf7, 0x45, 0xb7, 0xe7, - 0x6d, 0xdd, 0x3a, 0x89, 0xa7, 0xdd, 0x92, 0x27, 0x19, 0xe5, 0xd4, 0x91, - 0xde, 0x42, 0x8e, 0x8c, 0x52, 0x62, 0x13, 0xe3, 0x90, 0xbb, 0x9c, 0x65, - 0xde, 0xa3, 0xde, 0xe7, 0xf5, 0x96, 0x90, 0x13, 0x5b, 0xd6, 0x87, 0xe4, - 0xc4, 0xf3, 0x03, 0xb5, 0x19, 0x83, 0xf1, 0x03, 0xb7, 0xe9, 0x4d, 0x71, - 0xe6, 0x88, 0xab, 0x8d, 0xf3, 0x56, 0x6c, 0x95, 0x94, 0xd1, 0x7d, 0x31, - 0x25, 0xdf, 0xc7, 0x02, 0xf8, 0xab, 0x2c, 0xb8, 0x22, 0xb2, 0x96, 0x2f, - 0x6b, 0xb8, 0x0d, 0xf2, 0xcc, 0xb0, 0x59, 0xc6, 0xef, 0x92, 0x75, 0x41, - 0x44, 0x27, 0x5c, 0x30, 0x32, 0x07, 0x65, 0xce, 0xa6, 0x5b, 0x08, 0x2c, - 0xfc, 0x1d, 0x73, 0x0b, 0x99, 0x9f, 0x9a, 0x4c, 0x9d, 0x92, 0x09, 0xfa, - 0xc8, 0x91, 0x9f, 0x80, 0xde, 0x9c, 0xa0, 0xae, 0x1b, 0x43, 0xb2, 0x0f, - 0xc0, 0xe9, 0x4b, 0xc0, 0xe6, 0xc5, 0xe6, 0x69, 0x7c, 0x06, 0xa5, 0xcc, - 0x05, 0xe7, 0x8e, 0xad, 0x40, 0x59, 0x45, 0xd4, 0x57, 0x8c, 0x6b, 0x78, - 0xde, 0x46, 0xbe, 0xff, 0x05, 0x94, 0xad, 0x6c, 0x41, 0x82, 0x63, 0x2f, - 0x35, 0xbe, 0xc4, 0x6b, 0x0f, 0xa3, 0x2f, 0xe9, 0xe2, 0x38, 0xfe, 0xd5, - 0x2a, 0xab, 0x16, 0xd9, 0x4c, 0x6f, 0x09, 0xf3, 0xf4, 0xa8, 0xad, 0x0b, - 0x62, 0x63, 0x52, 0xb8, 0x48, 0x6d, 0x74, 0x3d, 0x98, 0x2b, 0x57, 0xeb, - 0x2d, 0x6d, 0x4a, 0x07, 0x6d, 0xb6, 0x9b, 0x3a, 0x97, 0xb2, 0x96, 0xb5, - 0x3c, 0x30, 0x49, 0x1d, 0x77, 0xf0, 0xdc, 0xf0, 0xbf, 0x05, 0xf5, 0x9a, - 0x42, 0x9c, 0xb2, 0xe2, 0x9a, 0x8f, 0x76, 0xa9, 0xae, 0x12, 0xde, 0xb2, - 0x34, 0x74, 0xae, 0x44, 0xf6, 0x21, 0x67, 0xed, 0xf4, 0x68, 0x4e, 0x97, - 0xe7, 0xef, 0xea, 0x36, 0x5e, 0xb5, 0xaf, 0x3b, 0xec, 0xeb, 0xe1, 0xdc, - 0xf5, 0xa3, 0xbc, 0xfe, 0x3d, 0x5e, 0xef, 0xa1, 0xee, 0xd5, 0x2b, 0xa4, - 0xfe, 0x5a, 0x53, 0xea, 0x33, 0x45, 0x31, 0xba, 0x73, 0xf3, 0xd1, 0xd1, - 0x9a, 0x2d, 0xdb, 0xd3, 0x9a, 0x6d, 0xc3, 0xc9, 0x36, 0xe2, 0xd1, 0x62, - 0x98, 0x28, 0x61, 0x9c, 0x3f, 0x6b, 0x88, 0x5c, 0x9c, 0xbb, 0xb4, 0xc8, - 0xd5, 0xc6, 0xb8, 0xd2, 0xf5, 0x42, 0x31, 0xe2, 0x1d, 0x33, 0x6c, 0x3b, - 0x3c, 0x7a, 0x97, 0xec, 0x8f, 0x7b, 0x5b, 0x69, 0xf0, 0xc9, 0xb6, 0xca, - 0x24, 0x79, 0xe2, 0x43, 0xa6, 0x33, 0x5c, 0xe7, 0x98, 0x97, 0x29, 0x84, - 0x11, 0x3b, 0xaf, 0x7c, 0x64, 0xe3, 0x43, 0x22, 0xd5, 0xc0, 0x4c, 0x26, - 0x1e, 0x64, 0x0e, 0x12, 0x4c, 0x53, 0xb7, 0xad, 0x44, 0xec, 0xa3, 0xf6, - 0x1e, 0x39, 0xe7, 0xc4, 0x0a, 0x34, 0xe8, 0x0e, 0xcc, 0x0b, 0xcf, 0x60, - 0x26, 0x43, 0xbb, 0x34, 0x0b, 0x1d, 0xba, 0xff, 0x56, 0x7c, 0xc6, 0x23, - 0xf5, 0x0e, 0xa6, 0x32, 0xeb, 0x8a, 0x39, 0xa7, 0xdf, 0xa0, 0x1c, 0xdb, - 0x03, 0x22, 0xc7, 0xd7, 0x73, 0x72, 0xb4, 0x30, 0x66, 0x99, 0xda, 0xcd, - 0x81, 0x9e, 0x0b, 0x7a, 0x7b, 0xc1, 0xd6, 0xdb, 0xc3, 0x3c, 0x2f, 0x64, - 0xbe, 0x5c, 0x80, 0x13, 0x75, 0xde, 0xdc, 0x7e, 0x37, 0xc9, 0x7d, 0x04, - 0x7f, 0xcf, 0x7c, 0x69, 0xb5, 0xa1, 0x87, 0x1d, 0x36, 0x67, 0x76, 0x23, - 0x6e, 0xf3, 0x51, 0x79, 0x76, 0x5e, 0x86, 0xc7, 0xed, 0x72, 0x2e, 0xea, - 0xa4, 0x04, 0x4f, 0xe4, 0xfc, 0x45, 0xf6, 0x2e, 0x7c, 0xc3, 0xfe, 0xbd, - 0x97, 0x73, 0xeb, 0xa2, 0xaf, 0xe6, 0x63, 0x94, 0xac, 0x81, 0x6f, 0xb4, - 0x7d, 0x7f, 0x08, 0xc7, 0xec, 0xff, 0x99, 0x6c, 0xfe, 0x82, 0x6e, 0x53, - 0xf6, 0xfc, 0x94, 0x60, 0x93, 0x3c, 0x8b, 0x4c, 0x4b, 0x4e, 0x7d, 0x3d, - 0xb6, 0x70, 0x54, 0x6e, 0x83, 0x1c, 0x43, 0x13, 0x9b, 0xe8, 0x44, 0x9f, - 0x66, 0x7a, 0xd3, 0x75, 0x53, 0x73, 0x0f, 0x13, 0xfb, 0xeb, 0x7e, 0x6f, - 0x45, 0xed, 0x7c, 0xe4, 0x94, 0x75, 0xc0, 0x38, 0x11, 0xa2, 0x07, 0xaf, - 0x2b, 0xb0, 0xf5, 0x7b, 0xfe, 0x2e, 0x7b, 0x9f, 0x20, 0x65, 0x7e, 0x21, - 0x21, 0x71, 0x74, 0x36, 0x52, 0xa6, 0xc8, 0xe6, 0x6c, 0xde, 0xc1, 0x39, - 0xe9, 0x4e, 0x06, 0xa2, 0x57, 0xf2, 0xde, 0x04, 0x63, 0xd9, 0x26, 0xea, - 0x33, 0xd6, 0x2c, 0x3c, 0xa8, 0x0d, 0x7b, 0x69, 0x63, 0xe3, 0xa6, 0x65, - 0x1d, 0x24, 0x46, 0x94, 0xcf, 0x53, 0x91, 0xa9, 0x6e, 0x43, 0x92, 0xb1, - 0xe9, 0xa0, 0xd1, 0xf0, 0x99, 0x02, 0xc4, 0xfd, 0x6e, 0xe8, 0xbe, 0xad, - 0x1c, 0xcd, 0x43, 0x9c, 0xaf, 0x13, 0xa6, 0xf0, 0x33, 0xe7, 0xf9, 0xa5, - 0x30, 0xc2, 0x8b, 0x1d, 0xff, 0x6a, 0x4d, 0xda, 0xcf, 0x51, 0xbb, 0xfe, - 0x27, 0x65, 0x68, 0x17, 0xe7, 0x2d, 0xe7, 0x1c, 0xbf, 0x17, 0x90, 0xe7, - 0xe0, 0x40, 0x6d, 0x6f, 0xc3, 0x3a, 0x91, 0xe1, 0x40, 0xc8, 0x19, 0x3b, - 0x88, 0x40, 0xf3, 0x06, 0xe5, 0x22, 0x07, 0xbf, 0x72, 0xcc, 0xc4, 0x68, - 0xdd, 0x8b, 0xe4, 0x0b, 0x52, 0xbf, 0x10, 0x4f, 0x9b, 0xcf, 0x5b, 0x35, - 0xd3, 0xbf, 0x67, 0x1d, 0x32, 0xd4, 0xf5, 0xd4, 0x76, 0xac, 0x94, 0x6d, - 0x95, 0xb0, 0xad, 0x7b, 0x03, 0xba, 0xb9, 0x83, 0x6d, 0x3d, 0x93, 0x38, - 0x11, 0x74, 0xb3, 0xad, 0x27, 0x4c, 0xe1, 0xe0, 0xce, 0xa6, 0x26, 0xce, - 0x6d, 0x57, 0x32, 0xe0, 0xdb, 0x46, 0xb9, 0x24, 0x37, 0xba, 0x33, 0x21, - 0xef, 0x74, 0x7c, 0x9d, 0xe3, 0x89, 0xb6, 0xbb, 0xd0, 0xf0, 0x50, 0x19, - 0xed, 0xa7, 0x1c, 0x79, 0x5b, 0xd7, 0x7d, 0xc4, 0x3b, 0xdc, 0xcb, 0x32, - 0x6f, 0x06, 0x66, 0xe3, 0x95, 0x50, 0xc3, 0xca, 0xd9, 0x70, 0xc6, 0x0e, - 0x29, 0x81, 0xa6, 0x0d, 0x4a, 0x5c, 0x13, 0x5b, 0xbc, 0x27, 0xa5, 0x07, - 0x1b, 0x21, 0xd8, 0xdd, 0x42, 0x7d, 0xcc, 0xc6, 0x87, 0x0b, 0x45, 0x2e, - 0x67, 0x38, 0xe8, 0x08, 0x74, 0x3c, 0xcf, 0xf9, 0x2d, 0x9b, 0x97, 0xcd, - 0xfb, 0xd2, 0xf6, 0xbe, 0xce, 0x16, 0xf4, 0xa5, 0x4f, 0xbd, 0x77, 0xc0, - 0x80, 0xf3, 0x68, 0xdd, 0xa3, 0x16, 0xec, 0x77, 0x40, 0x1a, 0x64, 0x1e, - 0x5a, 0x64, 0x1e, 0x8a, 0xe9, 0x4f, 0x37, 0x51, 0xee, 0xf5, 0xb6, 0xdc, - 0xb3, 0x31, 0x6c, 0xca, 0x7a, 0x92, 0x53, 0xbb, 0x07, 0x3d, 0xc4, 0xce, - 0xc0, 0xf9, 0x2e, 0xf6, 0xf3, 0x26, 0x65, 0x9e, 0x47, 0xbd, 0x4f, 0x36, - 0x0b, 0x3f, 0x7c, 0x18, 0xbd, 0xc9, 0xfc, 0x3b, 0x22, 0x0a, 0x52, 0x01, - 0xe9, 0xe3, 0x61, 0xf2, 0xa5, 0x2e, 0x6b, 0xb2, 0x5a, 0xae, 0xef, 0x65, - 0x2e, 0x1d, 0xd5, 0xe8, 0x0f, 0xd4, 0x3b, 0xf4, 0xd9, 0xd0, 0x27, 0xce, - 0x38, 0xa2, 0xf4, 0x01, 0xd3, 0x7b, 0x9e, 0xd8, 0x70, 0x14, 0x1d, 0x16, - 0x2a, 0x6c, 0x7b, 0xf8, 0xf9, 0x88, 0xf1, 0x0b, 0x45, 0x62, 0x7b, 0x86, - 0x3a, 0x60, 0xb6, 0xdf, 0x2e, 0x3a, 0x28, 0xa5, 0xcf, 0x8e, 0x05, 0x74, - 0xff, 0x2b, 0x94, 0x67, 0x07, 0xe5, 0x59, 0x91, 0x9d, 0x43, 0xdf, 0x16, - 0x45, 0x7c, 0x3a, 0xd0, 0xbc, 0x9a, 0xd7, 0xb7, 0x53, 0x9e, 0x40, 0xaf, - 0x82, 0xa1, 0xe6, 0x6e, 0xf2, 0xb1, 0x0e, 0xea, 0xe0, 0xa2, 0x3c, 0x6e, - 0x7b, 0xce, 0x3a, 0xc8, 0x05, 0x0a, 0x99, 0xff, 0x0b, 0x7e, 0x6b, 0x18, - 0xa6, 0x9d, 0xee, 0xe7, 0x8c, 0x44, 0xbd, 0x2a, 0x0a, 0x0d, 0xc1, 0x80, - 0x6a, 0x5e, 0x73, 0x71, 0x6e, 0xca, 0x71, 0x48, 0xdb, 0x6b, 0xef, 0x69, - 0xce, 0xe6, 0xea, 0x1f, 0x59, 0xa3, 0x5e, 0xe1, 0x67, 0xb2, 0xde, 0x24, - 0x6b, 0x32, 0x71, 0x4f, 0x76, 0x4f, 0xb5, 0x8b, 0x3a, 0xc9, 0x5e, 0x7f, - 0x41, 0x73, 0xe4, 0xf2, 0x66, 0xb9, 0xfe, 0x81, 0xf5, 0xac, 0x5d, 0x5e, - 0xca, 0xb9, 0x6c, 0x2e, 0x5c, 0x6c, 0x97, 0xfb, 0xc0, 0x7a, 0x51, 0x73, - 0x4e, 0x29, 0x97, 0x7f, 0x86, 0x77, 0xe2, 0x6b, 0x4e, 0x62, 0x5e, 0xe1, - 0xdc, 0xc5, 0x38, 0x69, 0x9c, 0xaa, 0x39, 0x5d, 0xd7, 0xc9, 0x38, 0x36, - 0x75, 0x1f, 0x98, 0x85, 0x27, 0xed, 0x1c, 0xb7, 0x6b, 0xbe, 0x03, 0x27, - 0x76, 0x16, 0xd0, 0x27, 0xa3, 0x9a, 0xac, 0x87, 0x45, 0x4b, 0x72, 0x7b, - 0x55, 0x24, 0x6f, 0x0c, 0xfa, 0xd5, 0xab, 0x6d, 0x6e, 0x18, 0x55, 0xff, - 0xdc, 0x7e, 0x3b, 0xe1, 0x2e, 0x9d, 0xd8, 0x6f, 0xe4, 0x39, 0xcb, 0x89, - 0x47, 0x55, 0xe2, 0xe4, 0x80, 0xb9, 0x58, 0x62, 0xb3, 0x9f, 0xf5, 0x83, - 0x31, 0x75, 0x2a, 0xb7, 0x59, 0xed, 0x41, 0x59, 0xd7, 0x36, 0x07, 0x64, - 0x9f, 0xa9, 0xec, 0x19, 0x95, 0xbe, 0x8a, 0x72, 0xeb, 0x3c, 0x9f, 0xc4, - 0x35, 0xf2, 0x7d, 0x09, 0xdf, 0xf8, 0x20, 0xc7, 0xdd, 0xf4, 0x60, 0xd4, - 0x96, 0xf3, 0x57, 0xd6, 0x4a, 0x2d, 0x33, 0x43, 0xc3, 0xa5, 0xb2, 0x47, - 0x73, 0xb2, 0xc7, 0x3e, 0x71, 0x9d, 0x4a, 0xfa, 0x99, 0xda, 0x66, 0x7e, - 0x4f, 0xb7, 0xac, 0x61, 0xca, 0x3d, 0x05, 0x5d, 0xc4, 0xa1, 0xa8, 0xd6, - 0xc0, 0x38, 0xaf, 0xfb, 0xd6, 0x70, 0x3e, 0xe2, 0x5e, 0xd9, 0xcb, 0x9e, - 0x8f, 0x91, 0x85, 0xc8, 0xae, 0x25, 0xca, 0x7e, 0x87, 0xec, 0xfa, 0x21, - 0xed, 0x1e, 0x5d, 0xa9, 0xdf, 0x59, 0x19, 0xaf, 0x93, 0xb1, 0xf0, 0xe2, - 0x3e, 0xea, 0x21, 0xea, 0x55, 0xd6, 0x41, 0xb6, 0x5c, 0x58, 0xab, 0x90, - 0x35, 0x1a, 0x89, 0xbd, 0xbf, 0xb5, 0x5a, 0x2f, 0x29, 0x3b, 0x75, 0x4f, - 0x79, 0x75, 0x4c, 0x9e, 0x83, 0x8d, 0xe6, 0xd6, 0xb1, 0x1b, 0xff, 0xe0, - 0x39, 0xd8, 0x04, 0x6d, 0x09, 0xd1, 0x2d, 0xe4, 0x76, 0x71, 0x74, 0x63, - 0x34, 0x51, 0xab, 0x6d, 0x85, 0x26, 0xeb, 0xb7, 0xfc, 0xeb, 0xc6, 0xa1, - 0x04, 0xa2, 0x05, 0x57, 0x95, 0x93, 0x6f, 0x21, 0xea, 0x60, 0x8c, 0x7a, - 0x22, 0x51, 0xdb, 0xb4, 0x9d, 0x63, 0xf2, 0xaf, 0xec, 0xc6, 0x70, 0xa2, - 0xe1, 0x4b, 0x8c, 0x23, 0xfe, 0x12, 0x9b, 0xeb, 0x44, 0xff, 0xcb, 0x01, - 0xe2, 0xc0, 0xe6, 0xdc, 0x1a, 0x52, 0x6b, 0xe2, 0xd7, 0x94, 0xdf, 0x16, - 0x92, 0xf5, 0xfe, 0x54, 0xb9, 0x09, 0xe6, 0xd3, 0xa7, 0xb0, 0xb6, 0x5f, - 0xc1, 0xb3, 0xc6, 0x29, 0xac, 0x19, 0x12, 0x79, 0x4e, 0xa1, 0xad, 0xff, - 0xfb, 0xd8, 0xdf, 0x3f, 0x1d, 0x8d, 0xb6, 0x6e, 0x3a, 0xb0, 0x61, 0xd7, - 0x11, 0xec, 0x48, 0x5a, 0xd8, 0x1e, 0xf2, 0x60, 0xfd, 0x3e, 0x05, 0xcb, - 0x03, 0xc7, 0xb0, 0x75, 0x97, 0x85, 0x39, 0xa1, 0x4e, 0x34, 0x99, 0x25, - 0x28, 0xac, 0x98, 0xb7, 0x4e, 0x65, 0xb9, 0xd6, 0xe1, 0x8e, 0xdc, 0xfe, - 0xe5, 0x43, 0xc4, 0x02, 0x15, 0x3e, 0x43, 0xf6, 0x26, 0x47, 0x95, 0xdb, - 0xd3, 0x8d, 0x4a, 0x4b, 0xee, 0x39, 0xe2, 0xad, 0xe9, 0x8f, 0x99, 0xff, - 0xc4, 0xb1, 0x3f, 0x74, 0x0a, 0x43, 0x43, 0xbf, 0x2e, 0xcd, 0xfa, 0xcb, - 0x04, 0xb9, 0x83, 0xe4, 0x1c, 0x26, 0x6d, 0xea, 0x4f, 0xbd, 0x37, 0x24, - 0x76, 0x37, 0x89, 0x9f, 0x0e, 0x9e, 0xc6, 0xe9, 0xc1, 0x7f, 0xc1, 0x12, - 0x4d, 0xf2, 0x34, 0xab, 0xd3, 0x19, 0xb1, 0xac, 0x3d, 0xf5, 0x71, 0xab, - 0xda, 0x78, 0xab, 0x0c, 0xc5, 0x65, 0x98, 0x16, 0x79, 0x0d, 0xdb, 0x35, - 0xb6, 0x95, 0x3c, 0x84, 0x9d, 0x8c, 0xeb, 0xbe, 0xc8, 0x1d, 0xf0, 0x25, - 0x33, 0x66, 0x25, 0xa2, 0x3b, 0x2b, 0xa1, 0xb7, 0x57, 0x38, 0x8c, 0x8e, - 0x7f, 0x56, 0xea, 0x70, 0x6b, 0xfa, 0x34, 0x7e, 0x31, 0x68, 0xef, 0xc9, - 0x6a, 0xf9, 0xb6, 0x62, 0x75, 0x6e, 0x0f, 0xe9, 0x4d, 0xff, 0x55, 0x89, - 0xc6, 0x65, 0x2f, 0x4f, 0x11, 0x73, 0x82, 0xdb, 0x06, 0x25, 0xdf, 0x6c, - 0x81, 0xbb, 0x57, 0xcf, 0x2c, 0x25, 0xcf, 0xfe, 0xca, 0x82, 0xf8, 0x8c, - 0x2a, 0xda, 0xa5, 0x43, 0xd1, 0x83, 0x86, 0xda, 0x89, 0xe3, 0xa6, 0x3e, - 0xf1, 0x5b, 0x87, 0x31, 0xf4, 0x2d, 0xd4, 0x61, 0x55, 0x5a, 0x1f, 0xba, - 0x86, 0x79, 0xd8, 0xd6, 0x3e, 0x13, 0xc9, 0x3e, 0xbd, 0xa5, 0xc3, 0xd1, - 0x83, 0xfb, 0x02, 0x35, 0xed, 0xef, 0x91, 0xcb, 0x79, 0x88, 0x29, 0x7d, - 0xe3, 0x23, 0xcc, 0x13, 0x7b, 0xb0, 0x61, 0x5f, 0x04, 0xeb, 0xf7, 0x98, - 0xe8, 0xee, 0x1b, 0xa1, 0x6c, 0x2f, 0x95, 0xca, 0x1e, 0x96, 0xe6, 0x50, - 0xfc, 0x66, 0x15, 0x81, 0x28, 0xfb, 0x6c, 0x50, 0x23, 0x01, 0xbf, 0xaa, - 0x30, 0xfa, 0x8f, 0x3b, 0xb1, 0x89, 0x65, 0x7a, 0x93, 0xb4, 0xb9, 0x3e, - 0x37, 0xe3, 0xe5, 0x4c, 0x0c, 0x8f, 0xf9, 0x70, 0x70, 0xcc, 0x83, 0xa1, - 0x31, 0x8d, 0x47, 0x31, 0x1e, 0x1b, 0x90, 0xbd, 0x20, 0x5e, 0x3c, 0x7d, - 0xc0, 0x8d, 0xcd, 0xbb, 0x3d, 0x98, 0x1d, 0x99, 0x86, 0x03, 0x07, 0x8a, - 0xb1, 0x97, 0xd7, 0x2b, 0x16, 0xfa, 0xf1, 0x24, 0xaf, 0xf7, 0xef, 0x76, - 0x71, 0x1e, 0xe6, 0xe0, 0x30, 0x0d, 0x7b, 0x68, 0xac, 0x04, 0xc9, 0x01, - 0x9a, 0x3c, 0x39, 0xeb, 0xdb, 0xcc, 0x30, 0x46, 0x0f, 0x30, 0x36, 0xee, - 0x33, 0x91, 0x60, 0x3f, 0x3b, 0xa8, 0xab, 0x6e, 0xe2, 0xda, 0x86, 0x31, - 0xc1, 0xf8, 0x55, 0xb8, 0xa9, 0x57, 0x6f, 0x6a, 0x54, 0x8c, 0xe8, 0x22, - 0x7b, 0xbf, 0x97, 0xbc, 0xdf, 0xb5, 0x0a, 0x0d, 0x09, 0xdd, 0x6c, 0x44, - 0x27, 0x4e, 0x72, 0xdc, 0xff, 0x17, 0xfd, 0x76, 0xb1, 0x43, 0xef, 0xb9, - 0x51, 0x3d, 0x82, 0x9d, 0xe9, 0xa3, 0xe4, 0xea, 0x40, 0x78, 0xff, 0x11, - 0xf2, 0xb7, 0xe3, 0xc4, 0x9f, 0x37, 0x2d, 0x9f, 0xa1, 0xe2, 0xd6, 0x47, - 0x8c, 0xf0, 0xfb, 0x4a, 0xa0, 0xfd, 0x57, 0xd4, 0xc1, 0x67, 0x0f, 0xa8, - 0xb8, 0x65, 0xe7, 0x62, 0xa4, 0x42, 0x51, 0xec, 0x58, 0xa4, 0xe2, 0xe6, - 0x7d, 0x47, 0x88, 0xfb, 0x13, 0x36, 0x4f, 0xce, 0xa4, 0x1e, 0x46, 0xb0, - 0x57, 0xd6, 0xb8, 0xdd, 0x8c, 0xdf, 0xa5, 0x78, 0xa6, 0x9f, 0x39, 0xb4, - 0x59, 0x8a, 0x13, 0x43, 0x47, 0x68, 0x8f, 0xa5, 0x38, 0xde, 0x6f, 0x4c, - 0xfc, 0xd4, 0x51, 0x8a, 0xa7, 0x79, 0xbe, 0x93, 0xe7, 0x0b, 0x07, 0x8c, - 0xfe, 0x0e, 0xb5, 0x14, 0x0b, 0xf6, 0xd7, 0xa3, 0xbf, 0x4f, 0x6c, 0x53, - 0x43, 0xfb, 0x58, 0x5d, 0x4e, 0xf7, 0xa2, 0x73, 0x2f, 0x36, 0x52, 0x57, - 0xf7, 0xed, 0xec, 0x64, 0x7f, 0x3e, 0xea, 0xfc, 0x08, 0x1e, 0x63, 0x5e, - 0xb7, 0xbd, 0xcf, 0x87, 0x73, 0x49, 0xc3, 0xff, 0x45, 0xc5, 0x30, 0x8b, - 0x94, 0x80, 0xf6, 0x0c, 0x7c, 0x38, 0x9d, 0x2e, 0xc6, 0xa6, 0x81, 0x99, - 0xf8, 0x29, 0xed, 0xf3, 0xd1, 0xdd, 0xd2, 0xdf, 0x04, 0xe3, 0xc3, 0x2c, - 0x3c, 0x3d, 0x62, 0xb2, 0x6d, 0x99, 0x27, 0x89, 0x39, 0xdd, 0x70, 0x25, - 0xc5, 0x37, 0xa2, 0x3b, 0x69, 0x16, 0xc4, 0xc4, 0x63, 0x48, 0xf7, 0xeb, - 0x3d, 0xb7, 0xa9, 0xc2, 0xab, 0x55, 0xea, 0xd2, 0x81, 0x49, 0x4d, 0x8f, - 0x57, 0xa8, 0xf1, 0x7e, 0xe6, 0xaf, 0xf1, 0x4a, 0xf5, 0x18, 0x9e, 0xee, - 0x77, 0x62, 0xde, 0x42, 0x95, 0xd7, 0xe3, 0xe7, 0x19, 0xdb, 0xe2, 0xb3, - 0x55, 0x13, 0x7b, 0x6d, 0x59, 0x11, 0x2f, 0x20, 0xb7, 0x2f, 0x5f, 0x58, - 0xc3, 0xf8, 0xe5, 0x10, 0xdb, 0x8b, 0x95, 0xaa, 0x4e, 0xea, 0xfd, 0x34, - 0x46, 0x68, 0xd7, 0x4f, 0xf0, 0x38, 0x3c, 0x68, 0x75, 0x2e, 0x27, 0xe7, - 0x9e, 0x13, 0xb0, 0x3a, 0x6f, 0x33, 0x0d, 0x5f, 0x81, 0x1a, 0x88, 0x7e, - 0x05, 0xa7, 0x71, 0x68, 0x44, 0xca, 0xc0, 0xed, 0x8d, 0x30, 0xaf, 0xee, - 0xb3, 0x3a, 0x77, 0x9a, 0x73, 0x50, 0x6f, 0xe7, 0xc6, 0x3f, 0x2f, 0xcd, - 0x62, 0xa6, 0xf8, 0x91, 0xbd, 0xa7, 0x0a, 0xbf, 0x62, 0x3b, 0xef, 0x0f, - 0x96, 0xa3, 0xaa, 0x52, 0xfc, 0xe0, 0x14, 0xde, 0xe9, 0x7f, 0x0d, 0xe7, - 0xfa, 0x2d, 0x2c, 0x08, 0x59, 0x70, 0x86, 0x6a, 0xcd, 0x46, 0xf5, 0x1a, - 0x62, 0x84, 0x82, 0x9b, 0xe6, 0x7e, 0x1f, 0xef, 0xd2, 0xff, 0x6f, 0x9e, - 0x6b, 0xd9, 0xb2, 0xf4, 0x62, 0xa1, 0xb5, 0xa3, 0x5a, 0xfc, 0xc6, 0xb4, - 0xf7, 0xd3, 0xfc, 0xe9, 0x3c, 0x38, 0xbf, 0xaf, 0x4b, 0x72, 0xe1, 0xd3, - 0x18, 0x1e, 0x34, 0xa2, 0x6b, 0xf3, 0x72, 0xf6, 0x9f, 0xa6, 0x0e, 0x2c, - 0xec, 0x34, 0x4f, 0xec, 0xab, 0xc0, 0xbc, 0xf3, 0xcc, 0x1a, 0xaf, 0x9b, - 0x4d, 0xdb, 0x59, 0xb0, 0x30, 0x60, 0x2e, 0x53, 0xff, 0x37, 0xfd, 0xf4, - 0x34, 0x0e, 0x0e, 0xe5, 0xf1, 0xda, 0x87, 0x46, 0xfa, 0x79, 0x76, 0xcf, - 0xbb, 0x17, 0x0d, 0xc9, 0xa3, 0xf6, 0xfa, 0xc3, 0x61, 0xe2, 0x63, 0xf6, - 0x19, 0xa1, 0x86, 0x91, 0x74, 0x23, 0xb1, 0x21, 0x8a, 0xef, 0xa6, 0x23, - 0xc4, 0x87, 0x30, 0xf1, 0xa1, 0x9e, 0xf8, 0x60, 0x12, 0x1f, 0xea, 0x88, - 0x0f, 0x41, 0xfb, 0xd9, 0xb9, 0xac, 0x47, 0x0f, 0x8d, 0xbe, 0x86, 0x82, - 0x81, 0x53, 0x70, 0x0d, 0xc8, 0x3e, 0x35, 0x8b, 0xfc, 0xa4, 0x56, 0x6b, - 0xc3, 0x1c, 0x45, 0xf6, 0x0c, 0x0e, 0xa5, 0x4f, 0xa1, 0x68, 0x40, 0xe3, - 0x58, 0x64, 0xaf, 0x40, 0x4d, 0xb8, 0x87, 0x58, 0xfd, 0x6b, 0xa3, 0xb6, - 0xc7, 0x8b, 0xda, 0xbd, 0xd5, 0x30, 0xfa, 0x17, 0xaa, 0x73, 0x95, 0xe8, - 0xe7, 0xbc, 0x1c, 0x67, 0x25, 0x66, 0xed, 0xd6, 0x30, 0x9b, 0xc7, 0x3f, - 0x25, 0x6b, 0x26, 0xde, 0x74, 0xc0, 0x3b, 0x9d, 0x74, 0x67, 0x06, 0x99, - 0x00, 0x59, 0xad, 0xd7, 0x87, 0x2b, 0x0f, 0x9f, 0x56, 0x15, 0x64, 0x3e, - 0x27, 0x31, 0xaf, 0x36, 0xd8, 0xad, 0x32, 0x5b, 0xd7, 0x04, 0xc3, 0x79, - 0xa8, 0x88, 0x90, 0x45, 0xcc, 0x64, 0x7e, 0x61, 0xb5, 0x99, 0x45, 0xd8, - 0x52, 0xa7, 0xca, 0x7e, 0x8d, 0xa3, 0x12, 0xa3, 0xa6, 0x33, 0x46, 0x14, - 0xf7, 0xc5, 0xef, 0x99, 0x0e, 0x0f, 0x8a, 0xfa, 0x2c, 0xeb, 0x1b, 0x21, - 0x0d, 0x9e, 0x48, 0x20, 0xba, 0x81, 0x69, 0xe4, 0xe7, 0xe6, 0x85, 0x71, - 0x53, 0xfa, 0x30, 0x06, 0x38, 0xbe, 0xe5, 0xe9, 0xfc, 0xbb, 0x9c, 0x7f, - 0xfa, 0xef, 0xe2, 0x3b, 0xa1, 0x57, 0xee, 0x9d, 0x0e, 0x43, 0x7b, 0x40, - 0xed, 0x28, 0x27, 0x07, 0x3f, 0xcc, 0xb8, 0xa7, 0x4c, 0x7e, 0x5e, 0x41, - 0xcb, 0x40, 0x1c, 0x55, 0xa1, 0x53, 0x4a, 0x4c, 0xf6, 0x32, 0x29, 0x95, - 0xf8, 0xfc, 0x6e, 0xea, 0x7a, 0x41, 0x86, 0xb6, 0xe2, 0xc3, 0xb7, 0x46, - 0x45, 0xb7, 0x35, 0x43, 0x3b, 0x39, 0x8e, 0x37, 0xe6, 0x1e, 0x16, 0x9c, - 0x3c, 0x32, 0x0b, 0x8e, 0x23, 0xd3, 0x98, 0x9b, 0xd6, 0xcc, 0xbd, 0xf2, - 0xfc, 0xbf, 0xa8, 0xa2, 0x17, 0x85, 0xd8, 0xa1, 0xf7, 0xc7, 0xd8, 0xf6, - 0x07, 0x8e, 0xc3, 0xd8, 0x44, 0x0c, 0x3e, 0x9a, 0xfe, 0x0e, 0x75, 0x79, - 0x28, 0x97, 0x2f, 0xad, 0x42, 0xa2, 0x57, 0xf6, 0xe3, 0x9d, 0xc2, 0xac, - 0x01, 0xbd, 0x79, 0x9b, 0x62, 0x04, 0x6f, 0x56, 0x4e, 0x61, 0xc6, 0x40, - 0x90, 0x73, 0xa9, 0x61, 0x59, 0x5f, 0x1e, 0x3f, 0x05, 0x83, 0x57, 0x11, - 0x83, 0xad, 0xc5, 0x3f, 0x35, 0xe3, 0xcc, 0x71, 0x74, 0xd3, 0xa9, 0xe8, - 0x2d, 0x73, 0x15, 0xd9, 0x9b, 0x63, 0x9c, 0x6f, 0x65, 0x1d, 0xcf, 0x40, - 0x1d, 0xee, 0xe4, 0x98, 0x9b, 0x38, 0x6f, 0xaf, 0x2d, 0xb4, 0xb0, 0x68, - 0xa1, 0xbe, 0xb7, 0xc8, 0x11, 0x7d, 0xa0, 0x02, 0x99, 0x8e, 0x6a, 0xda, - 0xcd, 0x7d, 0x0b, 0xf4, 0xf0, 0xab, 0xc4, 0x5d, 0xe2, 0x34, 0x36, 0x31, - 0xee, 0xb4, 0x31, 0x16, 0x15, 0x47, 0xf4, 0x1e, 0xe6, 0xa8, 0xef, 0xdf, - 0xed, 0x88, 0x86, 0xe4, 0x7d, 0xa3, 0x7f, 0xc0, 0x62, 0xb8, 0x43, 0x65, - 0xc4, 0x41, 0x3d, 0xf3, 0x1a, 0xf4, 0xbd, 0x77, 0x92, 0x93, 0xfe, 0x84, - 0xfc, 0xae, 0xfa, 0xaa, 0xa3, 0xc4, 0xa8, 0x11, 0x3c, 0x9a, 0x3e, 0x82, - 0xbd, 0xe9, 0x14, 0x76, 0xa5, 0x77, 0x28, 0x43, 0xf6, 0xb3, 0x3a, 0x45, - 0xde, 0xad, 0x8b, 0x96, 0x29, 0x5f, 0x46, 0x69, 0xe8, 0x9b, 0xd6, 0x50, - 0x85, 0x8a, 0xf2, 0x50, 0x10, 0x37, 0xf5, 0xc5, 0xe1, 0x88, 0xbc, 0x67, - 0xc9, 0x7b, 0xd9, 0xeb, 0xc7, 0x0d, 0xdc, 0xd8, 0x57, 0x8c, 0xd8, 0x7e, - 0xcb, 0xea, 0xa9, 0x77, 0x62, 0xcd, 0x78, 0x1d, 0x96, 0x0d, 0x3c, 0x66, - 0xcd, 0x66, 0xcc, 0xf9, 0xf8, 0x5a, 0x0f, 0xee, 0xde, 0xef, 0x41, 0x6b, - 0x5f, 0x14, 0xbe, 0x48, 0x09, 0x7f, 0x07, 0xcc, 0x25, 0x30, 0x26, 0x26, - 0x60, 0xf4, 0xdc, 0xe0, 0x08, 0x1c, 0x0a, 0xab, 0x1e, 0x7c, 0x95, 0x38, - 0xbe, 0x9c, 0xb8, 0x13, 0x1b, 0xb7, 0x50, 0x1e, 0xf1, 0xe2, 0x1e, 0xd6, - 0xbf, 0x85, 0x73, 0xff, 0xee, 0xa2, 0x43, 0xc4, 0x02, 0xd9, 0x83, 0xa8, - 0x61, 0xc3, 0xb8, 0x9b, 0xba, 0x72, 0x23, 0x76, 0xb0, 0x12, 0x37, 0xee, - 0xf6, 0xe3, 0xee, 0x71, 0x0f, 0x1a, 0xfa, 0xac, 0xc5, 0x87, 0xcd, 0xf8, - 0x4a, 0x0d, 0x06, 0x5a, 0xc7, 0xbd, 0xf8, 0xdb, 0x3e, 0xdd, 0x77, 0x33, - 0x73, 0xfe, 0x11, 0x33, 0x88, 0xbf, 0x1f, 0xf7, 0xe1, 0xf6, 0xbe, 0x13, - 0x92, 0x47, 0x2e, 0x71, 0x32, 0xf6, 0x3c, 0x34, 0x3e, 0x13, 0x2b, 0xfb, - 0xf4, 0xf3, 0x13, 0xe4, 0x76, 0x9d, 0x07, 0x4d, 0x3c, 0x30, 0xae, 0xa2, - 0x85, 0xed, 0x7c, 0xbe, 0x6f, 0x16, 0x3a, 0x0e, 0xd6, 0x53, 0x86, 0x85, - 0x58, 0x3e, 0xe0, 0x84, 0x49, 0x16, 0x8f, 0x2f, 0x00, 0xcd, 0x03, 0x13, - 0xcc, 0xe3, 0x1e, 0xc6, 0x8e, 0x5e, 0x13, 0xf7, 0x8e, 0xcb, 0xf9, 0x11, - 0xfb, 0x5d, 0xd8, 0xf7, 0xf7, 0x2d, 0xc4, 0x67, 0x07, 0x54, 0xe2, 0x40, - 0x21, 0x86, 0x56, 0x2a, 0xf8, 0x5b, 0x5e, 0xdf, 0x96, 0x94, 0xbd, 0xcc, - 0x40, 0x68, 0x67, 0xe0, 0x50, 0x05, 0x39, 0xc3, 0xa2, 0x7d, 0xd9, 0xeb, - 0x8f, 0x12, 0xe7, 0x8b, 0x88, 0xf3, 0x25, 0xe4, 0xb0, 0x37, 0x0c, 0x1f, - 0xc1, 0x23, 0xc4, 0xe5, 0xa3, 0x03, 0x9d, 0x8c, 0x3b, 0xa5, 0x78, 0x92, - 0x71, 0xa0, 0x8f, 0xe7, 0xa7, 0x76, 0x1a, 0x1d, 0x45, 0xc4, 0xe9, 0x57, - 0x89, 0xbf, 0x3d, 0xc4, 0x8c, 0xfb, 0xfa, 0x18, 0xee, 0x77, 0x32, 0x07, - 0xb8, 0x2a, 0x3a, 0xdf, 0xc3, 0x1c, 0xeb, 0x66, 0x25, 0xe0, 0x7b, 0x0b, - 0xa5, 0x70, 0xec, 0xab, 0x44, 0xc3, 0x6e, 0x29, 0x23, 0xf8, 0xa5, 0x42, - 0x3d, 0xe0, 0xa4, 0xce, 0x8f, 0xc1, 0xea, 0x77, 0x70, 0xbc, 0x35, 0x26, - 0x19, 0x38, 0xde, 0x30, 0x75, 0xed, 0xbb, 0xc4, 0xda, 0x0f, 0x89, 0xa9, - 0xfe, 0xe9, 0xf5, 0x68, 0x34, 0x4c, 0x1e, 0xc7, 0x70, 0xba, 0xdf, 0x30, - 0x65, 0x9f, 0xdc, 0x9b, 0xe4, 0x79, 0x93, 0xd3, 0x19, 0x33, 0x0d, 0xf1, - 0xc3, 0x11, 0x8e, 0x47, 0x95, 0xbc, 0x04, 0x8e, 0x31, 0xe0, 0x9d, 0x7d, - 0x8b, 0x39, 0x2e, 0x89, 0xa5, 0x12, 0xef, 0x46, 0x28, 0xeb, 0x62, 0xac, - 0xa0, 0x3e, 0x1a, 0xfb, 0x54, 0xa4, 0x0e, 0x46, 0x70, 0xef, 0x9e, 0x6c, - 0x1c, 0x6e, 0x0f, 0xc5, 0x6f, 0x63, 0x1c, 0x0e, 0x17, 0x33, 0x0e, 0xbb, - 0x22, 0x22, 0x9b, 0x13, 0xc3, 0x8c, 0xdb, 0x5b, 0x92, 0x61, 0x34, 0x71, - 0x0e, 0x27, 0x52, 0xec, 0xb7, 0x6f, 0x26, 0x9e, 0x49, 0x79, 0x18, 0xb3, - 0x34, 0x1e, 0x44, 0xb5, 0x91, 0x69, 0x3c, 0xfc, 0x3c, 0xe6, 0xf0, 0x30, - 0xec, 0x6b, 0x6d, 0x7d, 0x0a, 0xe2, 0xcd, 0xd9, 0xe7, 0x65, 0xcf, 0xa4, - 0x04, 0x9b, 0x65, 0x2d, 0xf3, 0xde, 0x72, 0xd9, 0xfb, 0xd9, 0x9f, 0xfc, - 0x3e, 0xca, 0x89, 0x4f, 0x65, 0x39, 0x1c, 0xfa, 0x79, 0x48, 0x70, 0xb7, - 0x86, 0xb8, 0x2b, 0xfb, 0x73, 0x2c, 0x6b, 0x55, 0x60, 0x2a, 0x1e, 0xfd, - 0xef, 0x8f, 0xa3, 0xf6, 0x7e, 0x56, 0xc1, 0x24, 0xe2, 0x5f, 0x92, 0xf8, - 0xc7, 0x31, 0x74, 0x5d, 0x4f, 0x0c, 0xa4, 0x4c, 0xff, 0x98, 0x24, 0x06, - 0x12, 0xa7, 0x8f, 0x10, 0xa7, 0x9f, 0x22, 0x4e, 0x7f, 0x93, 0x38, 0xfd, - 0x24, 0x31, 0x21, 0xbb, 0xa6, 0xd7, 0x24, 0xcf, 0x2f, 0x38, 0x1f, 0xef, - 0xd9, 0x6b, 0x8b, 0xd5, 0xd4, 0xd5, 0xac, 0x01, 0x79, 0xe7, 0x47, 0x3f, - 0x24, 0x76, 0xff, 0x13, 0xce, 0x93, 0xbf, 0x2a, 0xbb, 0xef, 0xaa, 0xb1, - 0xaf, 0x1b, 0xee, 0xbe, 0x5a, 0xad, 0x07, 0xf6, 0xb7, 0x02, 0x4c, 0xe1, - 0xa2, 0x05, 0x7d, 0x6d, 0x70, 0xf4, 0xd5, 0x1e, 0x3a, 0x29, 0xcf, 0x43, - 0xa7, 0x49, 0x5e, 0xdf, 0x26, 0x7b, 0xbd, 0x0f, 0xc9, 0x7e, 0xad, 0x65, - 0xbc, 0xe7, 0xea, 0xab, 0x35, 0xdf, 0x82, 0x8d, 0x6d, 0xfe, 0x49, 0xfb, - 0x5e, 0xcd, 0xfb, 0x8f, 0x50, 0x5f, 0x19, 0xb6, 0x99, 0x4a, 0xca, 0x7e, - 0xd4, 0x99, 0x78, 0x22, 0x2d, 0xbf, 0x6b, 0x5b, 0x12, 0xea, 0xe3, 0x88, - 0x55, 0x0b, 0x1f, 0x0f, 0xe3, 0xd6, 0x3e, 0x0f, 0xed, 0x20, 0x8e, 0x32, - 0xfa, 0xd6, 0xfd, 0xe3, 0xf5, 0xf4, 0xb5, 0xc7, 0x2c, 0x2d, 0x12, 0x68, - 0x19, 0x27, 0xe7, 0x59, 0x3f, 0xbe, 0x18, 0x4b, 0x07, 0x2c, 0xcb, 0x73, - 0x8d, 0x11, 0xde, 0xa0, 0xf8, 0xe1, 0xa2, 0x0f, 0x3a, 0xe8, 0x57, 0x6b, - 0xf7, 0x07, 0xb4, 0xb7, 0x88, 0xa7, 0xeb, 0xea, 0x0f, 0xd3, 0x3e, 0x8c, - 0xf3, 0x4d, 0xc4, 0x52, 0x67, 0x24, 0xc0, 0x3c, 0xd1, 0x43, 0xdb, 0xf7, - 0xe2, 0x7c, 0x42, 0xfc, 0x4b, 0xef, 0xf8, 0x2e, 0x73, 0x93, 0x0e, 0xfa, - 0xc6, 0x07, 0x89, 0xeb, 0xe9, 0x4b, 0x61, 0x1e, 0x33, 0xe9, 0x0b, 0x6e, - 0xbc, 0x93, 0x30, 0xe8, 0x77, 0x1e, 0xbc, 0x9b, 0xa8, 0x63, 0x9f, 0x41, - 0x96, 0xf5, 0x63, 0xa3, 0xfd, 0xde, 0x75, 0x4d, 0xfc, 0x5b, 0x4a, 0x4d, - 0xff, 0x2c, 0xb5, 0x02, 0xd1, 0x4a, 0x0d, 0x7f, 0x37, 0xfe, 0x37, 0xf8, - 0x19, 0xe3, 0xf6, 0x9a, 0x3e, 0x70, 0x0e, 0x11, 0x22, 0x0f, 0x9c, 0x38, - 0x28, 0xcf, 0xe9, 0x50, 0x1b, 0x9d, 0xeb, 0xd0, 0x99, 0xdb, 0xea, 0x99, - 0x73, 0x0e, 0x27, 0xfb, 0x24, 0x2b, 0x66, 0xd9, 0x0f, 0xfa, 0x8b, 0xf1, - 0xc0, 0xfe, 0xc3, 0xf4, 0x91, 0x02, 0x2c, 0x78, 0xc4, 0x8d, 0xbf, 0x3b, - 0x38, 0x22, 0x6b, 0x4b, 0x82, 0x99, 0xfe, 0x21, 0x12, 0x85, 0x30, 0xb9, - 0xde, 0xfd, 0x7b, 0x46, 0x30, 0x90, 0xe3, 0x79, 0x1f, 0x84, 0xe2, 0x5f, - 0x51, 0x71, 0x98, 0x3c, 0x22, 0x10, 0xbf, 0x9a, 0x36, 0x26, 0xef, 0xb8, - 0x49, 0xec, 0x5f, 0x41, 0x1b, 0xeb, 0xe6, 0x7c, 0x7e, 0x83, 0xe3, 0xd8, - 0x41, 0x1b, 0x1b, 0x4d, 0xcc, 0xc4, 0x56, 0xda, 0x58, 0x9c, 0x36, 0x16, - 0xa7, 0x3d, 0xc5, 0x69, 0x63, 0xf2, 0x6e, 0x7e, 0x9c, 0x36, 0x16, 0xa7, - 0x8d, 0xc5, 0x53, 0x8b, 0xf1, 0x14, 0x99, 0xc6, 0xae, 0x91, 0x45, 0xc4, - 0x31, 0x79, 0xb6, 0xc6, 0x79, 0xb8, 0xed, 0x6f, 0xc8, 0xd9, 0x6f, 0xe0, - 0xa1, 0xe0, 0x4e, 0xfa, 0xe4, 0x63, 0x43, 0xc4, 0x3b, 0xda, 0xc1, 0xa2, - 0xb4, 0x70, 0xfc, 0x7a, 0xe6, 0xb1, 0xc7, 0xc8, 0xf3, 0x55, 0x3c, 0x6b, - 0x4a, 0x1e, 0x6c, 0xf2, 0x9c, 0xb1, 0x26, 0x29, 0x1c, 0xec, 0x18, 0x36, - 0xf4, 0x03, 0x37, 0x91, 0x17, 0x56, 0x92, 0x97, 0x8c, 0x2c, 0x00, 0x5e, - 0x1c, 0x12, 0x19, 0xc5, 0xc7, 0xb3, 0xfb, 0x4f, 0x8f, 0xf7, 0xd7, 0x44, - 0x1b, 0x65, 0x7d, 0x88, 0x9c, 0x64, 0xf1, 0xb0, 0x70, 0xbc, 0xc3, 0xe4, - 0x48, 0x7a, 0xf8, 0xdf, 0x21, 0x1c, 0xaf, 0x12, 0x65, 0x7b, 0xf4, 0xf0, - 0x3b, 0x30, 0xd6, 0xfd, 0x52, 0xb1, 0x16, 0xbf, 0x16, 0x0a, 0xc4, 0x9f, - 0x54, 0x54, 0x34, 0x93, 0xef, 0xdd, 0xbc, 0xd3, 0x89, 0x9e, 0xd0, 0x62, - 0x7c, 0x85, 0x9c, 0x6f, 0xf5, 0x35, 0x2a, 0x96, 0xec, 0xa3, 0x2d, 0x55, - 0x0a, 0xc7, 0xd2, 0xc3, 0xe7, 0x30, 0x61, 0xaf, 0x13, 0x8e, 0xa6, 0x8e, - 0x5b, 0x55, 0x86, 0x60, 0x11, 0xb1, 0xed, 0xea, 0x37, 0x2d, 0xb7, 0xac, - 0x35, 0x91, 0x03, 0x0e, 0xf7, 0x47, 0x5f, 0x70, 0x12, 0xf7, 0xd7, 0x93, - 0x07, 0x3e, 0x91, 0xe3, 0x81, 0x07, 0xfb, 0x0d, 0xed, 0x07, 0xc4, 0x8b, - 0xfd, 0x3c, 0xdf, 0xca, 0x73, 0xab, 0xdf, 0xe0, 0x7c, 0x04, 0x9a, 0x66, - 0x90, 0x1b, 0xbe, 0x43, 0x99, 0x7b, 0x29, 0x73, 0x82, 0xf6, 0x9f, 0xee, - 0xd5, 0x90, 0x1c, 0x33, 0x30, 0xde, 0xeb, 0x45, 0xdf, 0x58, 0x10, 0x4f, - 0xf6, 0xfa, 0xb0, 0x93, 0xfc, 0xf0, 0x70, 0xaf, 0xf8, 0xe2, 0x4c, 0xf4, - 0x8f, 0xcd, 0xc4, 0x37, 0x92, 0xb2, 0x3e, 0xf5, 0x2e, 0x56, 0x57, 0x88, - 0x7e, 0xc4, 0x2f, 0xc9, 0xaf, 0x93, 0x7a, 0x4f, 0x8c, 0x63, 0x8a, 0x79, - 0xf5, 0x43, 0x31, 0xe8, 0x43, 0x9c, 0xc1, 0x8f, 0x87, 0xbe, 0x20, 0x31, - 0x52, 0x7c, 0x52, 0xc3, 0x13, 0xe4, 0x3c, 0xa5, 0xc4, 0xd5, 0x92, 0x48, - 0x4d, 0xf4, 0x0b, 0x8a, 0x1e, 0x7b, 0x45, 0xb5, 0xac, 0x4a, 0x89, 0xe1, - 0x07, 0x35, 0xf2, 0x0f, 0x13, 0x37, 0xdb, 0x31, 0x5b, 0xc3, 0xf4, 0xdd, - 0x95, 0xa8, 0xda, 0xdd, 0x87, 0xff, 0x56, 0x19, 0xff, 0x60, 0x1a, 0x63, - 0xfd, 0x34, 0x62, 0xfb, 0xec, 0xbe, 0x93, 0xd3, 0x67, 0x91, 0x33, 0xbf, - 0xa1, 0xd6, 0x66, 0xbe, 0x0b, 0xfd, 0xd0, 0x69, 0x87, 0x3e, 0x71, 0x94, - 0xf1, 0xc1, 0x45, 0xfb, 0x9c, 0x31, 0xae, 0xd1, 0x7f, 0x6b, 0x8f, 0x56, - 0xc1, 0x88, 0x5f, 0xab, 0x3a, 0x2d, 0x54, 0x8a, 0x3c, 0xa1, 0xf2, 0x6c, - 0x6e, 0x14, 0x26, 0xf6, 0x4b, 0x6c, 0x70, 0x40, 0x23, 0x0e, 0xff, 0x3d, - 0x7d, 0xe6, 0x4e, 0x3b, 0x1e, 0x1d, 0xb6, 0x9f, 0x85, 0x76, 0x8e, 0xc7, - 0xe9, 0x27, 0x8b, 0xd1, 0xd1, 0xef, 0x41, 0xbb, 0x1d, 0x8b, 0x1e, 0xb3, - 0x2a, 0xe8, 0x33, 0x1d, 0xfb, 0x03, 0x4d, 0x37, 0xd2, 0x67, 0xae, 0xbb, - 0x46, 0xe2, 0xd8, 0x61, 0xf2, 0x5f, 0xc3, 0xbc, 0x8e, 0xf8, 0xb2, 0xb5, - 0xde, 0xe8, 0x78, 0x9e, 0x32, 0xdd, 0x4f, 0xfb, 0x7f, 0x97, 0x3c, 0xe7, - 0xdc, 0x9e, 0x43, 0xd4, 0x99, 0x66, 0xfb, 0xc3, 0xcf, 0x92, 0x3e, 0xdb, - 0x37, 0x62, 0xfc, 0x2d, 0x71, 0x2f, 0x46, 0x5f, 0xfa, 0x37, 0xc6, 0xec, - 0xe2, 0x50, 0xfc, 0xf6, 0x62, 0x04, 0x71, 0x1f, 0x65, 0xfd, 0x38, 0xa9, - 0xf7, 0x6f, 0x90, 0x77, 0x8f, 0x43, 0x26, 0x65, 0xf1, 0xe0, 0x83, 0xa4, - 0xd8, 0xd9, 0x89, 0xff, 0x59, 0x89, 0xf8, 0x26, 0xc6, 0xe0, 0xa0, 0xe6, - 0x90, 0xb5, 0xf0, 0x99, 0x58, 0x73, 0xf0, 0x1a, 0xca, 0x5c, 0x47, 0xff, - 0x03, 0xe6, 0x0c, 0x47, 0x70, 0xcf, 0x1e, 0xc9, 0x31, 0xd0, 0x20, 0xb9, - 0xda, 0xbc, 0x50, 0xc0, 0x3c, 0x43, 0xac, 0x58, 0x3b, 0x76, 0x98, 0x71, - 0x42, 0xd6, 0x96, 0x91, 0xf1, 0x19, 0x61, 0xbc, 0xda, 0x5b, 0x6f, 0xbf, - 0xd3, 0x70, 0xff, 0x58, 0x3d, 0x5e, 0xe9, 0x9d, 0x89, 0xfb, 0x98, 0xeb, - 0xc4, 0x98, 0xeb, 0xc4, 0xc6, 0xbc, 0x88, 0x1d, 0x98, 0xc6, 0x83, 0xb2, - 0x1d, 0x98, 0xc3, 0x83, 0xb2, 0x8d, 0xa9, 0xf8, 0x2a, 0xf3, 0x97, 0x0d, - 0xc4, 0xf3, 0x1e, 0xda, 0xe3, 0xff, 0xe0, 0xdc, 0x0f, 0xd0, 0xde, 0xab, - 0x89, 0xf7, 0x6f, 0xee, 0x02, 0xee, 0xb4, 0xf5, 0x73, 0x84, 0x7a, 0x54, - 0xf0, 0x15, 0xfa, 0x44, 0x15, 0x63, 0x52, 0x37, 0xe7, 0x7c, 0xe7, 0xa0, - 0x11, 0x0c, 0xab, 0x01, 0xed, 0x09, 0xce, 0x73, 0xd7, 0x88, 0x8a, 0x47, - 0xfb, 0x17, 0x63, 0x3e, 0x63, 0xca, 0xb6, 0xa1, 0x09, 0xbb, 0x7c, 0x37, - 0xfd, 0xe1, 0x6e, 0xfa, 0xc9, 0x7b, 0xf4, 0x93, 0xc9, 0x95, 0xf2, 0x3e, - 0xa9, 0x93, 0x39, 0xff, 0xc3, 0x58, 0x93, 0x90, 0x78, 0xa7, 0xf7, 0x0c, - 0xa9, 0xcc, 0xb5, 0x68, 0x9f, 0x5d, 0xcc, 0x51, 0x6e, 0xa7, 0x6d, 0x3e, - 0x3a, 0x24, 0x3e, 0x24, 0x39, 0x8b, 0x11, 0xde, 0x46, 0xdb, 0x7c, 0x7e, - 0x48, 0xfc, 0xa3, 0x14, 0xb7, 0xee, 0x94, 0xfd, 0xa6, 0xa5, 0xf8, 0xec, - 0xbe, 0xc3, 0x94, 0xef, 0x08, 0x76, 0xd1, 0x2e, 0x4b, 0x69, 0x97, 0xf7, - 0x51, 0xaf, 0x1e, 0xda, 0xe5, 0x06, 0xe2, 0x50, 0x09, 0xed, 0xf2, 0x5e, - 0xf2, 0x81, 0xca, 0x9c, 0x5d, 0xfe, 0xdd, 0xf8, 0xc2, 0x8a, 0x6c, 0x8c, - 0xf0, 0x42, 0xdd, 0x2d, 0xef, 0xf7, 0x59, 0xd6, 0xed, 0x66, 0xa6, 0x69, - 0x06, 0x74, 0xb6, 0x1d, 0xc1, 0xb2, 0xb4, 0x13, 0xe5, 0x7d, 0x11, 0x2c, - 0x4d, 0xd6, 0xb4, 0x9f, 0x55, 0x22, 0xc8, 0xcc, 0xc8, 0xf2, 0x40, 0x57, - 0x9f, 0x7c, 0xdf, 0x43, 0x23, 0x07, 0xe1, 0xf8, 0xaf, 0xcd, 0x7e, 0x53, - 0xe4, 0xf3, 0x7f, 0x01, 0x7f, 0x5c, 0x42, 0x99, 0x3a, 0xcd, 0x8f, 0xac, - 0xc9, 0xec, 0xf7, 0x07, 0x9c, 0xb7, 0xf1, 0x7c, 0x16, 0xdb, 0xa8, 0x1a, - 0x77, 0x3a, 0xbf, 0x98, 0xf4, 0x60, 0xfa, 0xb8, 0x89, 0xbf, 0xcd, 0xb6, - 0xe3, 0x2e, 0x88, 0x34, 0xe2, 0xb9, 0x84, 0x82, 0x69, 0xc6, 0xd3, 0xf8, - 0x91, 0xbd, 0x2e, 0x50, 0x89, 0xf2, 0xdd, 0xf6, 0x9a, 0x02, 0x0e, 0x24, - 0xf4, 0xf6, 0x34, 0xcf, 0xcb, 0x0e, 0x7a, 0x51, 0xbc, 0x5b, 0xc1, 0x2d, - 0x01, 0x2f, 0x4a, 0xf9, 0xdb, 0x43, 0xbe, 0xd9, 0x1d, 0x5a, 0x6e, 0x6d, - 0x59, 0x25, 0xf6, 0xed, 0x05, 0x0e, 0x96, 0x94, 0x0b, 0x0e, 0x1e, 0x30, - 0x65, 0xed, 0xd2, 0x40, 0x77, 0xa2, 0x12, 0x85, 0xbb, 0x6b, 0x9a, 0x1a, - 0x51, 0x63, 0xbe, 0xc3, 0xfa, 0x05, 0x07, 0x3f, 0x5b, 0x21, 0xeb, 0xf6, - 0x4f, 0x49, 0x8c, 0x1b, 0x92, 0x79, 0xcd, 0xc6, 0x50, 0xe7, 0xd8, 0x5b, - 0x9a, 0xe8, 0x65, 0x13, 0x39, 0x8a, 0xda, 0xf7, 0xa6, 0x5d, 0xc6, 0x17, - 0x39, 0x4a, 0x0c, 0x90, 0xf8, 0x72, 0x0a, 0xed, 0xfd, 0xa7, 0x68, 0xff, - 0xb2, 0x8e, 0xc1, 0xbc, 0x77, 0x81, 0x85, 0xe2, 0x85, 0x99, 0x60, 0x31, - 0xa2, 0x15, 0x15, 0xc4, 0x6f, 0xfa, 0x00, 0x5e, 0x30, 0xf5, 0x96, 0x87, - 0x1c, 0xd1, 0x87, 0x8a, 0xa0, 0xaf, 0x7b, 0x5b, 0xe9, 0xc1, 0xc6, 0xc0, - 0x08, 0xfa, 0xc8, 0x05, 0xf3, 0xf9, 0xf8, 0xba, 0x3d, 0x8c, 0x6f, 0x8e, - 0x8b, 0xf9, 0xb8, 0x16, 0x8a, 0xff, 0x8e, 0x3c, 0xc0, 0x3f, 0x9b, 0x18, - 0xed, 0xb0, 0x7d, 0x27, 0x90, 0xd9, 0x44, 0x7b, 0x0d, 0x8f, 0x87, 0xe9, - 0x23, 0x23, 0x82, 0x7d, 0xf2, 0x35, 0xa3, 0x17, 0x0a, 0x98, 0x3f, 0x16, - 0x33, 0x0f, 0x39, 0x9d, 0xb4, 0x3a, 0xdd, 0xb4, 0x6b, 0xe7, 0xa2, 0x99, - 0x50, 0xd3, 0x37, 0xe0, 0x9d, 0x5d, 0x33, 0x51, 0x48, 0x5f, 0xaa, 0x48, - 0xca, 0x0b, 0x55, 0xea, 0xa7, 0xd9, 0x6f, 0xec, 0x3d, 0x04, 0xda, 0x03, - 0x8e, 0xda, 0x75, 0x49, 0x45, 0x27, 0xf6, 0xeb, 0x2d, 0xa5, 0xea, 0x4c, - 0x78, 0x98, 0xaf, 0x94, 0xa4, 0x3d, 0x00, 0xb9, 0x32, 0x58, 0xef, 0xa7, - 0xbb, 0x5c, 0x28, 0x37, 0x8c, 0xe8, 0x33, 0xcc, 0x81, 0x1c, 0xa3, 0x4e, - 0xfc, 0xcc, 0x96, 0x6b, 0x1a, 0x8a, 0x47, 0x6f, 0xc0, 0xe9, 0x5d, 0x7e, - 0xa8, 0xbc, 0x76, 0x76, 0xcf, 0x1c, 0x14, 0x8c, 0x12, 0x08, 0xd2, 0x8b, - 0xf1, 0xd6, 0x2e, 0x15, 0xae, 0xd1, 0xbf, 0xc1, 0x87, 0xbb, 0x14, 0xcc, - 0x9f, 0xa7, 0xa0, 0x68, 0x78, 0x84, 0x3a, 0x11, 0xee, 0x45, 0x3f, 0x4d, - 0xc1, 0xe6, 0x5d, 0x5b, 0x92, 0xc2, 0xed, 0xc9, 0xe9, 0x06, 0x2b, 0x61, - 0xee, 0x7e, 0xd3, 0xaa, 0x30, 0x8c, 0xd8, 0x2d, 0xaa, 0xb5, 0xb8, 0x72, - 0x41, 0xa0, 0x65, 0x80, 0x38, 0xfd, 0x12, 0x7d, 0xe0, 0x64, 0x7f, 0xdc, - 0xf2, 0x18, 0x8b, 0x89, 0xb5, 0x51, 0x34, 0x30, 0x37, 0x97, 0xbc, 0x7b, - 0x9b, 0x9d, 0xef, 0xca, 0x7e, 0x63, 0x27, 0xfc, 0x63, 0x0f, 0xe3, 0x78, - 0xc2, 0x8d, 0xc5, 0x63, 0xa5, 0xb8, 0x8e, 0x39, 0x75, 0x98, 0xdc, 0x21, - 0xbc, 0x2f, 0xcb, 0xf1, 0x9e, 0x27, 0xc7, 0xfb, 0x15, 0xb2, 0x1c, 0x6f, - 0x80, 0xb9, 0x5a, 0x95, 0x51, 0x8a, 0x5b, 0x06, 0x0c, 0xc6, 0x80, 0x52, - 0x34, 0xdb, 0xeb, 0x01, 0x1a, 0x6e, 0xa3, 0xff, 0x7e, 0x9e, 0xf9, 0xf8, - 0xcd, 0x3b, 0x03, 0xbe, 0x1d, 0x8a, 0x8f, 0x71, 0x40, 0xda, 0x3f, 0x4c, - 0xdc, 0xf0, 0x61, 0x4e, 0xaf, 0x11, 0x5c, 0x8a, 0xc0, 0xf9, 0x43, 0xd4, - 0xe5, 0xe2, 0xb1, 0x1b, 0x10, 0xa6, 0xee, 0xc2, 0xfb, 0x0e, 0xe7, 0xc6, - 0x31, 0x41, 0xd9, 0x9d, 0x78, 0x6f, 0x70, 0x16, 0x5e, 0x3d, 0x90, 0xcd, - 0xc3, 0x03, 0x7d, 0x13, 0xb2, 0x5e, 0xfc, 0x35, 0x86, 0xd7, 0x7b, 0x24, - 0x0f, 0xff, 0x41, 0xbf, 0xde, 0x5f, 0x2a, 0xeb, 0x84, 0xf4, 0xe7, 0xaf, - 0x2e, 0x70, 0x30, 0xbe, 0xe8, 0xfe, 0xef, 0x3b, 0xe2, 0xf2, 0x1c, 0xd9, - 0xff, 0x08, 0xef, 0x7f, 0x9f, 0xf1, 0xfc, 0x36, 0x5e, 0x8f, 0x55, 0x32, - 0xd7, 0x5e, 0x18, 0x3f, 0xef, 0xe2, 0xf5, 0xc7, 0x38, 0x97, 0x65, 0x46, - 0x4d, 0xec, 0x15, 0xe5, 0x08, 0x71, 0xc3, 0x81, 0x1d, 0x21, 0x3d, 0xba, - 0xc3, 0xce, 0xa1, 0x9d, 0x98, 0x48, 0x5f, 0x9d, 0xf3, 0xc1, 0x4a, 0x94, - 0xec, 0x96, 0xfc, 0xc5, 0x90, 0xf5, 0x9f, 0xfe, 0x12, 0xe6, 0x4f, 0x95, - 0x17, 0xec, 0x33, 0xbf, 0xff, 0x09, 0xee, 0x8a, 0x48, 0x33, 0x42, 0x7d, - 0xf9, 0x7d, 0x50, 0x87, 0xd0, 0x9d, 0x7e, 0x10, 0xed, 0xbb, 0xf4, 0x76, - 0x59, 0x1f, 0x7a, 0x25, 0x14, 0xb7, 0xca, 0x8d, 0x4e, 0xb8, 0x16, 0x18, - 0xcd, 0xcc, 0x5d, 0x62, 0xdf, 0x56, 0x8a, 0x19, 0x3b, 0x8e, 0x61, 0xf3, - 0xb0, 0x1e, 0xdc, 0xa1, 0x18, 0xcc, 0xf7, 0x34, 0x1c, 0x1a, 0x2c, 0xc0, - 0xdd, 0x7b, 0x5a, 0x19, 0xdb, 0x4c, 0xe2, 0x66, 0x8d, 0xff, 0x1c, 0xde, - 0xc7, 0x49, 0x53, 0xde, 0x11, 0x2a, 0x42, 0xab, 0x26, 0x7b, 0x80, 0x98, - 0x79, 0x4e, 0xbb, 0xe4, 0x3d, 0x71, 0x4f, 0x91, 0x91, 0x7f, 0xdf, 0xdf, - 0x60, 0xae, 0x38, 0x89, 0xfd, 0x83, 0xb2, 0x2e, 0x50, 0xa5, 0x1c, 0xef, - 0x9f, 0xeb, 0xeb, 0x22, 0xe6, 0x3f, 0x64, 0x66, 0x70, 0x7e, 0x61, 0x25, - 0x30, 0x5d, 0x41, 0xe8, 0xd3, 0x01, 0xf9, 0x9e, 0x0d, 0xff, 0xde, 0xb3, - 0xfc, 0x5f, 0x90, 0x76, 0x4a, 0xcb, 0xb2, 0x6b, 0x05, 0x3f, 0xaa, 0x94, - 0xf7, 0x01, 0x8f, 0x27, 0x2b, 0xca, 0xb3, 0xcf, 0x9c, 0xff, 0x54, 0x1f, - 0x6f, 0x58, 0x7e, 0xbb, 0x8d, 0x7c, 0xdd, 0xd7, 0xad, 0xa8, 0x57, 0xca, - 0x17, 0xb0, 0x6d, 0xf1, 0xcb, 0x2a, 0x65, 0x1d, 0x71, 0x54, 0x0d, 0x55, - 0x29, 0xad, 0x43, 0x97, 0xb7, 0xfb, 0x9a, 0x15, 0x6d, 0x96, 0xf3, 0x7c, - 0x39, 0x8b, 0xf7, 0xa5, 0x6c, 0xfe, 0xfe, 0x0b, 0xb9, 0xb6, 0x0a, 0xc9, - 0x53, 0xb3, 0x65, 0xee, 0xee, 0x97, 0xfd, 0x4b, 0x51, 0x9c, 0xa8, 0x9f, - 0xda, 0x5e, 0xbe, 0xef, 0xef, 0x5c, 0xd2, 0x5e, 0xb6, 0x6c, 0x55, 0x15, - 0x8a, 0xa5, 0x7c, 0x06, 0xff, 0x8f, 0xbd, 0x86, 0x70, 0xc6, 0xde, 0x73, - 0xb8, 0xcd, 0x6c, 0x88, 0x16, 0xe1, 0x33, 0x50, 0xaf, 0x8a, 0xcf, 0x2f, - 0xb2, 0xb9, 0x6d, 0xb4, 0xb9, 0x88, 0xf9, 0xad, 0xdb, 0x88, 0x3e, 0xe4, - 0x46, 0x26, 0xe3, 0x86, 0xde, 0x72, 0x5e, 0x39, 0xa4, 0xdc, 0x1d, 0xd0, - 0xdb, 0xdf, 0x23, 0xd7, 0x78, 0x39, 0x10, 0xb7, 0x4a, 0x0d, 0xc3, 0xd7, - 0xab, 0xe8, 0xe6, 0x1a, 0xc6, 0xb2, 0x17, 0x99, 0x3f, 0xb6, 0x05, 0x7a, - 0xec, 0xe7, 0x8b, 0x4a, 0x64, 0x05, 0xae, 0xb4, 0xbf, 0xdd, 0xd2, 0x0c, - 0x23, 0xf5, 0xb2, 0xac, 0x77, 0xf1, 0x77, 0x0c, 0xf3, 0xed, 0x6b, 0x6d, - 0x08, 0xda, 0xff, 0x57, 0xe5, 0xbe, 0xef, 0xd2, 0x82, 0x1a, 0xfb, 0xff, - 0x1d, 0x98, 0x9b, 0xba, 0xb0, 0x2e, 0x8c, 0x4d, 0xa6, 0x65, 0x3d, 0x67, - 0x5a, 0x38, 0x73, 0x71, 0xbf, 0xf3, 0x0a, 0x07, 0xf3, 0x0d, 0x52, 0xac, - 0x58, 0xf6, 0xfb, 0x54, 0x17, 0xdf, 0x97, 0x58, 0x7a, 0xc9, 0x7e, 0x67, - 0xf9, 0xae, 0x42, 0xa5, 0xfd, 0xfd, 0xb1, 0x79, 0x8b, 0x9c, 0x78, 0x29, - 0x51, 0x16, 0xf3, 0xf0, 0xf7, 0xe6, 0x45, 0x05, 0x58, 0x4f, 0x4e, 0xd6, - 0x74, 0xd5, 0x33, 0x38, 0x67, 0x7f, 0xc7, 0x21, 0x1e, 0x92, 0xef, 0x37, - 0x9c, 0x48, 0xd0, 0xa7, 0x07, 0xbb, 0x43, 0xfb, 0xed, 0xbe, 0x5f, 0xc7, - 0xa6, 0x51, 0x79, 0xe6, 0xd7, 0x8c, 0xd5, 0x89, 0x49, 0xc6, 0x37, 0x69, - 0x4b, 0xf2, 0x6e, 0x3d, 0xd3, 0xc6, 0x5c, 0x55, 0x75, 0x04, 0x71, 0x3b, - 0xe3, 0xca, 0x2b, 0x09, 0xda, 0xe9, 0x42, 0xbd, 0xe3, 0xdb, 0xe4, 0x06, - 0x65, 0x11, 0x3d, 0xf8, 0xae, 0xd2, 0x82, 0x31, 0xd6, 0x9f, 0x48, 0x88, - 0x2d, 0x56, 0xc6, 0x0a, 0x39, 0x96, 0x43, 0xe4, 0xa3, 0x2f, 0x27, 0x34, - 0x9c, 0xab, 0xf7, 0x20, 0x45, 0x7e, 0xfa, 0x52, 0x42, 0xb8, 0x9a, 0x17, - 0x4f, 0x0c, 0xca, 0xfa, 0x60, 0x23, 0x1a, 0x12, 0xb2, 0x36, 0xec, 0xc5, - 0xe3, 0x23, 0x5e, 0xda, 0xa3, 0x65, 0x6d, 0xa2, 0xed, 0xb6, 0x6a, 0x13, - 0xec, 0x53, 0xd6, 0x14, 0xa3, 0xb8, 0xa9, 0xb7, 0x12, 0x4f, 0x8c, 0xf8, - 0xf0, 0x3d, 0xf2, 0xf1, 0x3e, 0xd6, 0x7b, 0x25, 0xe1, 0x47, 0x6f, 0xca, - 0x87, 0xe7, 0xc9, 0xcb, 0xb7, 0xf2, 0x5c, 0xbe, 0x05, 0x56, 0x60, 0x04, - 0x91, 0x48, 0x1d, 0x63, 0x6c, 0xbc, 0x02, 0x6b, 0x57, 0x1e, 0x81, 0xda, - 0x7b, 0x94, 0xc7, 0xf5, 0x8c, 0xd5, 0xd7, 0x23, 0x39, 0x18, 0x41, 0x72, - 0xe4, 0x87, 0xe8, 0x19, 0x94, 0x71, 0xc9, 0x37, 0xa1, 0x64, 0x6f, 0x91, - 0x81, 0xf9, 0x8c, 0xa7, 0x43, 0x23, 0xd2, 0x4f, 0x25, 0xfb, 0xfe, 0x4b, - 0xdb, 0xff, 0x99, 0xb5, 0xf6, 0xf3, 0xd2, 0xf6, 0x91, 0x3f, 0xd1, 0xbe, - 0xe8, 0x2a, 0xff, 0x6e, 0x9f, 0xac, 0x73, 0xb8, 0xd9, 0xa6, 0x07, 0x8e, - 0x48, 0x66, 0x65, 0x29, 0xf4, 0xe8, 0x76, 0xc5, 0x68, 0x2a, 0x51, 0x26, - 0xb1, 0x3d, 0x2d, 0xef, 0x71, 0x15, 0xe2, 0x79, 0x72, 0x02, 0x57, 0x48, - 0xd7, 0xbe, 0x4d, 0xdb, 0x59, 0x42, 0x8c, 0x39, 0x63, 0x7e, 0x1a, 0x71, - 0x4d, 0xf4, 0x57, 0x88, 0x57, 0xfb, 0xdd, 0x78, 0x37, 0xc4, 0x98, 0x6d, - 0xef, 0xa1, 0xf6, 0xe0, 0x27, 0x09, 0x2f, 0xe7, 0xab, 0x36, 0x63, 0x38, - 0xe6, 0x02, 0x55, 0xd9, 0x6b, 0x27, 0x12, 0x6d, 0xd8, 0x4f, 0x79, 0x5f, - 0x49, 0x9c, 0xe7, 0xfc, 0xac, 0xa3, 0xfe, 0x45, 0xdf, 0xf1, 0x9c, 0xae, - 0xbb, 0xa9, 0xeb, 0x99, 0x78, 0x31, 0xf1, 0x30, 0x9e, 0xa0, 0xfc, 0x8f, - 0xf7, 0x1b, 0xd1, 0x39, 0xca, 0x31, 0x1c, 0x1a, 0x2a, 0x24, 0x7e, 0xbb, - 0x71, 0x37, 0xb3, 0xe4, 0x49, 0xe9, 0x2b, 0x29, 0x6b, 0x93, 0x0a, 0xb9, - 0xc7, 0x31, 0x8c, 0xf3, 0xde, 0x4f, 0xf8, 0x3b, 0xbc, 0xb0, 0x9c, 0x7d, - 0x88, 0x7e, 0xfc, 0x76, 0x1e, 0xd0, 0x45, 0x7e, 0xb3, 0xbc, 0xfe, 0x98, - 0xcd, 0x79, 0xba, 0x93, 0xad, 0xe8, 0xe9, 0x7f, 0x9f, 0x7c, 0x8e, 0x38, - 0xe4, 0xad, 0xa7, 0xad, 0x67, 0xb0, 0x3d, 0xf5, 0xef, 0x55, 0x59, 0xee, - 0xf9, 0x6a, 0x95, 0xec, 0xeb, 0x3d, 0x91, 0x28, 0xc4, 0x4b, 0xac, 0xb3, - 0x36, 0xe4, 0xca, 0x3d, 0x2f, 0x39, 0x86, 0x5e, 0xe2, 0x6a, 0x8a, 0x7d, - 0x24, 0xec, 0x36, 0xaa, 0x94, 0xbd, 0xf4, 0xc3, 0xf2, 0x85, 0x55, 0x4a, - 0x92, 0xe7, 0x7d, 0xc9, 0x1f, 0xe2, 0xd9, 0x47, 0xb2, 0x3a, 0xdc, 0x6f, - 0xb6, 0x61, 0x28, 0x75, 0x2a, 0xd7, 0xde, 0x8f, 0xa7, 0xbc, 0x9b, 0x26, - 0xef, 0xba, 0xe4, 0xdf, 0x7b, 0xc9, 0x3e, 0xcf, 0x7a, 0x2a, 0x5d, 0x46, - 0xde, 0x5c, 0x4c, 0x5b, 0x2b, 0x88, 0x79, 0x19, 0x4f, 0xdb, 0x16, 0x68, - 0xd8, 0x75, 0xcd, 0x9c, 0x2a, 0x94, 0x69, 0xee, 0x5f, 0xd7, 0xbf, 0xcc, - 0x7e, 0xca, 0x62, 0x15, 0x91, 0x8c, 0xbd, 0x07, 0x2a, 0x74, 0x4d, 0x35, - 0x73, 0x68, 0x79, 0x2e, 0x1c, 0xc3, 0xdb, 0x89, 0xca, 0x58, 0x65, 0xa4, - 0x9c, 0x78, 0x7b, 0x0e, 0xbd, 0xc3, 0xc4, 0x76, 0xf2, 0xe5, 0xd2, 0xbe, - 0x4a, 0xb8, 0xed, 0x35, 0xbc, 0x2b, 0x30, 0x63, 0xf7, 0x2c, 0xf8, 0x76, - 0xcf, 0x24, 0x5f, 0x61, 0x6e, 0x19, 0xb2, 0xac, 0x9f, 0x2f, 0xb4, 0xac, - 0x2b, 0x79, 0x14, 0xf1, 0x38, 0x1b, 0x12, 0x3f, 0x8d, 0xa2, 0xd6, 0xf6, - 0x57, 0x03, 0x75, 0xf6, 0xff, 0x46, 0xfa, 0x7a, 0x47, 0x68, 0xfe, 0xf8, - 0xc3, 0xa1, 0xb9, 0xe3, 0xd5, 0x50, 0x07, 0xa6, 0xc1, 0xc1, 0xb6, 0x3e, - 0x77, 0x8d, 0x85, 0x46, 0xfa, 0xf0, 0x1a, 0x53, 0xf8, 0x50, 0x1b, 0xf9, - 0x50, 0x4f, 0xc8, 0x18, 0x3f, 0x82, 0x1b, 0xc9, 0x97, 0xdd, 0x03, 0x3e, - 0xf6, 0x23, 0xf9, 0xb5, 0x33, 0x33, 0x9b, 0x3c, 0xfb, 0xd3, 0x0b, 0x85, - 0x1b, 0xb5, 0x90, 0x1b, 0x1d, 0x45, 0xcb, 0xf8, 0x31, 0xdc, 0xca, 0x32, - 0x1e, 0xe6, 0xfd, 0x7d, 0xe9, 0x1f, 0x92, 0x77, 0x58, 0x8c, 0x39, 0x19, - 0xdc, 0xcc, 0xb6, 0x8b, 0x07, 0x9a, 0x70, 0xf7, 0xf8, 0x0a, 0xac, 0x1d, - 0xb7, 0xb0, 0x3c, 0x34, 0x81, 0xe5, 0xe3, 0xe4, 0x9a, 0xe3, 0x79, 0x7f, - 0x15, 0x9e, 0xb4, 0x82, 0x3c, 0x49, 0xe2, 0xd0, 0x2a, 0x7b, 0x1d, 0x4d, - 0xa5, 0x1f, 0x36, 0x24, 0xe4, 0x9d, 0x9b, 0x38, 0x56, 0x8f, 0x0b, 0x56, - 0x3f, 0x88, 0x4d, 0xe3, 0xb2, 0x2e, 0xfb, 0xf5, 0xd0, 0x9c, 0xf1, 0xd7, - 0xd1, 0x30, 0x3e, 0x14, 0x9a, 0x37, 0x3e, 0x42, 0xb9, 0x13, 0x94, 0xad, - 0x3f, 0x54, 0x33, 0x3e, 0x18, 0x0a, 0x8e, 0xef, 0x0d, 0x05, 0xc6, 0x9b, - 0xb1, 0x75, 0x7c, 0x15, 0xb6, 0x8c, 0xb7, 0x63, 0xf3, 0xb8, 0xe0, 0xfc, - 0x24, 0x96, 0x8d, 0x9f, 0xc1, 0xd2, 0xf1, 0x97, 0xd1, 0x38, 0x7e, 0x0a, - 0x4b, 0xc6, 0x7f, 0x88, 0xa6, 0xf1, 0x1f, 0x73, 0x2c, 0xb2, 0xce, 0x2b, - 0x6b, 0xbc, 0xf9, 0x67, 0x6a, 0xf9, 0xf7, 0x44, 0xf3, 0xdf, 0xd7, 0x70, - 0x21, 0xaa, 0xbd, 0x81, 0xee, 0x3d, 0xf2, 0xbd, 0xc1, 0x5a, 0x6d, 0x93, - 0xfd, 0xbe, 0xc1, 0xcb, 0xb2, 0x4f, 0x1d, 0x45, 0xc6, 0xe5, 0xef, 0xc5, - 0xcb, 0x77, 0x31, 0xe4, 0x39, 0xe7, 0x24, 0xba, 0xd2, 0xe7, 0xad, 0xa8, - 0x26, 0x65, 0xde, 0xc0, 0xe6, 0x3d, 0xf2, 0x3e, 0x71, 0x06, 0x5d, 0x49, - 0x79, 0x0e, 0x2f, 0xef, 0xa0, 0xbf, 0x81, 0x2d, 0xa3, 0xb6, 0xaf, 0xa1, - 0x71, 0x48, 0xde, 0x89, 0x69, 0xc3, 0x75, 0xc9, 0x8c, 0xbd, 0x56, 0x5e, - 0x66, 0xe0, 0xef, 0x67, 0xe0, 0x41, 0xe6, 0x04, 0x05, 0xe4, 0xfd, 0xc5, - 0xe8, 0x7c, 0x24, 0x6e, 0x15, 0x1a, 0x1e, 0xcc, 0x88, 0x18, 0x99, 0x77, - 0x1d, 0xc5, 0xe8, 0xe0, 0xb5, 0xfb, 0x76, 0xc2, 0xef, 0x33, 0x44, 0xf7, - 0x81, 0xd8, 0x28, 0x63, 0xec, 0x86, 0x7d, 0x19, 0xf2, 0x8b, 0x0e, 0xf8, - 0xf9, 0x7f, 0x7b, 0x52, 0xf6, 0x21, 0x6d, 0x42, 0x74, 0x9f, 0xe8, 0xb0, - 0x99, 0x3a, 0x9c, 0x64, 0xdc, 0x90, 0x67, 0x38, 0x46, 0x70, 0x2b, 0x64, - 0x9d, 0x52, 0xc5, 0xf7, 0x06, 0xe5, 0x79, 0x83, 0xde, 0xf1, 0x25, 0xfa, - 0xf4, 0x87, 0xca, 0x0f, 0x51, 0x76, 0x40, 0xf8, 0xd2, 0x04, 0x7a, 0x84, - 0x6f, 0x47, 0x14, 0x23, 0x15, 0x38, 0x0b, 0xcf, 0x01, 0xc1, 0x5d, 0x27, - 0x4a, 0xc6, 0xe4, 0xfb, 0x38, 0x40, 0x31, 0xf3, 0x12, 0x1c, 0x20, 0xa7, - 0x3d, 0x70, 0x0a, 0xd8, 0x27, 0xeb, 0x56, 0xaf, 0x61, 0x72, 0x48, 0xe6, - 0xad, 0x8d, 0xf3, 0x26, 0x7e, 0xf8, 0x7d, 0x0c, 0x0f, 0x79, 0xe8, 0xe3, - 0x13, 0x1c, 0xc7, 0xeb, 0x78, 0x74, 0x8f, 0x3c, 0x17, 0x99, 0x89, 0x36, - 0xd6, 0x3b, 0xc1, 0x3c, 0xbf, 0x75, 0xcc, 0xe4, 0x78, 0x56, 0xa1, 0xf3, - 0xc0, 0x17, 0x78, 0x4c, 0xc3, 0x43, 0x07, 0xd6, 0x71, 0x8c, 0x71, 0x74, - 0x8c, 0x75, 0xf3, 0x68, 0xc5, 0xc6, 0x9d, 0x26, 0xb9, 0xa0, 0xd8, 0xb4, - 0x46, 0x3f, 0x6b, 0xe5, 0x98, 0xa4, 0x8f, 0xd5, 0xf8, 0x19, 0x31, 0xa6, - 0x29, 0xb4, 0x1a, 0xe7, 0x6c, 0xbf, 0x5b, 0x8d, 0x2d, 0xfd, 0x46, 0xf0, - 0x24, 0x56, 0x63, 0x33, 0xcf, 0x1f, 0xa5, 0xef, 0xcf, 0x21, 0x17, 0xbc, - 0x93, 0xbe, 0xbd, 0x78, 0x78, 0x42, 0xbe, 0x9d, 0x80, 0xbe, 0x5d, 0x32, - 0x1f, 0x6d, 0xf0, 0x8d, 0x65, 0x50, 0x3e, 0xc6, 0xec, 0x79, 0x27, 0xee, - 0x2a, 0x43, 0x39, 0xbe, 0x11, 0x92, 0x3d, 0x0b, 0x3f, 0x40, 0xf1, 0x3e, - 0x91, 0xf5, 0x87, 0x6c, 0xfb, 0x1c, 0x73, 0xf1, 0x53, 0x9c, 0x83, 0xfc, - 0xb3, 0xf1, 0x5f, 0xe0, 0x60, 0x6a, 0x92, 0xb8, 0x7a, 0x9a, 0xc7, 0xe5, - 0xcf, 0xa5, 0xbd, 0x76, 0x8e, 0x92, 0xdd, 0xff, 0xed, 0xc4, 0x8c, 0x3e, - 0x59, 0xdf, 0x6d, 0x86, 0x2f, 0x29, 0x7c, 0x27, 0xb3, 0x8d, 0xf9, 0x4a, - 0x7b, 0xd8, 0xe6, 0x3f, 0x46, 0x8c, 0xbc, 0xa7, 0xf9, 0xdb, 0x8a, 0x87, - 0xbc, 0x27, 0x88, 0x15, 0x69, 0x3d, 0x7a, 0x33, 0xf5, 0x5b, 0xf4, 0xc8, - 0x8f, 0xe0, 0x7c, 0xc4, 0x89, 0x42, 0xe6, 0x37, 0xa1, 0x90, 0xe8, 0x59, - 0xde, 0x95, 0xcd, 0xe8, 0x85, 0xc4, 0xcc, 0x82, 0xbe, 0x0c, 0xe7, 0x27, - 0x33, 0xbf, 0x00, 0x7e, 0xce, 0xcd, 0x0d, 0x68, 0xeb, 0x8f, 0x72, 0x6e, - 0x3e, 0x45, 0x1b, 0x9b, 0xa0, 0xbd, 0x48, 0x4e, 0xf4, 0x32, 0x65, 0x74, - 0xe5, 0xbe, 0xc9, 0x93, 0xd1, 0x9d, 0xd0, 0x4d, 0xbf, 0x5a, 0x95, 0x7d, - 0x27, 0x05, 0xf6, 0xb3, 0xe7, 0x30, 0xf0, 0x06, 0x6d, 0x33, 0xcf, 0x67, - 0x2c, 0xab, 0x9d, 0xf6, 0xd5, 0x3f, 0x2a, 0xbe, 0xb2, 0xb4, 0x2a, 0xfb, - 0xbe, 0xee, 0x54, 0xae, 0x93, 0xaf, 0xeb, 0x20, 0x36, 0xe6, 0xef, 0xff, - 0x08, 0x77, 0x32, 0x7e, 0x9d, 0x59, 0x78, 0x2a, 0x67, 0xf3, 0xd3, 0xab, - 0xb3, 0xf8, 0xf5, 0x49, 0xdf, 0x0b, 0xfa, 0x2b, 0xfb, 0xdb, 0x3b, 0xd9, - 0x6f, 0x1f, 0x01, 0xcf, 0x26, 0x0a, 0xe4, 0x29, 0xc1, 0x62, 0x17, 0x54, - 0xaf, 0x0b, 0x85, 0x8c, 0x01, 0xd5, 0xd8, 0xe4, 0xb5, 0x70, 0xa3, 0x59, - 0x80, 0x43, 0x75, 0xb7, 0x00, 0x15, 0xf1, 0x16, 0x97, 0xfd, 0x4e, 0xde, - 0xef, 0xbf, 0xf4, 0x87, 0xef, 0xe4, 0x9d, 0xb1, 0xf3, 0xe1, 0x52, 0xe3, - 0x76, 0xbc, 0x62, 0xc7, 0x09, 0x05, 0x25, 0x73, 0x65, 0x5d, 0xd2, 0x8f, - 0x17, 0x8d, 0x5a, 0x7f, 0x85, 0x3c, 0x6f, 0x52, 0xce, 0x5a, 0x71, 0xaf, - 0xbc, 0x87, 0xf7, 0xc7, 0xf6, 0x8f, 0x3f, 0x87, 0xad, 0xbb, 0xc2, 0x90, - 0xf7, 0x3b, 0x9c, 0x46, 0xa1, 0x37, 0x2b, 0xbf, 0xc8, 0x26, 0xeb, 0x44, - 0xb7, 0x71, 0x1c, 0x67, 0xe8, 0x8b, 0x67, 0xec, 0x75, 0x2a, 0xb7, 0xf1, - 0xd7, 0x08, 0x56, 0xe4, 0xc7, 0x2f, 0x39, 0x8d, 0x92, 0xd5, 0x41, 0xf6, - 0xfd, 0xda, 0x6a, 0xc1, 0xfe, 0x2d, 0xc9, 0x33, 0xf6, 0x9a, 0xac, 0xcb, - 0xf8, 0x0f, 0xeb, 0x2d, 0x6f, 0x25, 0xcb, 0x3e, 0x95, 0xbb, 0x3f, 0x29, - 0xeb, 0x38, 0xa6, 0x7c, 0xbb, 0xca, 0x69, 0xd7, 0x11, 0xbd, 0x5f, 0xac, - 0xb3, 0x89, 0xbc, 0x7a, 0xb6, 0x71, 0xca, 0xea, 0xf4, 0xca, 0x18, 0xd6, - 0x5c, 0x56, 0x47, 0xd6, 0x08, 0x34, 0xe9, 0x37, 0x2c, 0x63, 0xee, 0x4a, - 0xff, 0x61, 0x9f, 0xb2, 0x7e, 0x5b, 0x60, 0x94, 0xe0, 0x6c, 0x45, 0x76, - 0x4d, 0xe5, 0xa2, 0x8c, 0xed, 0xd5, 0xb2, 0xef, 0xae, 0xd0, 0x3e, 0xb7, - 0xfb, 0x35, 0x2f, 0xd6, 0x7b, 0x30, 0x37, 0xde, 0x4a, 0xfb, 0x9d, 0x9a, - 0x47, 0x6d, 0xae, 0xe3, 0x98, 0x32, 0xee, 0xdf, 0x78, 0x2f, 0xed, 0xe7, - 0xf3, 0xb9, 0x7e, 0x45, 0x1e, 0xef, 0x94, 0x3e, 0x44, 0xae, 0xde, 0x5c, - 0x1d, 0x3d, 0x1c, 0xb5, 0xfb, 0x57, 0x11, 0xde, 0x93, 0xef, 0xd3, 0xb2, - 0x0a, 0x16, 0xe6, 0xdb, 0xc8, 0xd0, 0x0f, 0xad, 0xce, 0x42, 0xc6, 0xab, - 0xb3, 0xf5, 0x0f, 0x62, 0x73, 0x42, 0xf4, 0x2c, 0xdf, 0x70, 0x25, 0x2e, - 0xdb, 0xfc, 0xcb, 0xc5, 0x5c, 0xf6, 0x1a, 0x0c, 0x69, 0x71, 0xec, 0xaf, - 0x93, 0x77, 0xc8, 0x5c, 0xf4, 0x85, 0x38, 0x71, 0xb0, 0x90, 0x38, 0x1a, - 0xb7, 0xf7, 0x94, 0x1c, 0x34, 0xf5, 0xe8, 0xb3, 0xf2, 0x8d, 0xb2, 0xab, - 0xec, 0xb5, 0xa7, 0xa6, 0x21, 0xc8, 0xf5, 0xfc, 0x7a, 0x52, 0xfe, 0xaf, - 0x88, 0xb6, 0x23, 0x72, 0x89, 0x0d, 0x50, 0xba, 0x84, 0xbc, 0xeb, 0x54, - 0x1b, 0x23, 0x67, 0xc4, 0x2b, 0x29, 0xd9, 0x7f, 0xf0, 0x5b, 0x2b, 0x5e, - 0x2d, 0xfb, 0x1c, 0xa7, 0xd6, 0x29, 0x20, 0x97, 0x0b, 0x84, 0xcb, 0x94, - 0xfc, 0xfb, 0x4e, 0x17, 0xff, 0x6e, 0xa5, 0xcd, 0x9c, 0xb3, 0xdf, 0x51, - 0x93, 0xb3, 0x08, 0x1a, 0x92, 0xf2, 0xad, 0x52, 0x7d, 0x62, 0x39, 0x6a, - 0x33, 0x35, 0x0e, 0x67, 0x8e, 0x93, 0x84, 0xb1, 0x82, 0x76, 0xb3, 0x25, - 0x10, 0xb6, 0xdf, 0xc5, 0x5a, 0x96, 0xac, 0x09, 0x3e, 0xce, 0x1c, 0xfa, - 0x1d, 0x96, 0xbf, 0x25, 0xfd, 0x3d, 0x6b, 0xc8, 0x2b, 0x63, 0xca, 0x63, - 0xc3, 0x29, 0xfa, 0x06, 0xf5, 0x18, 0x11, 0xff, 0xf0, 0xa0, 0x22, 0x12, - 0xa6, 0xff, 0x4a, 0x4c, 0x97, 0xf7, 0xb8, 0xf4, 0xbd, 0x71, 0x98, 0xc4, - 0xfc, 0x1e, 0xda, 0x91, 0xec, 0x5b, 0xd6, 0xfd, 0x2b, 0x19, 0x5b, 0x8e, - 0x5f, 0x78, 0xc6, 0x2f, 0x1c, 0xe0, 0xd9, 0xea, 0xdc, 0xde, 0x66, 0xf7, - 0x6c, 0xc6, 0x3c, 0xcb, 0x7e, 0x6e, 0xdf, 0x66, 0x63, 0x8a, 0x66, 0xe8, - 0x87, 0x7e, 0xe5, 0xe8, 0xc4, 0xd3, 0x0b, 0x8c, 0x8e, 0xc3, 0x6a, 0x66, - 0xc8, 0x47, 0x7c, 0xb9, 0xde, 0x11, 0xdd, 0xc9, 0xff, 0xfe, 0xd7, 0xec, - 0x6f, 0xab, 0x48, 0x5d, 0x3d, 0xb8, 0x4a, 0x95, 0xfd, 0x40, 0xcd, 0x18, - 0xeb, 0x95, 0x77, 0x06, 0xf4, 0x96, 0xa7, 0x94, 0x4e, 0x6c, 0x08, 0x19, - 0xcd, 0xed, 0x8a, 0xde, 0xf4, 0x0f, 0x8a, 0xee, 0x0f, 0x29, 0x52, 0x2e, - 0xc8, 0xbc, 0xeb, 0x62, 0x3c, 0x75, 0xb1, 0x8f, 0x03, 0x09, 0x3d, 0x5c, - 0xc5, 0xb2, 0x67, 0x4d, 0xc3, 0xf7, 0x3e, 0xdb, 0xfc, 0x57, 0x1e, 0x3b, - 0xed, 0xf7, 0xc4, 0xa5, 0x7c, 0x74, 0xbe, 0xcb, 0xfe, 0xbe, 0x69, 0x0b, - 0xe3, 0xae, 0x7c, 0x23, 0x38, 0x06, 0xad, 0x6f, 0x26, 0x4d, 0x4c, 0xef, - 0xb9, 0x0d, 0xb2, 0xe7, 0xa0, 0x89, 0x09, 0xba, 0x07, 0xde, 0x48, 0x27, + 0x9d, 0xbc, 0x0d, 0x78, 0x1b, 0xe5, 0x95, 0x36, 0x7c, 0xcf, 0x48, 0xb2, + 0x65, 0x5b, 0xb6, 0xc7, 0x8e, 0x9c, 0x28, 0x6c, 0x9a, 0x68, 0xf0, 0x28, + 0x51, 0xb0, 0x69, 0x47, 0x89, 0x03, 0x82, 0x55, 0x89, 0xea, 0x98, 0xc4, + 0x81, 0x50, 0x9c, 0x12, 0x5a, 0xb3, 0x4b, 0x5b, 0xe1, 0xfc, 0x60, 0x42, + 0xa0, 0xa1, 0xb0, 0xef, 0x9a, 0xef, 0x65, 0x5f, 0xab, 0xb6, 0x93, 0x38, + 0x89, 0x2c, 0x39, 0x8e, 0x21, 0x61, 0xbf, 0x5e, 0x8b, 0x89, 0x9d, 0x38, + 0x80, 0x6c, 0x85, 0x36, 0xdd, 0x0d, 0x7d, 0xd3, 0x8d, 0x36, 0x09, 0x60, + 0xfe, 0xda, 0x40, 0xbb, 0x2c, 0xed, 0xcb, 0x07, 0xde, 0x14, 0x42, 0xd8, + 0xb6, 0x40, 0xb7, 0x3f, 0x1b, 0x5a, 0xca, 0xbc, 0xf7, 0x19, 0x49, 0x89, + 0x13, 0x28, 0xed, 0x7e, 0xbe, 0xae, 0xb9, 0xac, 0x99, 0x79, 0x7e, 0xce, + 0x73, 0x9e, 0x73, 0xee, 0x73, 0x9f, 0x67, 0x9e, 0x19, 0x3f, 0x50, 0x8a, + 0xfc, 0x5f, 0x39, 0x8f, 0x4f, 0x37, 0x6c, 0x5c, 0xbd, 0x60, 0xc1, 0xa7, + 0x1b, 0xe4, 0xdc, 0x39, 0xdd, 0xe9, 0xc4, 0x9f, 0xf9, 0xe7, 0xff, 0x73, + 0x0b, 0x7e, 0xcc, 0x9f, 0x03, 0xd0, 0x0a, 0xfd, 0xcb, 0x01, 0xb7, 0x1a, + 0x71, 0xde, 0xdc, 0x68, 0xc0, 0xed, 0x88, 0x4c, 0xb4, 0xad, 0x36, 0x80, + 0x68, 0xba, 0xce, 0xbf, 0x04, 0x7f, 0xb0, 0xe2, 0x5e, 0x27, 0xe4, 0xfa, + 0xa7, 0x22, 0x1f, 0x74, 0x7e, 0xef, 0x72, 0xfd, 0xbd, 0x21, 0x07, 0xdc, + 0x5a, 0x24, 0x0e, 0x6d, 0x2e, 0xdc, 0xb3, 0x58, 0xe7, 0x9b, 0xf3, 0xbe, + 0xa9, 0xa0, 0xa2, 0xd0, 0xd6, 0x69, 0xeb, 0x7b, 0xf3, 0x7c, 0xb1, 0x92, + 0x88, 0x86, 0x23, 0x19, 0xb4, 0xd4, 0xf7, 0x75, 0x5a, 0xe5, 0x46, 0x08, + 0x6e, 0xc3, 0x68, 0xed, 0x53, 0x3c, 0xe1, 0xf5, 0x8b, 0xe0, 0x29, 0x36, + 0x10, 0xbf, 0x28, 0x82, 0x96, 0x4b, 0xc6, 0x4a, 0xe3, 0xce, 0x88, 0x1b, + 0xcd, 0x19, 0x77, 0xfc, 0x2f, 0x22, 0x06, 0x96, 0x65, 0x66, 0x95, 0xa2, + 0xc2, 0x8d, 0x9e, 0xcc, 0xeb, 0x25, 0xb9, 0xf6, 0xea, 0xf3, 0xff, 0x83, + 0xd3, 0x72, 0xff, 0xa7, 0xc7, 0x9c, 0x11, 0x60, 0x53, 0xc2, 0xb2, 0x8a, + 0x22, 0x37, 0xdc, 0xa0, 0x46, 0x0c, 0xdf, 0x3e, 0x2c, 0x46, 0x9b, 0x86, + 0xfb, 0x36, 0x37, 0xfc, 0xa7, 0x72, 0x74, 0x90, 0x0d, 0x8f, 0x3a, 0x10, + 0xd5, 0x8e, 0xf3, 0xff, 0xec, 0xd9, 0xad, 0x61, 0x03, 0xbb, 0x47, 0xcf, + 0xf0, 0xba, 0xd3, 0xbe, 0xd6, 0xbd, 0x6b, 0xf6, 0xec, 0x9b, 0xc2, 0xc7, + 0xf1, 0xe0, 0xa8, 0xfc, 0xbe, 0x15, 0x9d, 0xf5, 0x0a, 0x26, 0x6f, 0x58, + 0x07, 0x87, 0x61, 0xa0, 0x67, 0x97, 0xe2, 0xec, 0xaa, 0x57, 0x11, 0xf5, + 0xea, 0xc1, 0x18, 0x27, 0xc1, 0x69, 0x20, 0x56, 0x1c, 0x09, 0x3b, 0xdf, + 0x4e, 0x44, 0x34, 0x87, 0x61, 0x59, 0xc1, 0xd0, 0x0c, 0x38, 0xaa, 0x2c, + 0xeb, 0x09, 0xd3, 0x03, 0xff, 0x97, 0x9e, 0x42, 0x7c, 0xb8, 0x05, 0xaa, + 0xf1, 0x14, 0xba, 0x86, 0x9f, 0xc2, 0x43, 0x3b, 0x4b, 0x31, 0x39, 0x8d, + 0xe3, 0x4d, 0xf9, 0xf0, 0xbd, 0x79, 0xd2, 0xb7, 0xc8, 0x51, 0xcf, 0xc3, + 0x8d, 0x49, 0xc7, 0x6b, 0xfc, 0x2f, 0x65, 0xce, 0x58, 0x93, 0x33, 0xce, + 0x95, 0xd9, 0xc4, 0x32, 0x3d, 0x17, 0x94, 0x89, 0x0f, 0x47, 0xf0, 0x5c, + 0x42, 0xc1, 0xfa, 0x50, 0x05, 0xa2, 0x55, 0x32, 0x5e, 0xcb, 0x1a, 0x35, + 0x4f, 0x59, 0x93, 0x9a, 0xf4, 0x35, 0x81, 0xe7, 0x79, 0x6f, 0x73, 0xe8, + 0x0d, 0x2b, 0xeb, 0x95, 0xf6, 0xbe, 0x4e, 0x1b, 0x5a, 0xc9, 0xeb, 0x4e, + 0xa4, 0x12, 0x88, 0x55, 0x44, 0x6e, 0xe4, 0xb9, 0x6e, 0xbe, 0xa3, 0xb8, + 0xdd, 0xef, 0x26, 0xdc, 0x5f, 0x2a, 0x37, 0xd4, 0x7b, 0x2a, 0xe1, 0xc4, + 0x0b, 0x94, 0xf9, 0x90, 0xb9, 0x0e, 0x2e, 0xe3, 0x6e, 0xb1, 0x39, 0x8e, + 0xeb, 0x47, 0x16, 0x66, 0x14, 0xea, 0x4b, 0xbb, 0x6e, 0x6c, 0x4e, 0x59, + 0xd6, 0x56, 0x33, 0x7a, 0x45, 0x09, 0x0d, 0xe2, 0x58, 0xa2, 0x05, 0xee, + 0x48, 0xc0, 0x7f, 0x1a, 0x61, 0x2c, 0xc9, 0x78, 0xf1, 0x64, 0x02, 0xce, + 0xc6, 0x79, 0x5e, 0x74, 0x65, 0x22, 0xb8, 0x3a, 0x63, 0xa2, 0x29, 0xf3, + 0xa7, 0x2d, 0xeb, 0xda, 0x94, 0x9f, 0x63, 0xf8, 0x83, 0x95, 0x1b, 0x83, + 0x8c, 0x2f, 0xf7, 0xbf, 0x27, 0x75, 0x11, 0xb6, 0x71, 0x8e, 0xb6, 0x70, + 0xfe, 0x96, 0x87, 0xb2, 0xd1, 0x12, 0xe8, 0xe6, 0x69, 0x44, 0xb0, 0x34, + 0x63, 0x70, 0x4e, 0x23, 0x58, 0x92, 0xaa, 0xd5, 0x86, 0x31, 0x1f, 0x51, + 0x5f, 0xce, 0xb6, 0xb7, 0x73, 0xbc, 0x6d, 0x81, 0x16, 0x94, 0xd3, 0x46, + 0xd2, 0x8b, 0xc2, 0x68, 0x64, 0xff, 0x2b, 0xfe, 0x8c, 0xfe, 0xaf, 0x67, + 0xff, 0xef, 0xb0, 0xff, 0xac, 0xdd, 0x3f, 0x9c, 0xd7, 0xf0, 0xdc, 0x4d, + 0x7b, 0xdc, 0x96, 0x76, 0x3a, 0x97, 0xa7, 0xbc, 0xd8, 0x9a, 0x36, 0x69, + 0x73, 0x72, 0xcb, 0x87, 0xcd, 0x83, 0xb3, 0xb0, 0x65, 0x50, 0xf7, 0x3d, + 0xcd, 0xdf, 0xdd, 0x23, 0x17, 0x61, 0xd3, 0xa0, 0x82, 0x3d, 0xc6, 0x45, + 0xe8, 0xe2, 0xef, 0xdd, 0x83, 0xb3, 0xf1, 0xe0, 0xa0, 0x03, 0xe1, 0x69, + 0xe7, 0x8f, 0x63, 0xd2, 0x71, 0x11, 0xe2, 0x23, 0x7e, 0x74, 0x25, 0x9e, + 0xb7, 0x75, 0x58, 0x1e, 0xf9, 0x5e, 0xc1, 0x9f, 0xe9, 0x3b, 0x7e, 0xac, + 0x4e, 0x68, 0xe8, 0x4a, 0x89, 0x1f, 0xb8, 0x69, 0x9b, 0xe2, 0x07, 0xbf, + 0x06, 0x2a, 0x34, 0x74, 0x67, 0x0a, 0xf7, 0x15, 0x38, 0x39, 0x6f, 0x6b, + 0x34, 0x37, 0xb6, 0xa6, 0xc4, 0x26, 0xa4, 0x4d, 0xb1, 0x0b, 0xf9, 0x5d, + 0x4d, 0xbb, 0x2b, 0x85, 0x7f, 0x6f, 0x29, 0x82, 0xf7, 0x6b, 0x78, 0xb3, + 0x41, 0xae, 0xd3, 0xde, 0x43, 0x52, 0xa6, 0x1f, 0xfb, 0xd2, 0xe2, 0xa7, + 0x7e, 0x34, 0x26, 0x26, 0xd8, 0x7e, 0x03, 0xdb, 0x36, 0xf1, 0xcf, 0x99, + 0x7a, 0xfc, 0x53, 0x26, 0x88, 0x7f, 0xa4, 0x1e, 0xbf, 0x93, 0xf1, 0xe3, + 0x60, 0x66, 0x16, 0xbe, 0x9d, 0xf1, 0xe1, 0x5b, 0x9c, 0xbf, 0xc7, 0x33, + 0x2d, 0xb4, 0x7d, 0x0d, 0x07, 0x32, 0xa2, 0xff, 0x22, 0x8e, 0xb7, 0x14, + 0xdd, 0x83, 0xb5, 0xc1, 0x63, 0xb4, 0xad, 0x7f, 0x34, 0xaf, 0x41, 0xb6, + 0xba, 0xc1, 0xb6, 0xc9, 0xad, 0xbc, 0xbe, 0x6d, 0xb0, 0x36, 0x7a, 0x89, + 0x62, 0x59, 0x6a, 0xa8, 0x2e, 0x7c, 0x54, 0x55, 0x31, 0xe9, 0xd5, 0xfd, + 0x59, 0x55, 0xf7, 0x47, 0xe1, 0x42, 0x82, 0xbe, 0x11, 0xaf, 0xd1, 0x87, + 0xe2, 0xb4, 0x29, 0xaf, 0x31, 0xcc, 0xf1, 0xe8, 0xfe, 0xb8, 0xea, 0xc6, + 0x96, 0x94, 0xbe, 0x3b, 0xae, 0x7a, 0x10, 0xcf, 0x94, 0xe2, 0x17, 0x83, + 0x7a, 0x6f, 0x5c, 0xfd, 0x3c, 0xe2, 0xd5, 0x96, 0xf5, 0xad, 0x10, 0x36, + 0xce, 0x88, 0x20, 0x5a, 0x13, 0x41, 0x6c, 0x76, 0xc4, 0x8b, 0x54, 0x0a, + 0x78, 0xa7, 0xcf, 0xf0, 0xfd, 0x9b, 0xd2, 0x82, 0xbf, 0x69, 0xd1, 0xfd, + 0x7e, 0xb5, 0x2e, 0x3e, 0xac, 0x2e, 0xa2, 0x4b, 0xc3, 0xef, 0x8b, 0x2c, + 0x43, 0x87, 0x7d, 0x4d, 0x81, 0x66, 0x78, 0xd0, 0x9d, 0xba, 0x02, 0x31, + 0x6f, 0x6d, 0xeb, 0x0e, 0xb5, 0xf6, 0x8c, 0xa9, 0xea, 0x13, 0x2d, 0xaa, + 0x65, 0xfd, 0x72, 0xe1, 0x3b, 0x96, 0x7f, 0xba, 0x65, 0x2d, 0x58, 0x28, + 0x7d, 0xfa, 0x51, 0x15, 0x31, 0xb1, 0xd2, 0x9e, 0xc3, 0x52, 0x9c, 0x1a, + 0xac, 0x66, 0x1f, 0x1a, 0xfe, 0xf5, 0x72, 0x3d, 0xb8, 0x4e, 0x2d, 0xc5, + 0x9b, 0x23, 0xa5, 0x38, 0xc9, 0xf1, 0xfc, 0xe7, 0xa0, 0x0f, 0xbf, 0x1e, + 0xb4, 0xac, 0x2f, 0x99, 0x7f, 0x89, 0x81, 0xea, 0x7e, 0xfc, 0xd3, 0xb8, + 0x17, 0xbf, 0xe0, 0xdc, 0xbc, 0x91, 0x88, 0xde, 0x35, 0x0d, 0x7a, 0x74, + 0x5c, 0x39, 0xf6, 0xd5, 0x0a, 0xd4, 0xb5, 0x54, 0x28, 0x7a, 0xf3, 0x76, + 0xe8, 0xbe, 0x4b, 0x14, 0x2f, 0x4e, 0xa7, 0x35, 0xfc, 0x34, 0x5d, 0x1b, + 0xfe, 0x21, 0xfb, 0xfc, 0xad, 0xf9, 0x84, 0x95, 0x9d, 0x2e, 0x7a, 0x13, + 0x1d, 0x51, 0xcf, 0x29, 0xea, 0x39, 0x45, 0x3d, 0xa7, 0xa8, 0x67, 0xca, + 0x70, 0x30, 0x45, 0x3d, 0x53, 0x77, 0xdf, 0xa2, 0x4d, 0x3d, 0xce, 0x79, + 0x3c, 0x60, 0xcf, 0x63, 0x98, 0xf3, 0xf5, 0x17, 0xf8, 0x5f, 0x36, 0xb6, + 0x3e, 0x6f, 0xfd, 0xad, 0x57, 0xc6, 0xd4, 0x3d, 0x3d, 0x87, 0x5f, 0x32, + 0xb6, 0xe7, 0xac, 0x98, 0x26, 0xe3, 0x92, 0xf1, 0xd9, 0xfa, 0xf3, 0x6f, + 0x54, 0xb6, 0x28, 0x28, 0xb5, 0xac, 0x9d, 0x66, 0xfe, 0xbe, 0xb7, 0x30, + 0xbe, 0x1b, 0x94, 0x9c, 0x5d, 0xed, 0x74, 0x53, 0xdf, 0xc1, 0xa8, 0xba, + 0x8c, 0xe7, 0x7a, 0x3c, 0x8a, 0xb9, 0xc5, 0xe7, 0x9f, 0x5f, 0x5b, 0x23, + 0xf3, 0xe1, 0x3f, 0x7b, 0x4e, 0x7b, 0xb4, 0xfb, 0xbb, 0x8d, 0xe7, 0x32, + 0x16, 0xb1, 0x45, 0xb1, 0x01, 0x2f, 0xed, 0xe5, 0xf2, 0xfc, 0x3d, 0xc4, + 0xd5, 0xc8, 0x46, 0xb4, 0x34, 0x3c, 0x6a, 0xf7, 0x51, 0x94, 0x14, 0xbf, + 0x51, 0xf0, 0xce, 0x15, 0x0a, 0x8e, 0x86, 0x0c, 0xda, 0xcc, 0x10, 0x71, + 0x01, 0x28, 0x4e, 0xc2, 0xed, 0x89, 0x44, 0x90, 0xe8, 0x83, 0xbb, 0x24, + 0x12, 0xc6, 0xfc, 0xbe, 0xda, 0xf6, 0x53, 0xd0, 0x83, 0x7d, 0x8a, 0xde, + 0x02, 0xd4, 0x99, 0x63, 0xd4, 0xe3, 0x25, 0x8a, 0xee, 0x2f, 0x52, 0xe0, + 0x56, 0x58, 0x2e, 0x90, 0x1e, 0xc2, 0x96, 0x8c, 0xfc, 0x0e, 0xc3, 0x48, + 0xff, 0xb6, 0xd0, 0x17, 0xed, 0x7e, 0x23, 0xed, 0xfe, 0x14, 0xc7, 0xae, + 0xfb, 0x89, 0xaf, 0x6e, 0x57, 0xa4, 0x1d, 0x7b, 0x13, 0x70, 0x17, 0x45, + 0x36, 0xe0, 0xa9, 0x44, 0xf5, 0xf4, 0x42, 0x39, 0x85, 0xe5, 0xfc, 0xe9, + 0xa9, 0xb2, 0xbc, 0x66, 0x45, 0xbd, 0x39, 0x59, 0x4a, 0x93, 0x43, 0xd8, + 0x9e, 0x92, 0xba, 0x11, 0xbb, 0xae, 0x93, 0x7d, 0xf4, 0x24, 0x6a, 0x9b, + 0xaf, 0x55, 0xf4, 0xf0, 0x23, 0xa8, 0x8b, 0xbe, 0xcd, 0x39, 0xec, 0x82, + 0x7e, 0xa6, 0x1d, 0x39, 0x59, 0xe6, 0xa5, 0x73, 0x72, 0x2c, 0x4e, 0x43, + 0xb9, 0x29, 0x05, 0x8f, 0xcf, 0x98, 0x96, 0xf7, 0x65, 0x28, 0xd7, 0x71, + 0xfe, 0x54, 0xc3, 0x8f, 0xeb, 0x68, 0x43, 0x1b, 0x76, 0x5a, 0xe8, 0x0e, + 0x55, 0xd3, 0x57, 0x5b, 0x50, 0x41, 0xbf, 0xbc, 0x53, 0x43, 0xb4, 0x32, + 0x12, 0x56, 0xae, 0xcf, 0x0c, 0xe7, 0xf5, 0x7f, 0xb4, 0x9a, 0xf2, 0x29, + 0x4d, 0xa9, 0x0b, 0xaf, 0x57, 0xe6, 0xe3, 0xde, 0x85, 0xd7, 0x3d, 0x45, + 0x1f, 0x5f, 0xbe, 0x4e, 0x1b, 0x81, 0xc2, 0x78, 0x53, 0x42, 0xfd, 0xea, + 0x26, 0xab, 0x05, 0x5d, 0xf6, 0x35, 0x07, 0x86, 0x9c, 0x51, 0x9f, 0x03, + 0x1f, 0x58, 0xd1, 0x55, 0x72, 0xad, 0x14, 0xb1, 0x96, 0x3a, 0x9f, 0x13, + 0x75, 0xe1, 0x4d, 0xf4, 0xb7, 0xc9, 0x55, 0x8d, 0xbc, 0x17, 0x30, 0x8f, + 0xa1, 0xd6, 0xbf, 0x09, 0xf2, 0xfb, 0x7d, 0xda, 0x48, 0xa3, 0xd4, 0x65, + 0x19, 0xb1, 0x39, 0x5d, 0x3b, 0x06, 0x2f, 0x36, 0xd1, 0xfe, 0x8a, 0x23, + 0xba, 0xb9, 0xcc, 0xe1, 0xc4, 0x7e, 0xe2, 0xb8, 0xc3, 0xe8, 0x45, 0x31, + 0xc7, 0xc8, 0xf8, 0x8a, 0x47, 0x12, 0xc0, 0xb3, 0xfd, 0x16, 0x1a, 0x43, + 0x1e, 0x2c, 0xb1, 0x6d, 0xf3, 0x90, 0x72, 0x75, 0xea, 0x43, 0x6b, 0xc8, + 0x59, 0x12, 0x55, 0x23, 0x01, 0xdf, 0x49, 0xb2, 0x81, 0xa2, 0x48, 0x9d, + 0xe6, 0x44, 0x5c, 0x69, 0xce, 0xf4, 0x28, 0xcb, 0x33, 0xbd, 0xca, 0x92, + 0x8c, 0xb4, 0x7d, 0x48, 0x59, 0x9a, 0xf1, 0x20, 0xdd, 0xaf, 0x60, 0x7b, + 0x88, 0x72, 0xd5, 0xe4, 0xec, 0x38, 0xd3, 0xaf, 0x12, 0x63, 0xdf, 0x21, + 0xc6, 0xea, 0x61, 0xb0, 0xef, 0x27, 0x12, 0xd5, 0x38, 0x44, 0x2c, 0xfd, + 0x71, 0x5a, 0x57, 0x51, 0x7a, 0x11, 0x5e, 0x19, 0xa9, 0xc0, 0xd8, 0xa0, + 0xc9, 0xdf, 0xf5, 0x78, 0x61, 0xc4, 0xb2, 0x7a, 0x4c, 0xcb, 0xda, 0x6b, + 0x1e, 0x52, 0x1a, 0xd9, 0x67, 0xd4, 0x19, 0x8f, 0x16, 0x47, 0x02, 0xe6, + 0x16, 0xf6, 0xe9, 0x88, 0xc4, 0x95, 0x28, 0xfb, 0xbb, 0x9a, 0xfd, 0x2d, + 0xcd, 0xf7, 0x97, 0xeb, 0x57, 0x64, 0x91, 0x7a, 0x85, 0x3a, 0x61, 0xd6, + 0x01, 0xf6, 0x25, 0x02, 0xc1, 0x42, 0xbd, 0xa5, 0xac, 0x73, 0xf5, 0xd9, + 0x3a, 0xc0, 0x70, 0x22, 0xc8, 0x39, 0x15, 0x5b, 0xf7, 0x33, 0x76, 0x7d, + 0x83, 0x18, 0xdb, 0x80, 0xb6, 0x61, 0xc1, 0xdf, 0x6b, 0xd4, 0xdc, 0x3c, + 0xe5, 0xb0, 0x56, 0x62, 0x5e, 0x0e, 0x6f, 0x83, 0xe8, 0xa3, 0x5f, 0x77, + 0xa5, 0xc4, 0xc6, 0xef, 0xf9, 0x72, 0x22, 0xa0, 0xe0, 0xb1, 0x40, 0xb6, + 0xa5, 0x1c, 0x95, 0x68, 0x0f, 0x89, 0x6d, 0x6e, 0xfc, 0xf2, 0x53, 0x86, + 0x1e, 0x5e, 0xa1, 0x70, 0xce, 0x02, 0x7a, 0xf3, 0x52, 0x05, 0x08, 0x8c, + 0x01, 0x6f, 0xa4, 0x2b, 0xb1, 0xda, 0x74, 0x40, 0xad, 0x0a, 0xa2, 0x37, + 0x33, 0x35, 0x2e, 0x98, 0xc4, 0x78, 0x69, 0x2f, 0x48, 0xbf, 0x2e, 0xc3, + 0x32, 0x2d, 0x67, 0xd3, 0x6e, 0xb6, 0xed, 0x0e, 0x64, 0x83, 0x2a, 0xe3, + 0xdd, 0x7e, 0x5e, 0x38, 0x46, 0xfc, 0x6f, 0x34, 0x5c, 0xc4, 0xff, 0x4a, + 0x34, 0x9a, 0xbf, 0xb3, 0x96, 0xad, 0x92, 0x7b, 0x85, 0x76, 0xe0, 0x2e, + 0x66, 0xbf, 0x6f, 0x19, 0xba, 0x7f, 0x94, 0x27, 0xd9, 0x74, 0xee, 0x7a, + 0x9c, 0x31, 0xab, 0x9b, 0xed, 0x6e, 0x66, 0xbb, 0xeb, 0x34, 0x3d, 0x1a, + 0x3f, 0x5b, 0x2e, 0x1b, 0x74, 0x40, 0xd7, 0xa4, 0x6c, 0x13, 0xdb, 0x5d, + 0xcd, 0x76, 0x7b, 0x35, 0x91, 0xef, 0x77, 0xd6, 0xba, 0x55, 0x72, 0x2f, + 0x67, 0x1f, 0xb9, 0x76, 0xef, 0x91, 0x76, 0xcd, 0xd1, 0x7c, 0x5f, 0x47, + 0x13, 0xe8, 0x77, 0x44, 0x18, 0x63, 0x1b, 0x02, 0xfe, 0x2e, 0xc6, 0xdb, + 0x26, 0xc6, 0x8e, 0x9c, 0x4d, 0x4c, 0x8d, 0x77, 0x88, 0x9f, 0x2b, 0x23, + 0xd7, 0xa4, 0x9c, 0xd8, 0xda, 0x24, 0xf5, 0x2c, 0xf1, 0xc5, 0x47, 0xfd, + 0x0a, 0xb6, 0x38, 0x71, 0x20, 0x41, 0xfc, 0xc7, 0x37, 0x68, 0x77, 0x7e, + 0xb4, 0x64, 0x6a, 0xb1, 0x66, 0x27, 0xe3, 0xa0, 0x59, 0x45, 0x5b, 0xcf, + 0xd9, 0xdb, 0x32, 0xb6, 0x3d, 0x69, 0xb7, 0x1d, 0x57, 0x5a, 0x32, 0x75, + 0x5a, 0x15, 0x63, 0xee, 0x91, 0xb3, 0xd8, 0x39, 0x27, 0x5a, 0x1a, 0x09, + 0x34, 0xaf, 0xe7, 0x24, 0xb9, 0x19, 0xdf, 0xbe, 0x37, 0xaf, 0x87, 0x76, + 0xd1, 0x4b, 0x3b, 0xcc, 0xcd, 0x6f, 0x73, 0x66, 0x8f, 0x2a, 0x18, 0x07, + 0xb5, 0x16, 0xeb, 0x76, 0xca, 0x7f, 0x72, 0x95, 0x86, 0xc7, 0x78, 0xad, + 0x16, 0xab, 0x87, 0xbf, 0x47, 0x3b, 0xd3, 0x7d, 0x62, 0x87, 0x5d, 0x67, + 0xe5, 0x12, 0x99, 0x44, 0x36, 0x91, 0xa9, 0x8f, 0xe5, 0x66, 0x51, 0x3f, + 0x82, 0x8d, 0xd5, 0x94, 0x67, 0x2b, 0xf9, 0xd0, 0x21, 0xe5, 0xf3, 0x94, + 0x27, 0xeb, 0xf2, 0xe2, 0xa1, 0x94, 0xc8, 0xa3, 0x44, 0x67, 0x46, 0x66, + 0xe1, 0x4c, 0x2a, 0x10, 0x7f, 0x02, 0x22, 0x5b, 0x8f, 0xd2, 0x2a, 0xf5, + 0x53, 0xbd, 0xbc, 0x57, 0x90, 0x11, 0x5a, 0xa5, 0x2d, 0x5b, 0x4e, 0xa6, + 0xeb, 0x39, 0xd7, 0x2e, 0xe3, 0x6f, 0xcb, 0x51, 0xe1, 0xa4, 0xad, 0x49, + 0xdb, 0xff, 0x61, 0x45, 0xb5, 0x6e, 0x5e, 0xf3, 0x72, 0x9e, 0xdc, 0xe4, + 0x05, 0x7a, 0xf0, 0x3a, 0x87, 0xd2, 0xe2, 0x91, 0x78, 0x4d, 0xfb, 0x4c, + 0xa7, 0x9d, 0x38, 0x9e, 0x58, 0xba, 0xb4, 0xcc, 0xf8, 0x34, 0x1e, 0x1b, + 0xf1, 0x61, 0x84, 0x73, 0xfb, 0x6c, 0x42, 0xe2, 0xeb, 0x2c, 0x3c, 0x9a, + 0xf6, 0xe0, 0x99, 0x84, 0x1f, 0x8f, 0x30, 0xfe, 0x4c, 0x24, 0x0c, 0xec, + 0x4f, 0x7b, 0xf1, 0x34, 0xed, 0x79, 0x34, 0xed, 0xa3, 0xbd, 0xd4, 0x63, + 0x38, 0xdd, 0x66, 0x8f, 0xe1, 0xc9, 0xc4, 0xbf, 0xcb, 0x58, 0x83, 0x32, + 0xd6, 0xcd, 0xf6, 0x58, 0x0b, 0x71, 0x7e, 0xd6, 0xd9, 0x79, 0x38, 0x91, + 0xb0, 0x71, 0xa0, 0x77, 0x99, 0x43, 0xe6, 0x81, 0x36, 0x3b, 0x20, 0x58, + 0xa0, 0xf7, 0xc7, 0x61, 0x61, 0x8f, 0x39, 0x93, 0xfe, 0xdf, 0x4b, 0x79, + 0xa9, 0x53, 0x8e, 0x1f, 0xae, 0x8a, 0x68, 0x79, 0x24, 0x10, 0xeb, 0xa3, + 0xde, 0x9d, 0x11, 0xd1, 0x43, 0x4e, 0xef, 0x2b, 0x32, 0x87, 0x14, 0xe1, + 0x7a, 0x97, 0x0c, 0xc4, 0xad, 0x32, 0x43, 0xf4, 0x1d, 0x20, 0xce, 0x02, + 0xf3, 0xf7, 0x38, 0x39, 0xbe, 0x9b, 0x38, 0x66, 0x13, 0x45, 0x46, 0x9d, + 0x56, 0x4d, 0xd9, 0x8f, 0x7c, 0x24, 0x06, 0x8a, 0x8e, 0xfe, 0x36, 0x3f, + 0x5f, 0xba, 0x83, 0xf2, 0xfa, 0x81, 0xc2, 0xbc, 0x58, 0xd6, 0x0e, 0xb3, + 0x30, 0x37, 0x35, 0xf0, 0x57, 0xeb, 0xf1, 0x21, 0x5a, 0xc4, 0x48, 0x62, + 0x1a, 0xe2, 0x9a, 0x9a, 0x6f, 0x3b, 0xaa, 0x14, 0x31, 0xff, 0xc0, 0xb8, + 0xf8, 0x7e, 0x39, 0xa2, 0x4e, 0xa9, 0x8f, 0x68, 0x51, 0x24, 0x10, 0x9c, + 0xab, 0x4e, 0xb5, 0x19, 0xc1, 0x01, 0xe9, 0x2b, 0x4e, 0x59, 0xcf, 0xc7, + 0x82, 0x91, 0x44, 0x01, 0x37, 0xfe, 0x3b, 0xf5, 0x2e, 0xd4, 0xa9, 0xc8, + 0x29, 0x7a, 0x55, 0x71, 0x74, 0x50, 0xf4, 0xe7, 0xc4, 0x4a, 0x73, 0x7a, + 0x5e, 0xe6, 0x59, 0x9c, 0x17, 0x62, 0x0e, 0xe7, 0xeb, 0x85, 0x7e, 0x2f, + 0xe5, 0xb6, 0x90, 0x0e, 0x5d, 0x8c, 0x4d, 0x36, 0xe7, 0x5c, 0x95, 0xcf, + 0x5b, 0x38, 0x4f, 0xea, 0x76, 0xea, 0xfa, 0xb3, 0x8e, 0xdc, 0x79, 0x9d, + 0xef, 0xa3, 0xfa, 0xd2, 0xb5, 0x18, 0x0a, 0x3a, 0x03, 0x86, 0xd2, 0x88, + 0xb9, 0x23, 0xf5, 0x4d, 0xce, 0xbe, 0xb6, 0x0d, 0xf4, 0xef, 0x7b, 0x4f, + 0x35, 0x7c, 0x16, 0x9b, 0xa9, 0x17, 0xa7, 0x6d, 0x67, 0x51, 0xc5, 0x65, + 0x2c, 0xb1, 0xfd, 0x49, 0x1d, 0x5f, 0x91, 0xef, 0x23, 0x6a, 0xe7, 0x2c, + 0x50, 0x5b, 0xf2, 0xe7, 0x77, 0x53, 0xdf, 0x32, 0x0e, 0x15, 0x3f, 0x20, + 0x97, 0x7d, 0x27, 0xf4, 0x59, 0x64, 0x6d, 0xcc, 0x76, 0xd2, 0xdf, 0xaf, + 0x62, 0x5d, 0xe2, 0xdf, 0xb8, 0xc4, 0x52, 0xc4, 0x4b, 0xe8, 0xd7, 0x45, + 0xf4, 0xd5, 0x6b, 0x32, 0xf7, 0xa0, 0x3d, 0x15, 0x08, 0x97, 0x28, 0xf7, + 0xe0, 0xd6, 0x8c, 0x0b, 0xb1, 0x61, 0x0f, 0xd6, 0x51, 0x27, 0xce, 0xa4, + 0xf8, 0xb9, 0x86, 0x75, 0xa3, 0x47, 0x67, 0x3a, 0xe9, 0x37, 0xeb, 0x46, + 0xbd, 0x3c, 0xa6, 0xf3, 0x70, 0x63, 0x35, 0x8f, 0x3d, 0xb4, 0xcb, 0x36, + 0xc6, 0x86, 0x23, 0x09, 0x13, 0x9d, 0xd4, 0xd5, 0x13, 0x89, 0x06, 0xdc, + 0x4b, 0xbd, 0x1d, 0x4a, 0x7c, 0x8a, 0x3a, 0x0a, 0xa3, 0x83, 0x73, 0xfc, + 0x58, 0x42, 0xb5, 0xf3, 0xab, 0xdb, 0x33, 0xff, 0x62, 0x45, 0xa7, 0x8b, + 0x9c, 0xa2, 0x0b, 0x99, 0xcf, 0x8f, 0xe8, 0x81, 0xfe, 0x3b, 0x55, 0x17, + 0xf5, 0xd8, 0xb6, 0xcb, 0xc0, 0xf6, 0x5d, 0x75, 0xb4, 0xbb, 0x8c, 0xe5, + 0xaf, 0x1a, 0xa0, 0x0e, 0xa6, 0xea, 0xe1, 0x08, 0x79, 0x81, 0xe8, 0x41, + 0xda, 0xbc, 0x8f, 0x63, 0xee, 0xe6, 0x3d, 0x1f, 0x1e, 0x4f, 0x7c, 0x97, + 0xbf, 0xc3, 0xca, 0x5d, 0x19, 0xf1, 0x79, 0xf1, 0xb7, 0x7f, 0x70, 0xe4, + 0x62, 0x6f, 0xa1, 0xdc, 0x16, 0x96, 0xb3, 0xac, 0xcd, 0x67, 0xe3, 0x4a, + 0x51, 0xb4, 0x84, 0x71, 0x65, 0x7f, 0x22, 0x10, 0x7e, 0xc6, 0x8e, 0x7d, + 0x4e, 0xda, 0x8e, 0xd8, 0x47, 0x8f, 0x6d, 0x1b, 0xcb, 0xce, 0xda, 0xc6, + 0xe4, 0x59, 0x0e, 0xd5, 0x9f, 0x9a, 0xea, 0x73, 0x39, 0xbb, 0x70, 0x26, + 0xf5, 0x5e, 0xdb, 0x8e, 0xd3, 0x82, 0x8f, 0x0e, 0x38, 0x06, 0x9c, 0x68, + 0x33, 0x2f, 0xa5, 0xbe, 0xab, 0x19, 0x6f, 0x8a, 0x78, 0x30, 0x4f, 0x1d, + 0xfe, 0x0b, 0x94, 0x0e, 0x64, 0xad, 0x12, 0xfe, 0x6e, 0x0e, 0x89, 0xbe, + 0xaf, 0xc2, 0xad, 0xc3, 0x0e, 0x14, 0x0d, 0x28, 0x78, 0xd2, 0xac, 0xc7, + 0x90, 0x37, 0x87, 0xbb, 0x6a, 0xf2, 0x52, 0x7b, 0x9e, 0x2e, 0x1e, 0x3f, + 0xfa, 0x8c, 0xc4, 0x85, 0x7b, 0x47, 0x3d, 0xf0, 0x25, 0x15, 0x78, 0x88, + 0x2b, 0x65, 0x46, 0x3d, 0xf5, 0xaa, 0xa1, 0x32, 0x69, 0xe2, 0x6b, 0x19, + 0xd2, 0xa6, 0x07, 0xc2, 0xb8, 0x93, 0xf3, 0x52, 0xfe, 0xc0, 0x95, 0xb8, + 0x83, 0xe5, 0x36, 0xf0, 0xde, 0x86, 0xd1, 0x6a, 0x1e, 0x5e, 0x1e, 0xd3, + 0x79, 0x34, 0xe0, 0xf6, 0xe1, 0x5a, 0x44, 0xab, 0xf5, 0xa0, 0x5f, 0x75, + 0xa0, 0x7a, 0x40, 0xf4, 0xae, 0x62, 0xe5, 0x02, 0x05, 0xe6, 0xa7, 0x8b, + 0xa1, 0xce, 0xfd, 0x38, 0xdf, 0xfd, 0x53, 0xb2, 0xbe, 0x6c, 0x0d, 0xd9, + 0x98, 0x2e, 0x3a, 0x16, 0x3b, 0xf9, 0x57, 0xce, 0x85, 0xc8, 0x2b, 0x7d, + 0x48, 0xac, 0x15, 0x1d, 0x7f, 0x12, 0x36, 0x30, 0xb2, 0x54, 0x74, 0xb1, + 0xcc, 0x47, 0x7d, 0x01, 0x67, 0xe7, 0x7f, 0x2a, 0x67, 0x95, 0xb8, 0xaf, + 0x87, 0x87, 0x6c, 0x8e, 0xe3, 0x67, 0xbe, 0xa8, 0xc7, 0x45, 0xe7, 0xe4, + 0x34, 0x6e, 0xd5, 0x80, 0xbf, 0xc8, 0xb8, 0x19, 0xb7, 0x71, 0x9e, 0xf6, + 0x26, 0xd4, 0xa5, 0x2e, 0xa8, 0xb3, 0x5c, 0x4c, 0x9c, 0x47, 0x4c, 0x1d, + 0xed, 0xc3, 0xcc, 0xb5, 0x86, 0xcb, 0xd1, 0xa5, 0x29, 0xee, 0x6d, 0xf5, + 0x8b, 0x24, 0xa7, 0xf6, 0x57, 0x1a, 0x50, 0xcb, 0x18, 0xff, 0xb7, 0x6b, + 0x70, 0x16, 0x19, 0x8a, 0x9a, 0xa8, 0x6f, 0x42, 0xbc, 0x0a, 0xce, 0x0a, + 0x03, 0x0a, 0x73, 0x66, 0xf4, 0x69, 0x10, 0xec, 0x89, 0x16, 0x19, 0xf7, + 0xe0, 0xb6, 0x14, 0xac, 0xd2, 0x08, 0xf3, 0xa1, 0x88, 0x41, 0x8e, 0x1b, + 0xf0, 0x15, 0xd1, 0x3f, 0x56, 0x93, 0x57, 0xac, 0x1d, 0x16, 0x39, 0x3c, + 0xe4, 0x1b, 0x86, 0xbf, 0x0d, 0xcc, 0xe1, 0x5b, 0xf4, 0xe0, 0x24, 0xf3, + 0xd8, 0xd5, 0xd4, 0xfd, 0x48, 0xe2, 0x1e, 0x34, 0xa6, 0x8e, 0x58, 0x1e, + 0xf2, 0xc8, 0x22, 0xa3, 0xf6, 0x4c, 0x17, 0x62, 0xf4, 0x0d, 0xe1, 0x47, + 0x6b, 0xe8, 0x1b, 0x3e, 0x64, 0x12, 0xea, 0x71, 0xb2, 0x0b, 0x74, 0x8c, + 0xae, 0xc7, 0xd7, 0x46, 0x67, 0x61, 0x3c, 0xb1, 0x01, 0x77, 0x66, 0xc8, + 0x95, 0xfa, 0xaf, 0xc2, 0x1d, 0xc3, 0x57, 0xe1, 0xf6, 0x9d, 0x46, 0x70, + 0x03, 0x75, 0xbd, 0x76, 0x98, 0x81, 0x72, 0xba, 0xb4, 0x5b, 0xd0, 0x95, + 0xf0, 0x45, 0xea, 0x22, 0xaf, 0xa7, 0x2c, 0x0a, 0x1c, 0xe6, 0x5f, 0x2d, + 0x5e, 0x8a, 0x17, 0x35, 0x28, 0xfe, 0xdd, 0xf5, 0x2f, 0x31, 0xb7, 0x17, + 0xd9, 0x11, 0x9d, 0x69, 0xfc, 0xc0, 0x7a, 0x50, 0xa3, 0x7f, 0x47, 0x10, + 0x9f, 0xd3, 0xf0, 0xbc, 0xf5, 0xd0, 0x2a, 0xb9, 0x7e, 0x9b, 0x13, 0xa5, + 0x2a, 0xaf, 0x49, 0x9b, 0x82, 0x4b, 0x75, 0x44, 0xe2, 0x8f, 0x6b, 0x33, + 0x6b, 0x25, 0xcf, 0x96, 0x27, 0x2f, 0x24, 0x16, 0x3f, 0x91, 0xf0, 0xa2, + 0x37, 0x95, 0xe3, 0x56, 0x37, 0x65, 0x84, 0x53, 0xb9, 0x51, 0xda, 0x27, + 0x71, 0x25, 0x8a, 0xf5, 0xfc, 0x5d, 0xd2, 0xa7, 0xb7, 0xc4, 0x91, 0x60, + 0x9b, 0x4d, 0x9c, 0x0b, 0xda, 0x6b, 0x9f, 0x03, 0x25, 0x46, 0x73, 0xce, + 0x56, 0xfb, 0x56, 0xd0, 0x56, 0x35, 0x54, 0xf4, 0xf5, 0x70, 0xac, 0xb4, + 0x55, 0xd6, 0xbb, 0x83, 0xba, 0xf0, 0xf4, 0xad, 0xa2, 0xbd, 0xce, 0x42, + 0x59, 0x5f, 0x2b, 0xf1, 0x01, 0x8c, 0xeb, 0x16, 0x8e, 0x9a, 0x95, 0x79, + 0x7e, 0xda, 0x8c, 0x5b, 0x53, 0x51, 0xb4, 0xa5, 0x6a, 0xa3, 0x27, 0x65, + 0xad, 0xca, 0x95, 0xc3, 0xb0, 0x68, 0x8d, 0xe8, 0x62, 0x32, 0x8f, 0xa7, + 0x7a, 0x73, 0x8e, 0xd3, 0xe9, 0x9a, 0x5f, 0x29, 0xc8, 0xde, 0x83, 0x18, + 0xf3, 0x8f, 0x39, 0x91, 0x16, 0x58, 0x29, 0x91, 0x3b, 0x6e, 0xf9, 0x98, + 0x53, 0x7a, 0x22, 0xfa, 0xc6, 0xc5, 0x0e, 0xa3, 0xe3, 0x15, 0x25, 0x88, + 0xeb, 0x29, 0x43, 0x59, 0x5f, 0x27, 0x5e, 0x08, 0xe9, 0xbe, 0xef, 0x2a, + 0xfa, 0x99, 0x0d, 0x78, 0x05, 0x3f, 0xe3, 0xb5, 0xa2, 0xbe, 0x09, 0x3c, + 0x94, 0x79, 0x15, 0xa7, 0x28, 0xab, 0xda, 0xf7, 0xa1, 0xb5, 0xcc, 0x78, + 0x86, 0xe3, 0x77, 0x2b, 0x6f, 0x65, 0xa6, 0xda, 0xe2, 0x55, 0x58, 0xbd, + 0x53, 0xec, 0x4f, 0x0f, 0xc6, 0x89, 0xbd, 0x6d, 0x66, 0x85, 0x70, 0x79, + 0x89, 0x4f, 0x94, 0xbf, 0x45, 0xb0, 0x85, 0xfe, 0x41, 0x3b, 0xb0, 0xc7, + 0xd0, 0x6a, 0x63, 0xb2, 0x33, 0x09, 0x1b, 0x4b, 0x73, 0x7a, 0x8e, 0x28, + 0x6d, 0xa3, 0xbe, 0x52, 0x94, 0xfa, 0xf2, 0x7e, 0x90, 0x5b, 0xb3, 0x38, + 0x57, 0xf7, 0x3f, 0xad, 0x11, 0xef, 0xf9, 0x75, 0x2b, 0x98, 0x83, 0x55, + 0x72, 0x3c, 0xef, 0xf6, 0xc5, 0xad, 0xd2, 0xdc, 0x58, 0x9a, 0x7f, 0xa0, + 0x88, 0x4d, 0x06, 0xc9, 0xed, 0x3b, 0x71, 0x69, 0x48, 0x6f, 0xfd, 0xae, + 0x22, 0x65, 0xf5, 0xf0, 0x06, 0xa5, 0xd0, 0xcf, 0xcb, 0x38, 0x39, 0x22, + 0x7d, 0x48, 0x5f, 0x13, 0xcc, 0xc9, 0x72, 0x63, 0x10, 0x5f, 0x7a, 0xc4, + 0x9e, 0x4b, 0xf1, 0x27, 0x3f, 0x96, 0x73, 0x4c, 0xae, 0x3e, 0x1f, 0x0f, + 0x17, 0xed, 0xd5, 0x87, 0xb5, 0x99, 0x15, 0x58, 0xcd, 0xbc, 0x76, 0x75, + 0xa6, 0x85, 0xba, 0xdf, 0x48, 0x7c, 0x67, 0x46, 0xa0, 0xe5, 0x74, 0x7c, + 0xce, 0x3e, 0x74, 0xff, 0x24, 0x56, 0xf0, 0xfe, 0xcf, 0x9d, 0xa8, 0x68, + 0x61, 0x79, 0xfb, 0xbe, 0x29, 0xf8, 0x7d, 0xae, 0xcc, 0x47, 0x78, 0x98, + 0x1d, 0xe7, 0xf7, 0xda, 0x1c, 0xb1, 0xc5, 0xce, 0xbd, 0xae, 0xb6, 0xe7, + 0x5c, 0x38, 0x82, 0x85, 0x63, 0x66, 0x31, 0xf3, 0xaf, 0xba, 0xe0, 0xf9, + 0x9c, 0x50, 0x67, 0x16, 0x5a, 0xc0, 0x03, 0xe9, 0x4b, 0xf4, 0x72, 0xa2, + 0x26, 0xa7, 0x97, 0x4f, 0x2a, 0x7b, 0x3e, 0x76, 0xec, 0x49, 0x48, 0xdf, + 0x45, 0x36, 0x2f, 0x6d, 0xcc, 0x94, 0x22, 0xee, 0x15, 0x1d, 0x49, 0x7b, + 0xba, 0x5f, 0x64, 0x5a, 0xbb, 0x53, 0xec, 0xd8, 0xc2, 0x08, 0x65, 0xe8, + 0xb6, 0xe7, 0x2d, 0xc7, 0x25, 0x8f, 0x9c, 0x17, 0x9f, 0x65, 0x4c, 0x85, + 0xbe, 0x6f, 0x73, 0xe5, 0xf8, 0x66, 0x81, 0x2b, 0x58, 0xd6, 0x80, 0x59, + 0xe0, 0x0a, 0x32, 0xe6, 0xbf, 0x00, 0x63, 0x9d, 0x3d, 0xde, 0x35, 0xf9, + 0xb6, 0xbb, 0xcc, 0x00, 0xed, 0x5a, 0xb8, 0x54, 0x44, 0x59, 0xb3, 0x2b, + 0xc3, 0xb9, 0x95, 0xdc, 0x06, 0xb8, 0x93, 0xf7, 0xcb, 0x79, 0xff, 0xc5, + 0x90, 0x0b, 0x97, 0x4e, 0x97, 0xbe, 0xaf, 0x42, 0xc7, 0xce, 0x28, 0x2a, + 0x17, 0x06, 0x30, 0x69, 0x73, 0x89, 0x02, 0xef, 0x75, 0xe1, 0x8e, 0x9d, + 0x1f, 0x5a, 0x15, 0x36, 0x17, 0x33, 0x62, 0xe3, 0x8a, 0x8a, 0xed, 0x8b, + 0x84, 0xff, 0xba, 0x88, 0xef, 0xe4, 0xa2, 0xc2, 0xad, 0x5d, 0x65, 0xe4, + 0xb0, 0xc2, 0xe1, 0x02, 0xd9, 0x9b, 0x54, 0x68, 0x5a, 0x44, 0xb8, 0xdc, + 0x2c, 0x9b, 0xc3, 0x0a, 0x97, 0xfd, 0x56, 0xea, 0xd0, 0x14, 0x2e, 0x7b, + 0x96, 0x73, 0x30, 0xf7, 0x69, 0x61, 0x7e, 0xef, 0x81, 0x3b, 0xa2, 0xb7, + 0x6c, 0x52, 0x3a, 0xb1, 0x3c, 0x64, 0x98, 0x92, 0x53, 0x5f, 0xa9, 0xe8, + 0xc1, 0xd3, 0x08, 0x12, 0x6f, 0x5f, 0xc6, 0xc8, 0x60, 0xdc, 0x25, 0x76, + 0xb4, 0x29, 0x73, 0x4e, 0x9e, 0x5b, 0x29, 0x8f, 0x3b, 0x27, 0x8f, 0x79, + 0x1a, 0x2a, 0x9e, 0x6c, 0x70, 0x11, 0xb7, 0xfe, 0x0e, 0x6d, 0x3b, 0x55, + 0x2c, 0xb1, 0xb9, 0xf9, 0xdf, 0x11, 0x7f, 0x2f, 0x2a, 0xcd, 0x95, 0x07, + 0x3a, 0xe9, 0xdf, 0xef, 0x2f, 0x2c, 0x41, 0x68, 0x9a, 0x82, 0x2a, 0xa3, + 0x83, 0xf9, 0xf1, 0x87, 0x56, 0xdc, 0x49, 0x3a, 0x6b, 0x40, 0x2b, 0x89, + 0x44, 0x29, 0x5b, 0x93, 0x72, 0xcd, 0xf0, 0x20, 0xfb, 0xe9, 0x20, 0xef, + 0xf7, 0xe0, 0x2e, 0xda, 0xce, 0x5d, 0x8c, 0x65, 0x77, 0x31, 0x96, 0xdd, + 0x35, 0xfa, 0x2f, 0xbc, 0x3e, 0xdd, 0xfe, 0xbd, 0x29, 0x55, 0xb0, 0x65, + 0x27, 0xe3, 0x82, 0xe8, 0x77, 0x33, 0x7d, 0x47, 0xe2, 0x02, 0x28, 0x93, + 0x85, 0x93, 0x9c, 0xc7, 0x25, 0x9a, 0x1e, 0xcc, 0xe2, 0xeb, 0xae, 0x73, + 0x79, 0x5f, 0x21, 0xb6, 0xc8, 0x3c, 0xba, 0x70, 0x1b, 0x65, 0x0c, 0x86, + 0xfe, 0xcb, 0x42, 0x95, 0xf8, 0xee, 0x85, 0xf7, 0x73, 0xf3, 0x7a, 0xe4, + 0x2c, 0x07, 0x54, 0xc4, 0x4e, 0xe9, 0xf3, 0x7b, 0x6c, 0x4e, 0xf1, 0xa2, + 0xc9, 0xdc, 0x6d, 0xe7, 0xd1, 0xf9, 0x62, 0x2a, 0x6b, 0x47, 0xa3, 0xe8, + 0xe6, 0xb8, 0x57, 0x0f, 0x3f, 0x96, 0xd7, 0x4b, 0x61, 0xbc, 0x0a, 0xd5, + 0xe2, 0xa1, 0xff, 0xe4, 0x72, 0x95, 0xb6, 0x51, 0xe1, 0xb6, 0xd5, 0xfc, + 0x2f, 0xdc, 0xd6, 0xcb, 0xff, 0xc2, 0x73, 0xa7, 0xf3, 0xbf, 0x13, 0xfe, + 0xe9, 0x62, 0xc7, 0xf5, 0xe8, 0xdd, 0x65, 0x59, 0xc5, 0x81, 0x7a, 0x6c, + 0x19, 0xfd, 0x48, 0xbc, 0xbc, 0x40, 0x1e, 0x7b, 0x0e, 0xe8, 0x47, 0x2e, + 0xc1, 0x22, 0xbf, 0x5f, 0x95, 0xbe, 0x2d, 0x6c, 0x34, 0xaf, 0x62, 0x9f, + 0x8c, 0x80, 0xd5, 0x53, 0xfd, 0xa2, 0xd0, 0x46, 0x41, 0xdf, 0xc5, 0xf4, + 0x73, 0x68, 0x2e, 0xea, 0x7b, 0x65, 0x46, 0xea, 0x36, 0x29, 0x4b, 0x87, + 0xa7, 0x96, 0xef, 0x20, 0x1f, 0x3e, 0x4d, 0x5d, 0x17, 0xfc, 0xc8, 0x9b, + 0xcf, 0x2b, 0x98, 0x4b, 0xa4, 0x44, 0x97, 0x32, 0xbe, 0x5c, 0xae, 0x28, + 0xb6, 0x74, 0xe4, 0x6c, 0x1f, 0xa2, 0xb7, 0xf8, 0xf4, 0x12, 0x43, 0xec, + 0x28, 0x48, 0x5c, 0xd1, 0xc3, 0xcd, 0x84, 0xed, 0x53, 0x09, 0xc4, 0x1c, + 0x91, 0xe6, 0xa6, 0xb5, 0x89, 0xb9, 0xda, 0xf1, 0x7c, 0x2e, 0xba, 0x87, + 0x38, 0xae, 0x1a, 0xb2, 0x0e, 0x42, 0x5b, 0x19, 0x16, 0xdd, 0x75, 0x28, + 0xe7, 0xf2, 0xce, 0x28, 0x79, 0x97, 0x6a, 0xcb, 0xe8, 0x8c, 0x88, 0x6c, + 0x52, 0x87, 0xb2, 0x5f, 0xc0, 0xbf, 0x72, 0xba, 0xa8, 0x80, 0x67, 0x40, + 0x78, 0x97, 0x8e, 0x0d, 0x8c, 0xf3, 0x65, 0x03, 0x7e, 0xfa, 0x42, 0x35, + 0x4a, 0x1f, 0x88, 0x60, 0xfd, 0xa8, 0x86, 0x92, 0x07, 0x2c, 0x6b, 0x6e, + 0xa8, 0x87, 0x5c, 0xf6, 0xb2, 0x22, 0xc9, 0x9d, 0x9c, 0x49, 0x62, 0x16, + 0xf1, 0xad, 0x3d, 0xa5, 0xe0, 0x6a, 0xc6, 0xd3, 0x28, 0x71, 0xa8, 0xdd, + 0xc6, 0x39, 0xab, 0x73, 0x4e, 0xc4, 0x45, 0x1b, 0x5a, 0xc5, 0xfb, 0xad, + 0xc4, 0xc0, 0x56, 0x62, 0x9a, 0x65, 0xbd, 0x7f, 0x39, 0x3a, 0xcb, 0x22, + 0x37, 0x13, 0x0b, 0x6b, 0xc9, 0x89, 0x25, 0x7e, 0x5f, 0x8e, 0x35, 0x8c, + 0xfd, 0xc5, 0x49, 0x3b, 0x9f, 0xa2, 0xee, 0x18, 0xa3, 0x32, 0x8c, 0x71, + 0x94, 0xfd, 0x69, 0x72, 0x5c, 0xe1, 0xbb, 0x95, 0xc9, 0x0d, 0x8c, 0x75, + 0x1e, 0x54, 0x0c, 0x5c, 0x86, 0x3b, 0x19, 0xcf, 0xef, 0xd8, 0xe9, 0x47, + 0x7a, 0xd1, 0x55, 0x94, 0xef, 0x1e, 0xac, 0x4f, 0x19, 0x92, 0x43, 0x45, + 0x83, 0x8b, 0xc8, 0xb7, 0x33, 0x82, 0x3b, 0x92, 0x8f, 0x95, 0x61, 0x49, + 0x0b, 0x10, 0x4c, 0x16, 0xf0, 0x2d, 0x2a, 0x6b, 0x47, 0x30, 0x92, 0xe7, + 0x63, 0xdb, 0x39, 0x5e, 0x24, 0xeb, 0x70, 0x2d, 0x98, 0xcf, 0x58, 0x20, + 0xf6, 0xa5, 0x31, 0xc7, 0x2c, 0x51, 0x0c, 0xdf, 0x1e, 0xfa, 0xa9, 0xe4, + 0x3d, 0x57, 0x24, 0x0b, 0xb1, 0x4f, 0xcf, 0x2e, 0x76, 0x74, 0x12, 0x47, + 0xf4, 0x8d, 0xbf, 0x53, 0xf4, 0xf6, 0x13, 0xca, 0x2b, 0xd8, 0x37, 0xf6, + 0x2a, 0x86, 0xc6, 0xdc, 0xca, 0xe8, 0x98, 0xf4, 0x35, 0x81, 0xbe, 0xcc, + 0x9f, 0xea, 0x6b, 0xea, 0xfa, 0xcb, 0xa2, 0xf3, 0xd6, 0x6c, 0xae, 0xce, + 0xe7, 0x89, 0x4b, 0xcf, 0xe3, 0xc7, 0x32, 0x27, 0x62, 0x97, 0x5e, 0xf4, + 0xa4, 0xce, 0xad, 0x0b, 0xf4, 0x27, 0xb6, 0xd9, 0xfe, 0xd9, 0x92, 0x11, + 0x7b, 0x55, 0x19, 0x33, 0x2f, 0xce, 0xe7, 0x2c, 0xb5, 0xd4, 0x41, 0x9f, + 0x7d, 0x6f, 0x9f, 0xf9, 0x29, 0x64, 0xed, 0x6b, 0x8b, 0xe9, 0x9b, 0xd5, + 0x28, 0x26, 0x26, 0x06, 0x43, 0x3e, 0x14, 0x57, 0xc9, 0x3a, 0xce, 0xb9, + 0xdc, 0x7f, 0xc3, 0x4e, 0x86, 0x64, 0x1b, 0x73, 0x1a, 0x89, 0x7f, 0xb5, + 0x9c, 0xef, 0x1c, 0xce, 0xac, 0xa7, 0x0d, 0x5d, 0x27, 0x36, 0xe4, 0xca, + 0xd9, 0xd0, 0x47, 0xd7, 0x17, 0x54, 0x90, 0xfb, 0x69, 0x15, 0x76, 0xde, + 0xd7, 0xa4, 0x5c, 0x9f, 0xb7, 0xab, 0xcf, 0x67, 0x1e, 0x2d, 0xca, 0xe7, + 0x66, 0x17, 0x94, 0xff, 0x38, 0x1d, 0x5c, 0xf6, 0x67, 0xe8, 0x40, 0xe2, + 0x81, 0xe4, 0x04, 0xa2, 0x83, 0xf3, 0xf3, 0xf2, 0xfe, 0x44, 0x35, 0x71, + 0xef, 0x42, 0x5d, 0xcc, 0xcc, 0xeb, 0x62, 0x31, 0xb1, 0x4b, 0xfe, 0x5b, + 0x38, 0x65, 0x7a, 0xf1, 0xa2, 0x26, 0xe3, 0x5e, 0x8c, 0xf5, 0x1c, 0xaf, + 0x9b, 0xba, 0x58, 0x1e, 0xaa, 0x44, 0xf0, 0xbc, 0x78, 0x50, 0xcb, 0xd8, + 0xf1, 0x21, 0x79, 0xa6, 0xfc, 0xf6, 0xe3, 0x05, 0xea, 0xe2, 0x8e, 0xe1, + 0xc5, 0xb8, 0x8b, 0xfe, 0x94, 0xe3, 0x90, 0xb9, 0xd8, 0xb0, 0x76, 0x58, + 0xda, 0x14, 0x8c, 0xfb, 0xd9, 0xd9, 0x71, 0xfe, 0x71, 0x5e, 0xfe, 0x0a, + 0xe5, 0x97, 0x67, 0x07, 0xb2, 0x16, 0x2d, 0xcf, 0x11, 0x64, 0x2c, 0xc6, + 0x14, 0xdc, 0xb1, 0xac, 0x83, 0xe6, 0x3c, 0xc4, 0xaa, 0xf5, 0x7e, 0x89, + 0x8f, 0xfd, 0xc4, 0x03, 0x07, 0xf3, 0xc8, 0xa2, 0x48, 0x94, 0xfe, 0xac, + 0x5e, 0xe5, 0x80, 0x5a, 0xef, 0x40, 0x27, 0xde, 0x30, 0x8d, 0xde, 0x75, + 0xf8, 0x14, 0xba, 0xbc, 0x16, 0xf6, 0xb2, 0x9d, 0xee, 0x54, 0x09, 0xda, + 0xeb, 0x69, 0x56, 0x2b, 0x3d, 0xd8, 0x91, 0x8a, 0xb7, 0x12, 0x16, 0x18, + 0x73, 0x1a, 0xfe, 0x2a, 0x11, 0xd0, 0x5b, 0x36, 0x90, 0xb7, 0x2c, 0xef, + 0x73, 0xc3, 0xaf, 0xe4, 0x72, 0xb4, 0x01, 0x55, 0xd6, 0x09, 0x23, 0x94, + 0xbd, 0xc7, 0xce, 0xf7, 0xfc, 0xd3, 0xa5, 0x1f, 0x3f, 0xe2, 0x19, 0xa9, + 0xeb, 0x47, 0xe9, 0x5c, 0x05, 0xcb, 0xe7, 0xea, 0xf1, 0xa8, 0x62, 0x59, + 0x0b, 0x42, 0x4e, 0xfb, 0xfe, 0xb6, 0x4c, 0x5d, 0xeb, 0x0d, 0xea, 0xab, + 0x56, 0x6e, 0x6d, 0x52, 0xd7, 0xa2, 0x4c, 0x0a, 0x8e, 0xfc, 0xd1, 0xf5, + 0xf9, 0x20, 0xe4, 0xb9, 0x89, 0xdb, 0x58, 0x89, 0xfd, 0xf9, 0xf5, 0x39, + 0x57, 0xe4, 0xbd, 0x2f, 0xef, 0x35, 0x24, 0x6f, 0x11, 0x9d, 0x4b, 0x7f, + 0x62, 0x0b, 0xd7, 0x15, 0x0b, 0x06, 0x76, 0x65, 0x16, 0xd2, 0x16, 0x7f, + 0x6b, 0x8d, 0x7a, 0xa7, 0x96, 0xbd, 0x51, 0xcd, 0xad, 0xb7, 0x4b, 0xd9, + 0x42, 0xb9, 0x8b, 0x89, 0x09, 0x8d, 0x18, 0x3e, 0xaf, 0x4d, 0xc9, 0x75, + 0x0b, 0x6d, 0xde, 0xc6, 0x72, 0xd2, 0xae, 0xe0, 0xef, 0x7f, 0x59, 0xfb, + 0xce, 0x6b, 0xaf, 0xd5, 0x95, 0x6b, 0xef, 0xee, 0x62, 0xc9, 0xdd, 0xfb, + 0x53, 0x45, 0xac, 0xf3, 0x4e, 0x9e, 0x07, 0x16, 0xca, 0x7c, 0xea, 0x82, + 0x32, 0xc4, 0x79, 0xe3, 0x4d, 0x6b, 0xcf, 0x79, 0x65, 0x96, 0x3b, 0xcf, + 0x2f, 0xe3, 0xc4, 0x1c, 0xe3, 0x55, 0xeb, 0xc8, 0x79, 0x65, 0xd2, 0x17, + 0x94, 0xb9, 0x1c, 0x63, 0xf5, 0x8f, 0x58, 0x43, 0xb9, 0xb9, 0xc9, 0xd2, + 0x7d, 0xdc, 0x33, 0x23, 0xad, 0x7f, 0x75, 0xc5, 0x3c, 0xbd, 0x63, 0xa6, + 0x43, 0x9e, 0xd9, 0xb8, 0x91, 0xcd, 0xcd, 0x4d, 0x5c, 0xe6, 0xc6, 0xb5, + 0xa0, 0x30, 0x37, 0xd7, 0xe5, 0xeb, 0x17, 0xda, 0xbd, 0xae, 0xe8, 0xfc, + 0x76, 0x0b, 0xd7, 0xaf, 0xb8, 0x40, 0xee, 0xef, 0x5c, 0x50, 0xee, 0xb7, + 0x7f, 0xa4, 0xde, 0x2f, 0x1c, 0xe7, 0x5f, 0x3f, 0xa0, 0x9e, 0x7f, 0xde, + 0x9c, 0x3f, 0x2f, 0xe8, 0xbf, 0xea, 0x82, 0xf2, 0x35, 0x17, 0x94, 0x7f, + 0x59, 0xfd, 0xf8, 0x7e, 0xd6, 0x5d, 0x50, 0xcf, 0x5e, 0xab, 0xc6, 0x53, + 0x67, 0x7d, 0x1e, 0x4d, 0x45, 0x08, 0x98, 0x4e, 0x05, 0x7e, 0xfa, 0xbe, + 0xff, 0xe9, 0x0b, 0xd6, 0xac, 0x9b, 0xce, 0xfa, 0xfe, 0x79, 0x9c, 0x33, + 0x56, 0x1c, 0x91, 0x18, 0x56, 0x44, 0xee, 0x2c, 0x3c, 0xb0, 0x4e, 0x3b, + 0x97, 0x67, 0x15, 0x62, 0x65, 0x45, 0xac, 0x24, 0xd2, 0x00, 0xff, 0xd8, + 0x2c, 0xff, 0x9b, 0x09, 0x59, 0xb7, 0xfc, 0x80, 0x5c, 0xca, 0xf0, 0xed, + 0xc7, 0x2c, 0xff, 0x4f, 0xd3, 0x6f, 0x15, 0xa3, 0xc2, 0x83, 0xab, 0x13, + 0x1f, 0x5f, 0x4f, 0x8d, 0x40, 0x59, 0xd6, 0xe0, 0x63, 0x7e, 0x05, 0xe7, + 0x35, 0xf3, 0x30, 0xe5, 0xaf, 0x45, 0xf2, 0x3d, 0xf5, 0x58, 0x43, 0x98, + 0xf1, 0x39, 0xf7, 0xbc, 0x76, 0x49, 0x46, 0xf7, 0x45, 0x95, 0xdc, 0x33, + 0xd9, 0xf6, 0xd0, 0x1f, 0xc8, 0x77, 0x3a, 0x29, 0x97, 0xc5, 0xbe, 0x80, + 0x0d, 0x09, 0xcb, 0x7a, 0x8a, 0x79, 0xaa, 0x3c, 0xeb, 0xff, 0x79, 0xfa, + 0xf7, 0xd6, 0x84, 0xd7, 0x89, 0xb7, 0x8c, 0xa9, 0xed, 0xf9, 0x51, 0x19, + 0x31, 0x99, 0x2f, 0xd9, 0x27, 0xea, 0x98, 0x51, 0xb7, 0x71, 0x2f, 0xfd, + 0x6e, 0x7e, 0x40, 0xf7, 0x27, 0xf1, 0xef, 0x96, 0xbf, 0x46, 0x0f, 0x0e, + 0x29, 0x85, 0x75, 0xe2, 0x0b, 0xd7, 0x83, 0x2b, 0x62, 0x2e, 0x8e, 0x6f, + 0x8f, 0xcd, 0xf7, 0x8b, 0x88, 0x71, 0x88, 0x39, 0x23, 0xb3, 0xfc, 0x5b, + 0x12, 0xf6, 0x38, 0xc9, 0x17, 0x15, 0x1c, 0x6b, 0x98, 0xe5, 0xef, 0x4e, + 0x7b, 0xb1, 0x9d, 0xf1, 0xb8, 0xc4, 0x68, 0xc0, 0x23, 0x69, 0x15, 0xb7, + 0xdd, 0xef, 0xc5, 0x5a, 0x72, 0xd1, 0x8d, 0x7d, 0xdf, 0x80, 0x71, 0xa9, + 0x13, 0xb7, 0xd2, 0xfe, 0xd6, 0xf5, 0x15, 0xdb, 0x39, 0xc8, 0xfa, 0x3e, + 0x27, 0xea, 0x2f, 0xad, 0x40, 0xbc, 0xa6, 0x18, 0xdf, 0x37, 0x1d, 0xcc, + 0x7b, 0xca, 0x30, 0x64, 0x63, 0xa2, 0xe4, 0xb2, 0x82, 0x73, 0xa2, 0x37, + 0x87, 0xbd, 0x2e, 0xf9, 0xf1, 0x58, 0xfe, 0x5b, 0x2b, 0x5b, 0xb3, 0xdd, + 0xc6, 0x5f, 0x47, 0xc4, 0xb4, 0xe3, 0x25, 0x90, 0xe3, 0x69, 0x5d, 0xe7, + 0x3d, 0x57, 0x6e, 0x51, 0xe6, 0x44, 0x02, 0x13, 0x8b, 0x15, 0x07, 0xc2, + 0x81, 0x8a, 0x58, 0x65, 0x24, 0x8c, 0x65, 0x99, 0x2e, 0x9f, 0xcf, 0x7e, + 0x56, 0x1d, 0xc1, 0xe9, 0x45, 0x26, 0x73, 0x60, 0x38, 0x97, 0x51, 0xf7, + 0x4d, 0xd4, 0xeb, 0x66, 0xf3, 0x0f, 0x56, 0xd6, 0xf6, 0x7b, 0x37, 0x62, + 0x9a, 0x65, 0xad, 0xa3, 0x7e, 0x1d, 0xd4, 0xe3, 0xcf, 0xf2, 0xfa, 0x15, + 0x9d, 0x96, 0x8d, 0xfd, 0xde, 0x3a, 0x46, 0xfd, 0xba, 0xd9, 0x9e, 0x9b, + 0xed, 0x95, 0x8c, 0x9d, 0xaf, 0xe7, 0x62, 0xca, 0xb3, 0xcc, 0x96, 0xa1, + 0x52, 0x9e, 0xf5, 0xf9, 0xa3, 0x4a, 0x01, 0xb7, 0xff, 0xd4, 0x98, 0x5e, + 0x99, 0x92, 0x83, 0x88, 0xfe, 0xfd, 0xd4, 0xbf, 0x60, 0xb8, 0xcc, 0x41, + 0xbd, 0xac, 0xfb, 0xf4, 0x02, 0xa3, 0x4c, 0xd6, 0x15, 0x4c, 0x33, 0x22, + 0xf8, 0x76, 0x8b, 0x07, 0x6f, 0x26, 0xca, 0xed, 0x71, 0x5f, 0x3a, 0xd7, + 0xb2, 0x1e, 0x0f, 0xf9, 0xf1, 0x73, 0xa3, 0x2e, 0xbc, 0x40, 0xd5, 0x31, + 0xa9, 0x79, 0x91, 0x20, 0xce, 0x76, 0xa5, 0x66, 0x73, 0xbe, 0xbc, 0xd8, + 0x92, 0xc2, 0x46, 0xda, 0x93, 0xdf, 0x11, 0x01, 0xde, 0x48, 0x18, 0xc1, + 0xcd, 0xec, 0x7f, 0xd8, 0xdb, 0x40, 0xfe, 0xad, 0x36, 0x91, 0xaa, 0xc5, + 0x4b, 0x22, 0x46, 0x7c, 0x2b, 0xfe, 0xc3, 0x1a, 0x22, 0xce, 0x17, 0x85, + 0x64, 0x6d, 0x6e, 0x0e, 0x8e, 0x6b, 0x0e, 0x3c, 0x1b, 0x9c, 0x8e, 0x28, + 0xdd, 0xb1, 0xcc, 0x78, 0xcb, 0xfa, 0xa1, 0x57, 0xfa, 0x91, 0xb1, 0xfc, + 0x86, 0xe3, 0x50, 0x6c, 0x2c, 0xdc, 0x92, 0x6a, 0xa0, 0xbe, 0x2f, 0xec, + 0xff, 0xdf, 0xad, 0x49, 0xaf, 0xf4, 0xcf, 0x5c, 0x9e, 0xf1, 0xec, 0xc8, + 0x1f, 0xc5, 0xee, 0x97, 0xac, 0xe7, 0xec, 0x36, 0x17, 0xb9, 0x73, 0x71, + 0x50, 0xda, 0xfb, 0x17, 0x8e, 0x4f, 0xda, 0x2c, 0xf4, 0x23, 0x7a, 0xcb, + 0xba, 0xc5, 0x9f, 0xb7, 0xa4, 0x44, 0x7f, 0x82, 0x57, 0xc7, 0x2c, 0x4c, + 0x97, 0xf3, 0x87, 0xed, 0xb2, 0x71, 0xea, 0xab, 0x8b, 0x36, 0xc4, 0xd8, + 0xcb, 0x3c, 0x4e, 0x76, 0x51, 0x68, 0x76, 0x9e, 0xb6, 0x89, 0xdc, 0x7e, + 0xc8, 0x5b, 0x89, 0x2d, 0x26, 0xed, 0xce, 0x50, 0x2f, 0x76, 0x42, 0x72, + 0x53, 0x39, 0x77, 0x61, 0xd2, 0xeb, 0xc0, 0x56, 0xd3, 0x89, 0x76, 0x43, + 0xd5, 0xe5, 0xba, 0x23, 0x24, 0xe7, 0x2e, 0xf8, 0x6b, 0x14, 0x6c, 0x0f, + 0xab, 0x58, 0x6f, 0x74, 0xf9, 0xe5, 0xfa, 0x92, 0x90, 0x9c, 0x2b, 0x58, + 0x43, 0x9d, 0xc4, 0x35, 0x05, 0x1b, 0x0c, 0x79, 0xbe, 0x98, 0xe3, 0xbe, + 0x31, 0x58, 0xd6, 0x76, 0xb3, 0xf1, 0x8a, 0x32, 0x48, 0x9c, 0x17, 0x2e, + 0xf7, 0xde, 0xcd, 0xf3, 0x03, 0x71, 0x12, 0x31, 0x3d, 0x56, 0x42, 0x3f, + 0xdd, 0xd2, 0x37, 0x87, 0xf5, 0x14, 0x72, 0x1c, 0xa7, 0x6f, 0x1b, 0x24, + 0x7e, 0x06, 0xfc, 0x3f, 0x65, 0xf2, 0x34, 0xe4, 0x9d, 0x47, 0xcd, 0x1a, + 0xfe, 0x93, 0x9c, 0xb7, 0x4a, 0xc3, 0xb9, 0xf1, 0x07, 0xd0, 0xdb, 0x4b, + 0x94, 0x79, 0xc1, 0x0a, 0xe6, 0x00, 0x71, 0xe2, 0xfb, 0xc8, 0x98, 0x13, + 0x9b, 0x53, 0x86, 0xb6, 0xcf, 0xe6, 0x6e, 0x4e, 0xea, 0xc2, 0xc9, 0x1c, + 0x3f, 0xa0, 0x4d, 0x28, 0x85, 0xf3, 0x39, 0x82, 0x0d, 0xe4, 0xe2, 0x82, + 0x6f, 0x71, 0xeb, 0xc9, 0x06, 0x49, 0xdb, 0xdc, 0xfe, 0x58, 0xda, 0xc3, + 0x43, 0xe3, 0xe1, 0xf5, 0xaf, 0x4d, 0xfb, 0xfc, 0x6b, 0xd2, 0xf0, 0xb7, + 0xa5, 0x0b, 0x76, 0x59, 0xf0, 0x6d, 0xc1, 0x36, 0x8b, 0x7c, 0x33, 0x97, + 0x73, 0x75, 0x49, 0x4e, 0x03, 0x79, 0x3e, 0xf6, 0xde, 0xcd, 0x4f, 0xd1, + 0xd6, 0x5d, 0xe4, 0xf2, 0x5b, 0x8d, 0x78, 0x54, 0x9e, 0xd7, 0x19, 0x21, + 0xdd, 0x57, 0xa4, 0xf8, 0xb1, 0xa5, 0xfe, 0x77, 0x9c, 0x4f, 0x72, 0xdc, + 0xf4, 0xa7, 0x4a, 0x72, 0xf3, 0x21, 0x7e, 0x26, 0x18, 0xe0, 0x67, 0x1e, + 0xe4, 0xf3, 0x77, 0xb1, 0x9f, 0x4d, 0xe9, 0xa9, 0x3e, 0xa0, 0xe0, 0x1a, + 0xb6, 0xd5, 0x18, 0x82, 0x73, 0x69, 0xfd, 0x7f, 0x59, 0x59, 0xef, 0xd4, + 0x7d, 0x11, 0x20, 0x87, 0x80, 0xb3, 0xad, 0x5e, 0xce, 0x15, 0x34, 0x86, + 0xe5, 0x5c, 0x41, 0x9b, 0x91, 0x93, 0x4f, 0x7c, 0xb7, 0x9b, 0xb8, 0x7d, + 0xee, 0xfc, 0x42, 0x2c, 0x32, 0x71, 0x7b, 0x0a, 0xb1, 0xa2, 0x88, 0x60, + 0x91, 0xdb, 0xff, 0x5c, 0xba, 0x9e, 0x5c, 0x5c, 0x9e, 0x7f, 0xbb, 0x39, + 0xe7, 0x1e, 0xff, 0xb3, 0xe9, 0x2b, 0x71, 0xdb, 0xae, 0x30, 0xda, 0x77, + 0xc9, 0x86, 0x23, 0xe6, 0x60, 0xa1, 0x80, 0x7f, 0x14, 0x9a, 0xff, 0x38, + 0x75, 0x72, 0x94, 0x72, 0x1e, 0x3b, 0x4f, 0x4e, 0xd1, 0x21, 0xfc, 0x77, + 0x24, 0xdc, 0x48, 0x87, 0xde, 0xb7, 0xe2, 0x36, 0xe7, 0xf0, 0xfa, 0xef, + 0x4c, 0xf8, 0x91, 0xb5, 0xb9, 0xe7, 0xbf, 0xbb, 0x25, 0x47, 0xec, 0x49, + 0xc5, 0xa3, 0x4c, 0x79, 0xf3, 0xf3, 0xab, 0x87, 0x65, 0x6e, 0xdf, 0x48, + 0xc8, 0xbd, 0xe8, 0x37, 0x54, 0xe8, 0x7e, 0x95, 0xb1, 0xb4, 0xdf, 0x14, + 0xfb, 0xb5, 0xec, 0x67, 0xfb, 0xac, 0x18, 0xf7, 0x44, 0x02, 0xad, 0xf5, + 0xbc, 0xae, 0x2d, 0x40, 0xac, 0x8a, 0x7a, 0x2a, 0x35, 0xbc, 0xfe, 0xba, + 0x71, 0x9f, 0xdf, 0x1c, 0x87, 0xff, 0x92, 0xf1, 0xa9, 0x22, 0x90, 0xa3, + 0xab, 0x1f, 0x87, 0x05, 0x5e, 0xff, 0xba, 0xc4, 0x1c, 0xa8, 0x91, 0xb8, + 0xb5, 0xa4, 0xe1, 0xb4, 0x35, 0x27, 0x62, 0x64, 0x8f, 0x51, 0x86, 0xf7, + 0x2f, 0xd7, 0xe3, 0x33, 0x1d, 0x47, 0xef, 0xd5, 0xa6, 0xf4, 0xf1, 0x5e, + 0xe8, 0xff, 0x6f, 0x1f, 0x85, 0x38, 0x47, 0x7b, 0x68, 0x90, 0x31, 0x48, + 0xbc, 0x2b, 0x62, 0xce, 0x29, 0x63, 0xf9, 0x54, 0xe1, 0xb9, 0x47, 0x7e, + 0x5c, 0x0a, 0xe7, 0x1a, 0x36, 0x0f, 0xce, 0xc5, 0x30, 0xcb, 0xea, 0x36, + 0x7c, 0xf9, 0xe7, 0x67, 0x9c, 0xb3, 0xcc, 0xd1, 0x2b, 0x9c, 0x58, 0x4c, + 0x3f, 0x68, 0xfc, 0x4b, 0x27, 0xa2, 0xbe, 0x62, 0xc6, 0x56, 0x59, 0x17, + 0x3a, 0x5e, 0x3f, 0x69, 0x4d, 0x18, 0xf5, 0x68, 0xcc, 0xc8, 0xf3, 0x4c, + 0x07, 0xed, 0xdb, 0xc2, 0x23, 0xa6, 0xdc, 0x17, 0x9c, 0x89, 0xc7, 0x1c, + 0xb4, 0x15, 0xb7, 0xa1, 0xb7, 0xfe, 0xbd, 0x52, 0x81, 0xd2, 0x88, 0x33, + 0x38, 0x01, 0x3d, 0xbc, 0x5e, 0xa1, 0x1f, 0x56, 0xcd, 0x33, 0x65, 0x0a, + 0xde, 0x4e, 0x04, 0xcc, 0x40, 0x3e, 0x2e, 0x9d, 0xe2, 0xdc, 0xbd, 0x93, + 0x30, 0xda, 0x9f, 0xca, 0x9f, 0xff, 0x22, 0x3d, 0x35, 0xa7, 0x15, 0x7b, + 0x74, 0xbb, 0x37, 0x25, 0xf0, 0x9e, 0xa3, 0x01, 0xef, 0xed, 0x31, 0x8b, + 0x98, 0x8b, 0x89, 0x9d, 0xba, 0xdd, 0x5b, 0x12, 0x98, 0x74, 0xf2, 0xda, + 0x29, 0x73, 0x36, 0x31, 0x4d, 0xe5, 0xb5, 0xb0, 0xd8, 0x59, 0x4c, 0x63, + 0x7c, 0x2d, 0x8d, 0x78, 0xdd, 0xa5, 0xe3, 0xd0, 0x4a, 0x8c, 0x0a, 0xe6, + 0xba, 0x68, 0x72, 0x24, 0x75, 0x7f, 0xb3, 0xa3, 0x9e, 0x39, 0xaf, 0x5f, + 0x71, 0x19, 0xdf, 0x63, 0x5e, 0x2f, 0x6b, 0x61, 0x61, 0xda, 0xa4, 0x93, + 0x15, 0x76, 0x4c, 0x57, 0x23, 0x0a, 0xb1, 0xb0, 0x02, 0xb7, 0x6b, 0x1b, + 0x3e, 0xab, 0x46, 0xfa, 0x71, 0x7d, 0x83, 0xbb, 0xa9, 0x72, 0xbc, 0xa0, + 0x13, 0xc4, 0x3c, 0x11, 0xe6, 0x25, 0x06, 0xd4, 0xf2, 0x88, 0xe8, 0xc6, + 0xdf, 0x94, 0x1c, 0x13, 0x59, 0x35, 0x77, 0xdf, 0xd8, 0x3b, 0x25, 0x28, + 0x0d, 0x13, 0xab, 0x7e, 0xe2, 0xfb, 0xef, 0xd5, 0x3b, 0x5a, 0x22, 0x78, + 0xef, 0x32, 0xe4, 0xbf, 0x6d, 0x5b, 0x6e, 0x77, 0xe4, 0x83, 0x98, 0x3b, + 0x60, 0x59, 0x8c, 0x93, 0x3e, 0x28, 0xb3, 0x39, 0x1e, 0xfa, 0x1a, 0xe7, + 0x66, 0x4d, 0xfa, 0x0f, 0xd6, 0xe7, 0x9c, 0x36, 0x07, 0x70, 0x17, 0x47, + 0x3a, 0x6e, 0x79, 0xcb, 0xf8, 0xc0, 0x7a, 0x33, 0xc1, 0x5c, 0xd9, 0x90, + 0x67, 0x43, 0x73, 0xb0, 0xcd, 0x74, 0x36, 0x2f, 0x55, 0x14, 0xf4, 0x18, + 0xf3, 0xb4, 0x12, 0xc6, 0xa9, 0x6e, 0xfa, 0x75, 0xcc, 0x6b, 0x04, 0xf7, + 0x80, 0xe5, 0xd2, 0xeb, 0xd6, 0xb9, 0x22, 0x77, 0xde, 0x32, 0xd2, 0x20, + 0x58, 0x10, 0x6e, 0x7b, 0xca, 0x68, 0x41, 0x4f, 0x66, 0x10, 0xbd, 0x99, + 0x5c, 0x3f, 0x59, 0xcc, 0xf9, 0x98, 0x7e, 0xd6, 0xad, 0x2b, 0x8e, 0x08, + 0xf7, 0x3a, 0x73, 0xcb, 0x5e, 0x23, 0x8a, 0xcd, 0x99, 0x3b, 0x6f, 0x39, + 0xd5, 0xd0, 0xcf, 0xff, 0xb9, 0x3a, 0x43, 0xa8, 0xfc, 0xd8, 0x3a, 0x65, + 0x11, 0xe9, 0xa3, 0xe3, 0x96, 0xa7, 0x8c, 0x3b, 0x6f, 0x69, 0x5f, 0xf4, + 0x4d, 0x6c, 0xca, 0xb4, 0xff, 0xc9, 0x7e, 0xca, 0x59, 0xa7, 0x34, 0x72, + 0xa8, 0xed, 0x9a, 0xc0, 0x9d, 0xb7, 0xa4, 0x17, 0xf5, 0xb2, 0x8f, 0x55, + 0x8c, 0x2f, 0xb9, 0x3a, 0x51, 0xc6, 0xf6, 0x8f, 0xd3, 0x41, 0x49, 0x64, + 0xa2, 0x6d, 0x7e, 0xe0, 0x03, 0x6b, 0x5e, 0x5f, 0x91, 0xad, 0x03, 0x17, + 0x75, 0xf0, 0xa0, 0xe9, 0xcc, 0x06, 0x1c, 0xb6, 0x0e, 0x3a, 0x7c, 0xd4, + 0x41, 0x92, 0x3a, 0xc8, 0xd6, 0x18, 0xe1, 0x77, 0xa9, 0x83, 0x79, 0x63, + 0xeb, 0xd6, 0x95, 0x44, 0xe0, 0x74, 0x18, 0xaf, 0x3a, 0x9c, 0x9c, 0x0b, + 0x97, 0xb1, 0x8e, 0x7a, 0xbb, 0xf3, 0x96, 0x8b, 0x17, 0xd9, 0x3a, 0xff, + 0xb2, 0x3b, 0xb0, 0xc1, 0xde, 0x3b, 0xd7, 0x9d, 0x59, 0xc3, 0xa3, 0x99, + 0xc7, 0x7d, 0x3c, 0x7a, 0x98, 0xb3, 0xdc, 0x4c, 0x5d, 0x35, 0x71, 0x1c, + 0x2b, 0x28, 0xd7, 0x46, 0xfe, 0x6e, 0xe5, 0xef, 0x0e, 0xfe, 0x96, 0xf9, + 0x51, 0xcf, 0xca, 0x16, 0x3b, 0x2b, 0x9b, 0x83, 0xf2, 0x78, 0x88, 0x57, + 0x32, 0x26, 0xf7, 0x57, 0xae, 0x09, 0xc4, 0xd8, 0xc6, 0xfd, 0xa5, 0xb2, + 0x6f, 0xc8, 0x65, 0xc4, 0x7d, 0x4e, 0x88, 0x7c, 0x7a, 0x6b, 0x3b, 0xb2, + 0xc4, 0xde, 0xdf, 0xe7, 0xb0, 0x97, 0xb2, 0x55, 0x70, 0x7e, 0x5e, 0x58, + 0x34, 0x34, 0xc3, 0x63, 0xc0, 0xe7, 0x36, 0xe2, 0xcc, 0xf9, 0x13, 0xd4, + 0x81, 0xd8, 0xc9, 0x3d, 0xd4, 0x5f, 0x27, 0xeb, 0x1c, 0x65, 0x2c, 0xdb, + 0xcd, 0xfe, 0xed, 0xf5, 0xdb, 0xb0, 0xfd, 0x9c, 0x0c, 0xba, 0x79, 0x9c, + 0xed, 0xed, 0x35, 0x7e, 0x53, 0x76, 0xb4, 0x5e, 0xf6, 0x53, 0x3a, 0x31, + 0x6c, 0xcf, 0xbb, 0x42, 0x2e, 0x73, 0x11, 0x79, 0x82, 0x65, 0xfd, 0xd4, + 0x68, 0x9c, 0xef, 0xb0, 0xed, 0xea, 0x50, 0x9b, 0x3b, 0xe0, 0xc6, 0x90, + 0xbd, 0x06, 0x6e, 0x59, 0x45, 0xb6, 0x7d, 0x89, 0x2c, 0x75, 0xcd, 0x9b, + 0x68, 0x78, 0xeb, 0xd2, 0x1f, 0x90, 0x27, 0x8a, 0xfc, 0x73, 0x70, 0x92, + 0x31, 0x35, 0xaa, 0xc5, 0xdb, 0x45, 0xd6, 0x32, 0xc3, 0x19, 0xbe, 0x16, + 0xf1, 0x16, 0x27, 0xfb, 0x6b, 0x26, 0xa7, 0x3c, 0x95, 0xc7, 0xee, 0x7d, + 0x69, 0x3d, 0xb6, 0x5f, 0xc9, 0xf1, 0xd3, 0xde, 0xb1, 0x42, 0xfc, 0x09, + 0x92, 0xcf, 0x7a, 0xe0, 0x8c, 0xe8, 0xfe, 0x26, 0x47, 0x57, 0xd0, 0x05, + 0xfa, 0x58, 0xa9, 0xc8, 0x1b, 0xa7, 0xec, 0x82, 0xc7, 0x6e, 0x6d, 0x8d, + 0x8d, 0xd1, 0xf1, 0xf9, 0x2e, 0x78, 0xb4, 0xb5, 0xe9, 0x42, 0xec, 0xf2, + 0x68, 0x6d, 0x09, 0xf1, 0x77, 0x59, 0xab, 0x0f, 0xdb, 0xdc, 0xe3, 0x48, + 0xe6, 0xa5, 0x52, 0xd9, 0x8b, 0x47, 0xdf, 0xaf, 0x70, 0x1a, 0xb9, 0x76, + 0x35, 0xb6, 0xdb, 0xe2, 0xd0, 0x70, 0xce, 0x77, 0x75, 0xad, 0xc5, 0x21, + 0xfb, 0x5f, 0x89, 0x4a, 0xe9, 0x7c, 0xbd, 0x1c, 0x7e, 0x2d, 0x76, 0xd9, + 0xf8, 0xc5, 0x36, 0x4a, 0x81, 0x25, 0x89, 0x0b, 0xfb, 0x97, 0xfe, 0xa4, + 0xdf, 0xae, 0x2a, 0x15, 0x13, 0xf6, 0xb3, 0x92, 0x83, 0x99, 0x18, 0x06, + 0x53, 0x53, 0xf7, 0xe8, 0xe9, 0x87, 0xd8, 0xfe, 0x81, 0x38, 0xe7, 0x69, + 0xb6, 0x21, 0xfb, 0xf7, 0x64, 0xcf, 0xde, 0xd4, 0xfd, 0x7a, 0x22, 0x5b, + 0x65, 0x19, 0x81, 0x0d, 0x7b, 0x89, 0x7f, 0xd1, 0x16, 0xa9, 0x6f, 0x59, + 0xaf, 0xcd, 0x0b, 0x22, 0x3b, 0xcd, 0x89, 0xc1, 0xb9, 0xc0, 0x40, 0x52, + 0xf6, 0x53, 0x9d, 0x89, 0xad, 0x66, 0x1e, 0x19, 0xad, 0xae, 0xd3, 0xba, + 0x55, 0xd9, 0x0b, 0xf5, 0xc1, 0x97, 0x7b, 0x8c, 0x5a, 0xad, 0x47, 0xcd, + 0xee, 0x67, 0x7c, 0xd9, 0x0d, 0xcc, 0x2e, 0x13, 0x0c, 0xa8, 0x32, 0xa2, + 0xbd, 0x55, 0x98, 0x0b, 0x7f, 0xb5, 0x8d, 0xcb, 0xf1, 0x6f, 0xab, 0x46, + 0x70, 0xa5, 0xf0, 0x4a, 0xf5, 0x7d, 0x6b, 0x88, 0xdc, 0xe4, 0xee, 0xb9, + 0xff, 0xa7, 0x34, 0xbf, 0xee, 0xd4, 0x3e, 0x9d, 0xf3, 0xf2, 0xf3, 0x05, + 0xba, 0x3f, 0xad, 0x88, 0x8e, 0x84, 0x4b, 0x25, 0xb0, 0x95, 0x71, 0xf6, + 0xbf, 0xe6, 0x46, 0xb0, 0x8f, 0xff, 0x7f, 0x76, 0xa5, 0xec, 0x4d, 0xb5, + 0xac, 0x60, 0x60, 0x5e, 0xb8, 0x8a, 0x63, 0x78, 0x96, 0xf7, 0x7b, 0x33, + 0x6f, 0x59, 0xa7, 0xa6, 0x1b, 0xfd, 0xcb, 0x18, 0xec, 0x06, 0xc6, 0x75, + 0x6d, 0x52, 0xfd, 0xef, 0xee, 0x95, 0x83, 0xbb, 0x82, 0x63, 0xf9, 0x7e, + 0xa0, 0x4e, 0x4b, 0xaa, 0xa5, 0x65, 0xa2, 0xd7, 0x81, 0xf1, 0x57, 0xa6, + 0x3c, 0x3b, 0x28, 0xf0, 0x59, 0x7b, 0x5d, 0xa5, 0x77, 0x88, 0xbe, 0x3e, + 0xa4, 0x45, 0xe3, 0xd4, 0xbb, 0x7b, 0x1a, 0xc7, 0x7c, 0xf7, 0xdc, 0x2f, + 0xd9, 0xe3, 0xac, 0x36, 0x66, 0x72, 0x8c, 0x0a, 0xb4, 0xb9, 0xff, 0x99, + 0x5f, 0x7f, 0x6d, 0x24, 0xfb, 0x1a, 0xb2, 0x9a, 0xe8, 0x1b, 0x45, 0xac, + 0x73, 0xb5, 0xf9, 0xf0, 0x8c, 0xae, 0x7a, 0xdd, 0x77, 0x37, 0x6d, 0x34, + 0x34, 0xf7, 0xd7, 0x16, 0x6d, 0xda, 0xfc, 0x16, 0x47, 0x7d, 0x5b, 0xc2, + 0x8e, 0x55, 0x9c, 0x57, 0x23, 0x3a, 0x57, 0x79, 0xc7, 0x42, 0x4d, 0x20, + 0x3c, 0xd7, 0x1e, 0x3f, 0x70, 0x6b, 0x3a, 0x81, 0x6d, 0x29, 0x69, 0x53, + 0xc1, 0xb2, 0xc0, 0xdb, 0x96, 0x7f, 0x7a, 0x02, 0x5b, 0x32, 0x9f, 0xc4, + 0x4d, 0x07, 0xc9, 0x8d, 0xf5, 0xd6, 0x38, 0xf4, 0x68, 0xee, 0xd9, 0xd4, + 0x1c, 0x59, 0xdb, 0x96, 0xbd, 0x45, 0xb7, 0x24, 0x02, 0x70, 0x97, 0x13, + 0x83, 0xc7, 0x02, 0xf2, 0x2c, 0xd3, 0x8b, 0x6c, 0x8b, 0x94, 0xa9, 0xd5, + 0xc6, 0x90, 0x25, 0x73, 0x94, 0xb5, 0xd0, 0xfe, 0xb2, 0xdc, 0x3e, 0x09, + 0x1a, 0x5e, 0x8d, 0xae, 0xbd, 0x41, 0xae, 0xd7, 0x6c, 0x48, 0x1b, 0x0a, + 0xe6, 0x07, 0xa6, 0xa1, 0x6e, 0xe5, 0xab, 0xaf, 0x17, 0x05, 0x8a, 0x18, + 0x4f, 0xc4, 0xb7, 0x8c, 0x8d, 0xc7, 0xf0, 0x1b, 0x62, 0x90, 0xec, 0x19, + 0x4b, 0x4a, 0x3d, 0xb6, 0x35, 0x17, 0x69, 0xf1, 0x53, 0x43, 0xf6, 0x2f, + 0x5b, 0xd6, 0x35, 0x81, 0x37, 0xad, 0x68, 0x0d, 0xe5, 0x21, 0x5f, 0xcb, + 0xd5, 0x95, 0x32, 0xf9, 0xbd, 0x40, 0x4a, 0xe3, 0x2d, 0xa2, 0x93, 0x27, + 0xcd, 0x38, 0xb3, 0x01, 0xc1, 0xfd, 0x0f, 0x62, 0x6f, 0x19, 0x8a, 0xfd, + 0x8c, 0x71, 0x99, 0x52, 0xc9, 0x38, 0xea, 0xf4, 0x8f, 0xd8, 0xeb, 0x05, + 0x1d, 0xc4, 0x68, 0xe1, 0x97, 0x92, 0xf3, 0x39, 0xf1, 0x94, 0x51, 0x85, + 0x27, 0xb5, 0x1c, 0x57, 0x23, 0xd6, 0xe1, 0x07, 0x89, 0x79, 0x59, 0x7a, + 0x08, 0x39, 0xaf, 0xd1, 0x7e, 0x46, 0xf9, 0x0d, 0xfd, 0x1c, 0x78, 0x21, + 0xbd, 0x11, 0x0f, 0xca, 0x1a, 0xa2, 0x52, 0xdb, 0x5c, 0xe7, 0x90, 0xfe, + 0x36, 0x62, 0x6b, 0x46, 0xda, 0xfa, 0x20, 0xb6, 0xd7, 0xd8, 0x9d, 0x97, + 0x55, 0xb0, 0xfc, 0x83, 0xd8, 0x53, 0xc6, 0xe3, 0xf6, 0xdc, 0xc9, 0x73, + 0xaf, 0x5e, 0x53, 0x30, 0xaf, 0x14, 0x2a, 0xf3, 0x06, 0x87, 0x71, 0x33, + 0x1c, 0x55, 0xdf, 0xa4, 0xed, 0xc9, 0xbe, 0x9a, 0xaf, 0xc2, 0x59, 0xe5, + 0xa2, 0x6f, 0xde, 0x0a, 0x57, 0x95, 0x70, 0xf5, 0x02, 0x8f, 0x8e, 0xf2, + 0xbe, 0xe8, 0x36, 0xdc, 0x26, 0xba, 0x75, 0x12, 0x87, 0x7a, 0x24, 0xaf, + 0x33, 0x2a, 0xa9, 0x23, 0xbd, 0x95, 0x9c, 0x1e, 0xe5, 0xc4, 0x4c, 0xc6, + 0x47, 0x37, 0xf3, 0xb7, 0xb6, 0x77, 0xa9, 0xf7, 0x79, 0x7d, 0x65, 0xe4, + 0xf0, 0x96, 0xf5, 0x3e, 0x39, 0xfc, 0xfc, 0x40, 0x5d, 0xd6, 0x20, 0x4e, + 0xe1, 0x06, 0xbd, 0x39, 0x4e, 0xbc, 0x59, 0x6d, 0x9c, 0xb1, 0x62, 0xab, + 0xa4, 0x8c, 0xee, 0x8b, 0x29, 0x85, 0x3e, 0x16, 0xc0, 0x3f, 0xcd, 0x82, + 0x2b, 0x22, 0xcf, 0x14, 0x64, 0xbd, 0xb8, 0x51, 0x9e, 0xf5, 0xb5, 0xc8, + 0xf8, 0x5d, 0xb2, 0xee, 0x86, 0xe8, 0x84, 0x0b, 0x46, 0x76, 0x9f, 0xcc, + 0xd9, 0x0c, 0x0b, 0x81, 0x85, 0xbf, 0x67, 0x2e, 0x24, 0xf3, 0x53, 0x9b, + 0xad, 0x57, 0xb2, 0x41, 0x1f, 0x39, 0xfd, 0xa3, 0xd0, 0x5b, 0x12, 0xd4, + 0x75, 0x53, 0x48, 0x9e, 0xdf, 0x3b, 0x7d, 0x09, 0xd8, 0x3c, 0xde, 0x3c, + 0x89, 0xcf, 0xa1, 0x9c, 0xb9, 0xeb, 0xdc, 0xb1, 0x15, 0xa8, 0xa8, 0x8a, + 0xfa, 0x4a, 0x71, 0x19, 0xcf, 0xd7, 0x30, 0x3f, 0xf9, 0x22, 0x2a, 0x56, + 0xb6, 0x22, 0xc1, 0xb1, 0x97, 0x1b, 0x7f, 0xc5, 0x6b, 0xf7, 0x21, 0x99, + 0x72, 0x71, 0x1c, 0x3f, 0xb1, 0x2a, 0x6a, 0x44, 0x36, 0xd3, 0x5b, 0x66, + 0x30, 0x9f, 0xb6, 0x75, 0x41, 0xdc, 0x4e, 0x09, 0x47, 0xaa, 0x8b, 0xae, + 0x07, 0x73, 0xfb, 0x1a, 0xbd, 0x75, 0x8d, 0xd2, 0x41, 0x9b, 0xed, 0xa1, + 0xce, 0xa5, 0xac, 0x65, 0x2d, 0x0f, 0x9c, 0xa6, 0x8e, 0x3b, 0x78, 0x6e, + 0xf8, 0xdf, 0x84, 0x7a, 0x59, 0x31, 0x4e, 0x58, 0x71, 0xcd, 0x47, 0xbb, + 0x54, 0x57, 0x09, 0x9f, 0x5a, 0x1a, 0x7a, 0x8f, 0xf7, 0xb5, 0xbc, 0x9d, + 0x9e, 0xb9, 0x25, 0xa7, 0xcb, 0x30, 0x75, 0xf9, 0x6f, 0xf6, 0x75, 0x87, + 0x7d, 0xbd, 0x23, 0x7f, 0xfd, 0xcc, 0x2d, 0x3d, 0xc6, 0xcb, 0xbc, 0xde, + 0x4b, 0xdd, 0xab, 0x17, 0x49, 0xfd, 0x75, 0xa6, 0xd4, 0x67, 0x4a, 0x65, + 0xf4, 0xe4, 0xe7, 0xe3, 0x50, 0x7e, 0x3e, 0x26, 0xf2, 0x6d, 0x38, 0xd9, + 0x46, 0x3c, 0x5a, 0x0a, 0x13, 0x65, 0x01, 0xc1, 0x79, 0x91, 0x8b, 0x73, + 0x97, 0x11, 0xb9, 0xd6, 0x30, 0xde, 0x75, 0x3d, 0x53, 0x8a, 0x78, 0xc7, + 0x4c, 0xdb, 0x0e, 0xcf, 0xdc, 0x22, 0xfb, 0xde, 0xde, 0x52, 0x1a, 0x7d, + 0xb2, 0x65, 0x23, 0x45, 0x2e, 0x7b, 0xaf, 0xe9, 0x0c, 0xd7, 0x3b, 0xe6, + 0x65, 0x8b, 0x61, 0xc4, 0xce, 0x28, 0x2e, 0x8f, 0xe0, 0x43, 0x22, 0xdd, + 0xc8, 0xcc, 0x2b, 0x1e, 0x64, 0xce, 0x14, 0xcc, 0x50, 0xb7, 0x6d, 0x44, + 0xec, 0x43, 0xf6, 0xde, 0x37, 0xe7, 0xc4, 0x0a, 0x34, 0xea, 0x0e, 0xcc, + 0x0b, 0xcf, 0x64, 0xe6, 0x45, 0xbb, 0x34, 0x8b, 0x1d, 0xba, 0xff, 0x7a, + 0x2c, 0xb7, 0xeb, 0xed, 0x4b, 0x67, 0xdb, 0x4b, 0x39, 0xa7, 0x8f, 0x51, + 0x8e, 0x6d, 0x01, 0x91, 0xe3, 0x9b, 0x79, 0x39, 0x5a, 0x19, 0x4b, 0x4d, + 0xed, 0xda, 0x40, 0xef, 0x59, 0xbd, 0x3d, 0x63, 0xeb, 0xed, 0x3e, 0x9e, + 0x17, 0x33, 0xbf, 0x2f, 0xc2, 0xd1, 0x7a, 0x6f, 0x7e, 0x1f, 0x9b, 0xe4, + 0x6a, 0x82, 0xbf, 0x0d, 0x7f, 0xbd, 0xda, 0xd0, 0xc3, 0x0e, 0x9b, 0xd7, + 0xbb, 0x11, 0xb7, 0x39, 0xb3, 0x3c, 0xf3, 0xae, 0xc0, 0x23, 0x76, 0x39, + 0x17, 0x75, 0x52, 0x86, 0x47, 0xf3, 0xfe, 0x22, 0x7b, 0x0e, 0x1e, 0xb3, + 0x7f, 0xef, 0xe6, 0xdc, 0xba, 0xe8, 0xab, 0x85, 0x18, 0x25, 0xeb, 0xed, + 0xff, 0xc3, 0xf6, 0xfd, 0x21, 0x1c, 0xb7, 0xff, 0x67, 0x73, 0xf9, 0x16, + 0x7a, 0x4c, 0xd9, 0x3b, 0x53, 0x86, 0x6e, 0x7b, 0x0f, 0xb9, 0xac, 0x01, + 0x5c, 0x89, 0xcd, 0x9a, 0xac, 0x07, 0x93, 0xfb, 0x68, 0x62, 0x13, 0x9d, + 0x48, 0x6a, 0xa6, 0x37, 0x53, 0x3f, 0x35, 0x57, 0x32, 0xb1, 0xa7, 0xfe, + 0x03, 0x2b, 0x6a, 0xe7, 0x4f, 0x27, 0xac, 0xbd, 0xc6, 0xd1, 0x10, 0x3d, + 0xb8, 0xbd, 0xc8, 0xd6, 0x6f, 0xb8, 0xcd, 0xde, 0xff, 0x47, 0x99, 0x9f, + 0x49, 0x48, 0x1c, 0x9d, 0x83, 0xb4, 0x69, 0xc7, 0xe2, 0x96, 0xed, 0x9c, + 0x93, 0x9e, 0x54, 0x20, 0x7a, 0x09, 0xef, 0x4d, 0x30, 0x96, 0x75, 0x53, + 0x9f, 0xb1, 0x16, 0xe1, 0x67, 0x6b, 0xb0, 0x9b, 0x36, 0x36, 0x6e, 0x5a, + 0xd6, 0x3e, 0x62, 0x44, 0xe5, 0x3c, 0x15, 0xd9, 0x9a, 0x35, 0x48, 0x31, + 0x36, 0xed, 0x33, 0x1a, 0x3f, 0x57, 0x84, 0xb8, 0xdf, 0x0d, 0xdd, 0xb7, + 0x85, 0xa3, 0xb9, 0x97, 0xf3, 0x75, 0xd4, 0x14, 0xde, 0xe8, 0x3c, 0xb3, + 0x14, 0x46, 0x78, 0xb1, 0xe3, 0x27, 0xd6, 0xa4, 0xfd, 0xec, 0xb8, 0xeb, + 0x5f, 0x28, 0xc3, 0x46, 0x71, 0xde, 0x4a, 0xce, 0xf1, 0xbb, 0x01, 0x79, + 0x7e, 0x0d, 0xd4, 0xf5, 0x35, 0xb6, 0x8b, 0x0c, 0x7b, 0x43, 0xce, 0xd8, + 0x3e, 0x04, 0x5a, 0x36, 0x28, 0xe7, 0x72, 0x83, 0x4b, 0xc6, 0x4c, 0x8c, + 0xd6, 0x3f, 0x4b, 0x1e, 0x23, 0xf5, 0x8b, 0xf1, 0x84, 0xf9, 0xb4, 0x55, + 0x3b, 0xe3, 0xfb, 0xd6, 0x7e, 0x43, 0x5d, 0x4f, 0x6d, 0xc7, 0xca, 0xd9, + 0x56, 0x19, 0xdb, 0xba, 0x3d, 0xa0, 0x9b, 0xdb, 0xd9, 0xd6, 0xf1, 0xc4, + 0xd1, 0xa0, 0x9b, 0x6d, 0x3d, 0x6a, 0x4a, 0x6e, 0xe0, 0x6c, 0x6e, 0xe6, + 0xdc, 0x76, 0xa5, 0x02, 0xbe, 0xad, 0x94, 0x4b, 0xf2, 0xb7, 0xaf, 0x26, + 0xe4, 0x5d, 0x8f, 0x6f, 0x72, 0x3c, 0xd1, 0x8d, 0x2e, 0x34, 0xde, 0x5b, + 0x41, 0xfb, 0xa9, 0x44, 0xc1, 0xd6, 0x75, 0x1f, 0xf1, 0x0e, 0xb7, 0xb3, + 0xcc, 0xeb, 0x81, 0x39, 0x78, 0x21, 0xd4, 0xb8, 0x72, 0x0e, 0x9c, 0xe4, + 0x21, 0x81, 0xe6, 0x0d, 0x4a, 0x5c, 0x13, 0x5b, 0xbc, 0x2d, 0xad, 0x07, + 0x9b, 0x20, 0xd8, 0xdd, 0x4a, 0x7d, 0xcc, 0xc1, 0xfb, 0x0b, 0x45, 0x2e, + 0x67, 0x38, 0xe8, 0x08, 0x74, 0x3c, 0xcd, 0xf9, 0xad, 0x98, 0x97, 0xcb, + 0x53, 0x33, 0xf6, 0x7e, 0xcd, 0x56, 0x24, 0x33, 0x27, 0xde, 0xdd, 0x6b, + 0xc0, 0x79, 0xa8, 0xfe, 0x41, 0x0b, 0xf6, 0xbb, 0x21, 0x8d, 0x32, 0x0f, + 0xad, 0x32, 0x0f, 0xa5, 0xf4, 0xa7, 0x6b, 0x28, 0xf7, 0x7a, 0x5b, 0xee, + 0x39, 0x18, 0x36, 0x65, 0xfd, 0xcb, 0xa9, 0xdd, 0x86, 0x5e, 0x62, 0x67, + 0xe0, 0x4c, 0x17, 0xfb, 0x79, 0x9d, 0x32, 0xcf, 0xa3, 0xde, 0x27, 0x5b, + 0x84, 0xb7, 0xde, 0x87, 0xbe, 0x54, 0xe1, 0xdd, 0x11, 0x05, 0xe9, 0x80, + 0xf4, 0x71, 0x1f, 0x79, 0x5c, 0x97, 0x35, 0x59, 0x23, 0xd7, 0x77, 0x33, + 0xf7, 0x8f, 0x6a, 0xf4, 0x07, 0xea, 0x1d, 0xfa, 0x1c, 0xe8, 0x13, 0x6f, + 0x38, 0xa2, 0xf4, 0x01, 0xd3, 0x7b, 0x86, 0xd8, 0x70, 0x08, 0x1d, 0x16, + 0xaa, 0x6c, 0x7b, 0xf8, 0xd9, 0x88, 0xf1, 0xa1, 0x22, 0xb1, 0x3d, 0x4b, + 0x1d, 0xa8, 0x9c, 0x13, 0xd1, 0x41, 0x39, 0x7d, 0x76, 0x2c, 0xa0, 0xfb, + 0x5f, 0xa0, 0x3c, 0xdb, 0x29, 0xcf, 0x8a, 0xdc, 0x1c, 0xfa, 0x36, 0x2b, + 0xe2, 0xd3, 0x81, 0x96, 0xd5, 0xbc, 0xbe, 0x8d, 0xf2, 0x04, 0xfa, 0x14, + 0x0c, 0xb5, 0xf4, 0x90, 0x2b, 0x76, 0x50, 0x07, 0xe7, 0xe4, 0x71, 0xdb, + 0x73, 0xd6, 0x41, 0x2e, 0x50, 0x8c, 0xbd, 0xa6, 0xe0, 0xb7, 0x86, 0x61, + 0xda, 0xe9, 0x1e, 0xce, 0x48, 0xd4, 0xab, 0xa2, 0xd8, 0x10, 0x0c, 0xa8, + 0xe1, 0x35, 0x17, 0xe7, 0xa6, 0x12, 0xfb, 0xb5, 0xdd, 0xf6, 0x5e, 0xe5, + 0x1c, 0xb7, 0xfb, 0x83, 0x35, 0xea, 0x15, 0x7e, 0x26, 0xeb, 0x63, 0xb2, + 0x86, 0xd4, 0xeb, 0xc9, 0xed, 0xd7, 0x72, 0x51, 0x27, 0xb9, 0xeb, 0xcf, + 0x68, 0xc2, 0x7d, 0x0b, 0xe5, 0x7f, 0x69, 0x3d, 0x69, 0x97, 0x97, 0x72, + 0x2e, 0x9b, 0xa3, 0x97, 0xda, 0xe5, 0x7e, 0x69, 0x3d, 0xab, 0x39, 0xa7, + 0x94, 0x2b, 0x3c, 0x2f, 0x3c, 0xfa, 0x0d, 0x27, 0x31, 0xaf, 0x78, 0xee, + 0x62, 0x1c, 0x33, 0x4e, 0xd4, 0x9e, 0xac, 0xef, 0x64, 0x1c, 0x9b, 0xba, + 0x7f, 0xcb, 0xc2, 0xe3, 0x76, 0x1e, 0xde, 0x45, 0x3e, 0x7b, 0x74, 0x47, + 0x11, 0x84, 0xa3, 0xca, 0xfa, 0x5d, 0x73, 0xd9, 0xb9, 0x5c, 0x56, 0xf6, + 0x35, 0x5d, 0x66, 0x73, 0xc3, 0xa8, 0x2a, 0xb8, 0xfb, 0x49, 0x7b, 0xf8, + 0x84, 0xbb, 0x74, 0x62, 0x8f, 0x51, 0xe0, 0x2c, 0x47, 0x1f, 0x54, 0x89, + 0x93, 0x03, 0xe6, 0x62, 0x89, 0xcd, 0x7e, 0xd6, 0x0f, 0xc6, 0xd4, 0xa9, + 0xdc, 0xe6, 0x76, 0x0f, 0x2a, 0xba, 0xb6, 0x3a, 0x20, 0xfb, 0x47, 0x65, + 0x2f, 0xa8, 0xf4, 0x55, 0x92, 0x5f, 0x97, 0xfa, 0x38, 0xae, 0x51, 0xe8, + 0x4b, 0xf8, 0xc6, 0xfb, 0xa5, 0x85, 0x7d, 0x86, 0x51, 0x5b, 0xce, 0x5f, + 0x59, 0x2b, 0xb5, 0xec, 0x4c, 0x0d, 0xe7, 0xcb, 0x1e, 0xcd, 0xcb, 0x1e, + 0xfb, 0xd8, 0x75, 0xb5, 0xa9, 0xfb, 0xee, 0x82, 0xf9, 0xe7, 0x5d, 0xf2, + 0x0c, 0x46, 0xd6, 0x5c, 0xe5, 0x9e, 0x82, 0x2e, 0xe2, 0x50, 0x54, 0x6b, + 0x64, 0x9c, 0xd7, 0x7d, 0x6b, 0x39, 0x1f, 0x71, 0xaf, 0xec, 0x51, 0x2f, + 0xc4, 0xc8, 0x62, 0xe4, 0xd6, 0x3e, 0x65, 0x9f, 0x45, 0x6e, 0xbd, 0x93, + 0x76, 0x8f, 0xae, 0xf4, 0xef, 0xad, 0xac, 0xd7, 0xc9, 0x58, 0x78, 0x6e, + 0x7f, 0xf4, 0x10, 0xf5, 0x3a, 0xcc, 0x7b, 0x9b, 0xcf, 0xae, 0xa7, 0xc8, + 0x9a, 0x92, 0xc4, 0xde, 0xdf, 0x59, 0x6d, 0xe7, 0x95, 0x9d, 0xba, 0x57, + 0xbc, 0x26, 0x26, 0xcf, 0xdc, 0x46, 0xf3, 0xeb, 0xee, 0x4d, 0x1f, 0x79, + 0xe6, 0x36, 0x41, 0x5b, 0x42, 0x74, 0x33, 0xb9, 0x5d, 0x1c, 0x3d, 0x18, + 0x4d, 0xd4, 0x69, 0x5b, 0xa0, 0xc9, 0x7a, 0x33, 0xff, 0x7a, 0xb0, 0x3f, + 0x81, 0x68, 0xd1, 0xa5, 0x95, 0xe4, 0x5b, 0x88, 0x3a, 0x18, 0xa3, 0x1e, + 0x4d, 0xd4, 0x35, 0x6f, 0xe3, 0x98, 0xfc, 0x2b, 0x7b, 0x30, 0x9c, 0x68, + 0xfc, 0x2b, 0xc6, 0x11, 0x7f, 0x99, 0xcd, 0x75, 0xe2, 0x7f, 0xbd, 0x97, + 0x38, 0xb0, 0x29, 0xbf, 0xe6, 0xd5, 0x96, 0xf8, 0x35, 0xe5, 0xb7, 0x85, + 0x64, 0xbd, 0x4f, 0x2a, 0x37, 0xc1, 0x3c, 0xff, 0x04, 0xd6, 0xf5, 0x2b, + 0x78, 0xd2, 0x38, 0x81, 0xb5, 0x43, 0x22, 0xcf, 0x09, 0xac, 0xe9, 0x7f, + 0x09, 0x7b, 0xfa, 0x67, 0xa0, 0xc9, 0xd6, 0x4d, 0x07, 0x36, 0xec, 0x3c, + 0x88, 0xed, 0x29, 0x0b, 0xdb, 0x42, 0x1e, 0xac, 0x7f, 0x58, 0xc1, 0xf2, + 0xc0, 0x61, 0x6c, 0xd9, 0x69, 0xe1, 0xe2, 0x50, 0x27, 0x9a, 0xcd, 0x32, + 0x14, 0x57, 0xcd, 0x6b, 0x57, 0x59, 0xae, 0x6d, 0xb8, 0x23, 0xbf, 0x2f, + 0x79, 0x3f, 0xb1, 0x40, 0x85, 0xcf, 0x90, 0x3d, 0xc7, 0x51, 0xe5, 0xa6, + 0x4c, 0x93, 0xd2, 0x9a, 0x7f, 0x66, 0x79, 0x7d, 0xa6, 0xa8, 0x02, 0xa5, + 0x71, 0xec, 0x09, 0x9d, 0xc0, 0xd0, 0xd0, 0x07, 0xe5, 0x39, 0x7f, 0x99, + 0x20, 0x77, 0x90, 0x9c, 0xc3, 0xa4, 0x4d, 0x7d, 0xd2, 0xfb, 0x40, 0x62, + 0x77, 0x93, 0xf8, 0xe9, 0xe0, 0x49, 0x9c, 0x1c, 0xfc, 0x37, 0x2c, 0xd1, + 0x24, 0x7f, 0xb4, 0x3a, 0x9d, 0x11, 0xcb, 0xda, 0xd5, 0x10, 0xb7, 0x6a, + 0x8c, 0x5f, 0xb0, 0xed, 0x0a, 0x4c, 0x8f, 0xbc, 0x88, 0x6d, 0x1a, 0xdb, + 0x4a, 0xed, 0xc7, 0x0e, 0xc6, 0x75, 0x5f, 0xe4, 0x66, 0xf8, 0x52, 0x59, + 0xb3, 0x1a, 0xd1, 0x1d, 0xd5, 0xd0, 0x37, 0x56, 0x39, 0x8c, 0x8e, 0x7f, + 0x55, 0xea, 0x71, 0x7d, 0xe6, 0x24, 0x7e, 0x3e, 0x68, 0xef, 0xa5, 0x6a, + 0xfd, 0xae, 0x62, 0x75, 0x6e, 0x0b, 0xe9, 0xcd, 0xff, 0x43, 0x89, 0xc6, + 0x4b, 0x69, 0x53, 0x25, 0xcc, 0x09, 0x6e, 0x18, 0x94, 0x1c, 0xb1, 0x15, + 0xee, 0x3e, 0x3d, 0xbb, 0x94, 0x3c, 0xfb, 0xee, 0x05, 0xf1, 0x99, 0xd3, + 0x68, 0x97, 0x0e, 0x45, 0x0f, 0x1a, 0x6a, 0x27, 0x8e, 0x98, 0xfa, 0xc4, + 0xef, 0x1c, 0xc6, 0xd0, 0x77, 0x50, 0x8f, 0x55, 0x19, 0x7d, 0xe8, 0x32, + 0xe6, 0x61, 0x5b, 0x92, 0x26, 0x52, 0x49, 0xbd, 0xb5, 0xc3, 0xd1, 0x8b, + 0x3b, 0x02, 0xb5, 0x1b, 0xdf, 0x25, 0x97, 0xf3, 0x10, 0x53, 0x92, 0xe3, + 0x23, 0xcc, 0x5f, 0x7b, 0xb1, 0xe1, 0xe1, 0x08, 0xd6, 0xef, 0x32, 0xd1, + 0x93, 0x1c, 0xa1, 0x6c, 0x3f, 0x2c, 0x97, 0xbd, 0x34, 0x2d, 0xa1, 0xf8, + 0xb5, 0x2a, 0x02, 0x51, 0xf6, 0xd9, 0xa8, 0x46, 0x02, 0x7e, 0x55, 0x61, + 0xf4, 0x1f, 0x77, 0xa2, 0x9b, 0x65, 0xfa, 0x52, 0xb4, 0xb9, 0xa4, 0x9b, + 0xf1, 0x72, 0x16, 0x86, 0xc7, 0x7c, 0xd8, 0x37, 0xe6, 0xc1, 0xd0, 0x98, + 0xc6, 0xa3, 0x14, 0x0f, 0x0d, 0xc8, 0x9e, 0x14, 0x2f, 0x9e, 0xd8, 0xeb, + 0xc6, 0xa6, 0x07, 0x3c, 0x98, 0x13, 0x99, 0x8e, 0xbd, 0x7b, 0x4b, 0xb1, + 0x9b, 0xd7, 0xab, 0x16, 0xfa, 0xf1, 0x38, 0xaf, 0xf7, 0x3f, 0xe0, 0xe2, + 0x3c, 0x5c, 0x8c, 0x03, 0x34, 0xec, 0xa1, 0xb1, 0x32, 0xa4, 0x06, 0x68, + 0xf2, 0xe4, 0xac, 0x6f, 0x31, 0xc3, 0x18, 0xdd, 0xcb, 0xd8, 0xf8, 0xb0, + 0x89, 0x04, 0xfb, 0xd9, 0x4e, 0x5d, 0xf5, 0x10, 0xd7, 0x36, 0x8c, 0x09, + 0xc6, 0xaf, 0xc2, 0x35, 0x7d, 0x7a, 0x73, 0x93, 0x62, 0x44, 0x17, 0xd9, + 0xfb, 0xb4, 0xe4, 0xbd, 0xad, 0x55, 0x68, 0x4c, 0xe8, 0x66, 0x13, 0x3a, + 0x71, 0x8c, 0xe3, 0xfe, 0x7f, 0xe8, 0xb7, 0x8b, 0x1d, 0x7a, 0xef, 0xd5, + 0xea, 0x41, 0xec, 0xc8, 0x1c, 0x22, 0x57, 0x07, 0xc2, 0x7b, 0x0e, 0x92, + 0xbf, 0x1d, 0x21, 0xfe, 0xbc, 0x6e, 0xf9, 0x0c, 0x15, 0xd7, 0xdf, 0x6f, + 0x84, 0xdf, 0x53, 0x02, 0x1b, 0x7f, 0x45, 0x1d, 0x7c, 0x7e, 0xaf, 0x8a, + 0xeb, 0x76, 0x2c, 0x46, 0x3a, 0x14, 0xc5, 0xf6, 0x45, 0x2a, 0xae, 0x7d, + 0xf8, 0x20, 0x71, 0x7f, 0xc2, 0xe6, 0xc9, 0xd9, 0xf4, 0x7d, 0x08, 0xf6, + 0xc9, 0x9a, 0xbc, 0x9b, 0xf1, 0xbb, 0x1c, 0xc7, 0xfb, 0x3b, 0xe9, 0xb7, + 0xe5, 0x38, 0x3a, 0x74, 0x90, 0xf6, 0x58, 0x8e, 0x23, 0xfd, 0xc6, 0xc4, + 0x4f, 0x1d, 0xe5, 0x78, 0x82, 0xe7, 0x3b, 0x78, 0xbe, 0x70, 0xc0, 0xe8, + 0xef, 0x50, 0xcb, 0xb1, 0x60, 0x4f, 0x03, 0xfa, 0x93, 0x62, 0x9b, 0x1a, + 0x36, 0x8e, 0xd5, 0xe7, 0x75, 0x2f, 0x3a, 0xf7, 0xe2, 0x4e, 0xea, 0xea, + 0x8e, 0x1d, 0x9d, 0xec, 0xcf, 0x47, 0x9d, 0x1f, 0xc4, 0x43, 0xcc, 0xeb, + 0xb6, 0x25, 0x7d, 0x38, 0x9d, 0x32, 0xfc, 0x5f, 0x52, 0x0c, 0xb3, 0x44, + 0x09, 0x68, 0xc7, 0xe1, 0xc3, 0xc9, 0x4c, 0x29, 0xba, 0x07, 0x66, 0xe1, + 0xa7, 0xb4, 0xcf, 0x07, 0x1f, 0x90, 0xfe, 0x26, 0x18, 0x1f, 0x66, 0xe3, + 0x89, 0x11, 0x93, 0x6d, 0xcb, 0x3c, 0x49, 0xcc, 0xe9, 0x81, 0x2b, 0x25, + 0xbe, 0x11, 0xdd, 0x41, 0xb3, 0x20, 0x26, 0x1e, 0x46, 0xa6, 0x5f, 0xef, + 0xbd, 0x41, 0x15, 0x5e, 0xad, 0x52, 0x97, 0x0e, 0x4c, 0x6a, 0x7a, 0xbc, + 0x4a, 0x8d, 0xf7, 0x33, 0x7f, 0x8d, 0x57, 0xab, 0x87, 0xf1, 0x44, 0xbf, + 0x13, 0xf3, 0x16, 0xaa, 0xbc, 0x1e, 0x3f, 0xc3, 0xd8, 0x16, 0x9f, 0xa3, + 0x9a, 0xd8, 0x6d, 0xcb, 0x8a, 0x78, 0x11, 0xb9, 0x7d, 0xe5, 0xc2, 0x5a, + 0xc6, 0x2f, 0x87, 0xd8, 0x5e, 0xac, 0x5c, 0x75, 0x52, 0xef, 0x27, 0x31, + 0x42, 0xbb, 0x7e, 0x94, 0xc7, 0x81, 0x41, 0xab, 0x73, 0x39, 0x39, 0xf7, + 0xc5, 0x01, 0xab, 0xf3, 0x06, 0xd3, 0xf0, 0x15, 0xa9, 0x81, 0xe8, 0xdd, + 0x38, 0x89, 0xfd, 0x23, 0x52, 0x06, 0x6e, 0x6f, 0x84, 0x79, 0x75, 0xd2, + 0xea, 0xdc, 0x61, 0x5e, 0x8c, 0x06, 0x3b, 0x37, 0xfe, 0x55, 0x79, 0x0e, + 0x33, 0xc5, 0x8f, 0x64, 0x0d, 0x64, 0x12, 0xbf, 0x62, 0x3b, 0xef, 0x0d, + 0x56, 0x62, 0x5a, 0xb5, 0xf8, 0xc1, 0x09, 0xbc, 0xdd, 0xff, 0x22, 0x4e, + 0xf7, 0x5b, 0x58, 0x10, 0xb2, 0xe0, 0x0c, 0xd5, 0x99, 0x4d, 0xea, 0x65, + 0xc4, 0x08, 0x05, 0xd7, 0xcc, 0x7d, 0x09, 0xef, 0xd0, 0xff, 0xaf, 0x9d, + 0x6b, 0xd9, 0xb2, 0xf4, 0x61, 0xa1, 0xb5, 0xbd, 0x46, 0xfc, 0xc6, 0xb4, + 0xf7, 0xf5, 0x7c, 0x72, 0x1e, 0x5c, 0xd8, 0xb7, 0x26, 0xb9, 0xf0, 0x49, + 0x0c, 0x0f, 0x1a, 0xd1, 0x75, 0x05, 0x39, 0xfb, 0x4f, 0x52, 0x07, 0x16, + 0x76, 0x98, 0x47, 0x1f, 0xae, 0xc2, 0xbc, 0x33, 0xcc, 0x1a, 0xaf, 0x98, + 0x43, 0xdb, 0x59, 0xb0, 0x30, 0x60, 0x2e, 0x53, 0xdf, 0xa4, 0x9f, 0x9e, + 0xc4, 0xbe, 0xa1, 0x02, 0x5e, 0xfb, 0xd0, 0x44, 0x3f, 0xcf, 0xed, 0x65, + 0xf7, 0xa2, 0x31, 0x75, 0xc8, 0x5e, 0x7f, 0x38, 0x40, 0x7c, 0xcc, 0x3d, + 0xd3, 0xd4, 0x30, 0x92, 0x69, 0x22, 0x36, 0x44, 0xf1, 0xcf, 0x99, 0x08, + 0xf1, 0x21, 0x4c, 0x7c, 0x68, 0x20, 0x3e, 0x98, 0xc4, 0x87, 0x7a, 0xe2, + 0x43, 0xd0, 0x7e, 0xd6, 0x2f, 0x6b, 0xe6, 0x43, 0xa3, 0x2f, 0xa2, 0x68, + 0xe0, 0x04, 0x5c, 0xf4, 0x81, 0xe3, 0xa6, 0x45, 0x7e, 0x52, 0xa7, 0xad, + 0xc1, 0xc5, 0x4a, 0x54, 0xf3, 0x62, 0x28, 0x73, 0x02, 0x25, 0x03, 0x1a, + 0xc7, 0x22, 0xfb, 0x33, 0x6a, 0xc3, 0xbd, 0xc4, 0xea, 0x5f, 0x1b, 0x75, + 0xbd, 0x5e, 0xd4, 0xed, 0xae, 0x81, 0xd1, 0xbf, 0x50, 0x9d, 0xab, 0x44, + 0xbf, 0xe0, 0xe5, 0x38, 0xab, 0x31, 0xfb, 0x01, 0x0d, 0x73, 0x78, 0xfc, + 0x53, 0xaa, 0x76, 0xe2, 0x75, 0x07, 0xbc, 0x33, 0x48, 0x77, 0x66, 0x92, + 0x09, 0x90, 0xd5, 0x7a, 0x7d, 0xb8, 0xe4, 0xc0, 0x49, 0x55, 0x41, 0xf6, + 0x0b, 0x12, 0xf3, 0xea, 0x82, 0x3d, 0xaa, 0x2a, 0x6b, 0x48, 0xc4, 0x70, + 0x1e, 0x2a, 0x22, 0x64, 0x11, 0xb3, 0x98, 0x5f, 0x58, 0x6b, 0xcc, 0x12, + 0x6c, 0xae, 0x57, 0x65, 0x6f, 0xc8, 0x21, 0x89, 0x51, 0x33, 0x18, 0x23, + 0x4a, 0x93, 0xf1, 0xdb, 0x66, 0xc0, 0x83, 0x92, 0xa4, 0x65, 0x3d, 0x16, + 0xd2, 0xe0, 0x89, 0x04, 0xa2, 0x1b, 0x98, 0x46, 0x7e, 0x61, 0x5e, 0x18, + 0xd7, 0x64, 0x0e, 0x60, 0x80, 0xe3, 0x5b, 0x9e, 0x29, 0xbc, 0xe3, 0xf9, + 0xc9, 0x7f, 0xe7, 0xde, 0x15, 0xbd, 0x64, 0xf7, 0x0c, 0x18, 0xda, 0x5d, + 0x6a, 0xbc, 0x92, 0x1c, 0xfc, 0x00, 0xe3, 0x9e, 0x32, 0x79, 0xa3, 0x82, + 0xd6, 0x81, 0x38, 0xa6, 0x85, 0x7e, 0xa0, 0xc4, 0xaa, 0x75, 0xbf, 0x5f, + 0xa9, 0xc6, 0x8d, 0x0f, 0x50, 0xd7, 0x0b, 0x26, 0x68, 0x2b, 0x3e, 0x7c, + 0x67, 0x54, 0x74, 0x5b, 0x3b, 0xb4, 0x83, 0xe3, 0x98, 0x98, 0x7b, 0x40, + 0x70, 0xf2, 0xa0, 0x1b, 0x8e, 0x83, 0xd3, 0x99, 0x9b, 0xd6, 0xcf, 0xbd, + 0xa4, 0xe3, 0xdf, 0x54, 0xd1, 0x8b, 0xf0, 0x6b, 0xbd, 0x3f, 0xae, 0x18, + 0xda, 0x2f, 0x95, 0x03, 0xe4, 0x6c, 0x5e, 0x3c, 0x96, 0x39, 0x4c, 0x5d, + 0xee, 0xcf, 0xe7, 0x4b, 0xab, 0x90, 0xe8, 0x93, 0x7d, 0x81, 0x27, 0x30, + 0x7b, 0x40, 0x6f, 0xd9, 0xaa, 0x18, 0xc1, 0x6b, 0x95, 0x13, 0x98, 0x39, + 0x10, 0xe4, 0x5c, 0x6a, 0x58, 0x96, 0x2c, 0xe0, 0xa7, 0x60, 0xf0, 0x2a, + 0x62, 0xb0, 0xb5, 0xf8, 0xa7, 0x66, 0x9c, 0x39, 0x8e, 0x6e, 0x3a, 0x15, + 0xbd, 0x75, 0xae, 0x22, 0xfb, 0x80, 0x8c, 0x33, 0x6d, 0xac, 0xe3, 0x19, + 0xa8, 0xc7, 0x57, 0x39, 0xe6, 0x66, 0xce, 0xdb, 0x8b, 0x0b, 0x2d, 0x2c, + 0x5a, 0xa8, 0xef, 0x2e, 0x71, 0x44, 0xef, 0xaa, 0x42, 0xb6, 0xa3, 0x86, + 0x76, 0x73, 0xc7, 0x02, 0x3d, 0xfc, 0x03, 0xe2, 0x2e, 0x71, 0x1a, 0xdd, + 0x8c, 0x3b, 0x6b, 0x18, 0x8b, 0x4a, 0x23, 0x7a, 0x2f, 0x73, 0xd4, 0xf7, + 0x6e, 0x75, 0x44, 0x43, 0xf2, 0x1e, 0xd1, 0xdf, 0x63, 0x31, 0xdc, 0xa1, + 0x0a, 0xe2, 0xa0, 0x9e, 0x7d, 0x11, 0xfa, 0xee, 0xaf, 0x92, 0x93, 0xfe, + 0x98, 0xfc, 0xae, 0xe6, 0xd2, 0x43, 0xc4, 0xa8, 0x11, 0x3c, 0x98, 0x39, + 0x88, 0xdd, 0x99, 0x34, 0x76, 0x66, 0xb6, 0x29, 0x43, 0xf6, 0xb3, 0x45, + 0x45, 0xde, 0x99, 0x8b, 0x56, 0x28, 0x5f, 0x46, 0x79, 0xe8, 0x5b, 0xd6, + 0x50, 0x95, 0x8a, 0xca, 0x50, 0x10, 0xd7, 0x24, 0xe3, 0x70, 0x44, 0xde, + 0xb5, 0xe4, 0x7d, 0xed, 0xf5, 0xe3, 0x06, 0xae, 0x4e, 0x96, 0x22, 0xb6, + 0xc7, 0xb2, 0x7a, 0x1b, 0x9c, 0x58, 0x3b, 0x5e, 0x8f, 0x65, 0x03, 0x0f, + 0x59, 0x73, 0x18, 0x73, 0x3e, 0xbc, 0xdc, 0x83, 0x5b, 0xf7, 0x78, 0xd0, + 0x96, 0x8c, 0xc2, 0x17, 0x29, 0xe3, 0xef, 0x80, 0xb9, 0x04, 0xc6, 0xc4, + 0x04, 0x8c, 0xde, 0xab, 0x1c, 0x81, 0xfd, 0x61, 0xd5, 0x83, 0xbf, 0x21, + 0x8e, 0x2f, 0x27, 0xee, 0xc4, 0xc6, 0x2d, 0x54, 0x46, 0xbc, 0xb8, 0x8d, + 0xf5, 0xaf, 0xe3, 0xdc, 0xbf, 0xb3, 0x68, 0x3f, 0xb1, 0x40, 0xf6, 0x42, + 0x6a, 0xd8, 0x30, 0xee, 0xa6, 0xae, 0xdc, 0x88, 0xed, 0xab, 0xc6, 0xd5, + 0x0f, 0xf8, 0x71, 0xeb, 0xb8, 0x07, 0x8d, 0x49, 0x6b, 0xf1, 0x01, 0x33, + 0xbe, 0x52, 0x83, 0x81, 0xb6, 0x71, 0x2f, 0xbe, 0x92, 0xd4, 0x7d, 0xd7, + 0x32, 0xe7, 0x1f, 0x31, 0x83, 0xf8, 0x5f, 0xe3, 0x3e, 0xdc, 0x94, 0x3c, + 0x2a, 0x79, 0xe4, 0x12, 0x27, 0x63, 0xcf, 0xbd, 0xe3, 0xb3, 0xb0, 0x32, + 0xa9, 0x9f, 0x99, 0x20, 0xb7, 0xeb, 0xdc, 0x67, 0xe2, 0xae, 0x71, 0x15, + 0xad, 0x6c, 0xe7, 0xc6, 0xe4, 0x6c, 0x74, 0xec, 0x6b, 0xa0, 0x0c, 0x0b, + 0xb1, 0x7c, 0xc0, 0x09, 0x93, 0x2c, 0x1e, 0x5f, 0x04, 0x5a, 0x06, 0x26, + 0x98, 0xc7, 0xdd, 0x87, 0xed, 0x7d, 0x26, 0x6e, 0x1f, 0x97, 0xf3, 0x83, + 0xf6, 0x3b, 0xae, 0xef, 0x3d, 0xbc, 0x10, 0x9f, 0x1f, 0x50, 0x89, 0x03, + 0xc5, 0x18, 0x5a, 0xa9, 0xe0, 0x2b, 0xbc, 0xbe, 0x35, 0x25, 0x7b, 0x90, + 0x81, 0xd0, 0x8e, 0xc0, 0xfe, 0x2a, 0x72, 0x86, 0x45, 0x0f, 0xe7, 0xae, + 0x3f, 0x48, 0x9c, 0x2f, 0x21, 0xce, 0x97, 0x91, 0xc3, 0x5e, 0x35, 0x7c, + 0x10, 0xf7, 0x13, 0x97, 0x0f, 0x0d, 0x74, 0x32, 0xee, 0x94, 0xe3, 0x71, + 0xc6, 0x81, 0x24, 0xcf, 0x4f, 0xec, 0x30, 0x3a, 0x4a, 0x88, 0xd3, 0x3f, + 0x20, 0xfe, 0xf6, 0x12, 0x33, 0xee, 0x48, 0x32, 0xdc, 0xef, 0x60, 0x0e, + 0x70, 0x69, 0x74, 0xbe, 0x87, 0x39, 0xd6, 0xb5, 0x4a, 0xc0, 0xf7, 0x26, + 0xca, 0xe1, 0x78, 0xb8, 0x1a, 0x8d, 0x0f, 0x48, 0x19, 0xc1, 0x2f, 0x15, + 0xea, 0x5e, 0x27, 0x75, 0x7e, 0x18, 0x56, 0xbf, 0x83, 0xe3, 0xad, 0x35, + 0xc9, 0xc0, 0xf1, 0x9a, 0xa9, 0x6b, 0xff, 0x4c, 0xac, 0x7d, 0x9f, 0x98, + 0xea, 0x9f, 0xd1, 0x80, 0x26, 0xc3, 0xe4, 0x71, 0x18, 0x27, 0xfb, 0x0d, + 0x53, 0xf6, 0xe4, 0xbd, 0x4e, 0x9e, 0x37, 0x39, 0x83, 0x31, 0xd3, 0x10, + 0x3f, 0x1c, 0xe1, 0x78, 0x54, 0xc9, 0x4b, 0xe0, 0x18, 0x03, 0xde, 0x7e, + 0x78, 0x31, 0xc7, 0x25, 0xb1, 0x54, 0xe2, 0xdd, 0x08, 0x65, 0x5d, 0x8c, + 0x15, 0xd4, 0x47, 0x53, 0x52, 0x45, 0x7a, 0x5f, 0x04, 0xb7, 0xef, 0xca, + 0xc5, 0xe1, 0x8d, 0xa1, 0xf8, 0x0d, 0x8c, 0xc3, 0xe1, 0x52, 0xc6, 0x61, + 0x57, 0x44, 0x64, 0x73, 0x62, 0x98, 0x71, 0x7b, 0x73, 0x2a, 0x8c, 0x66, + 0xce, 0xe1, 0x44, 0x9a, 0xfd, 0x26, 0x67, 0xe1, 0x78, 0xda, 0xc3, 0x98, + 0xa5, 0xf1, 0x20, 0xaa, 0x8d, 0x4c, 0xe7, 0xe1, 0xe7, 0x71, 0x31, 0x0f, + 0xc3, 0xbe, 0xb6, 0x26, 0xa9, 0x20, 0xde, 0xa2, 0xd8, 0x7c, 0xfe, 0x78, + 0x5a, 0xb0, 0x59, 0xd6, 0x32, 0xef, 0xae, 0x94, 0x3d, 0xa8, 0xfd, 0xa9, + 0x97, 0x50, 0x49, 0x7c, 0xaa, 0xc8, 0xe3, 0xd0, 0xcf, 0x42, 0x82, 0xbb, + 0xb5, 0xc4, 0x5d, 0xd9, 0x4f, 0x64, 0x59, 0xab, 0x02, 0x53, 0xf1, 0xe8, + 0xff, 0xfb, 0x30, 0x6a, 0xef, 0xab, 0x15, 0x4c, 0x22, 0xfe, 0xa5, 0x88, + 0x7f, 0x1c, 0x43, 0xd7, 0x95, 0xc4, 0x40, 0xca, 0xf4, 0x8f, 0x29, 0x62, + 0x20, 0x71, 0xfa, 0x20, 0x71, 0xfa, 0xdb, 0xc4, 0xe9, 0x6f, 0x11, 0xa7, + 0x1f, 0x27, 0x26, 0xe4, 0xd6, 0xf4, 0x9a, 0xe5, 0xb9, 0x0a, 0xe7, 0xe3, + 0x1d, 0x7b, 0x6d, 0xb1, 0x86, 0xba, 0x9a, 0x3d, 0xa0, 0x60, 0x8e, 0xa1, + 0xef, 0x17, 0xbb, 0xff, 0x31, 0xe7, 0xc9, 0x3f, 0x2d, 0xb7, 0xe7, 0xb7, + 0x29, 0xd9, 0x03, 0x77, 0xb2, 0x4e, 0xeb, 0x85, 0xfd, 0x0d, 0x01, 0x53, + 0xb8, 0x68, 0x51, 0x72, 0x0d, 0x1c, 0xc9, 0xba, 0xfd, 0xc7, 0xe4, 0xf9, + 0xed, 0x74, 0xc9, 0xeb, 0xd7, 0xc8, 0x1e, 0xed, 0xfd, 0xb2, 0x37, 0x6c, + 0x19, 0xef, 0xb9, 0x92, 0x75, 0xe6, 0x9b, 0xb0, 0xb1, 0xcd, 0x3f, 0x69, + 0xdf, 0xab, 0x7d, 0xef, 0x7e, 0xea, 0x2b, 0xcb, 0x36, 0xd3, 0x29, 0xd9, + 0x17, 0x3b, 0x0b, 0x8f, 0x66, 0xe4, 0x77, 0x5d, 0x6b, 0x42, 0xdd, 0x8f, + 0x58, 0x8d, 0xf0, 0xf1, 0x30, 0xae, 0x4f, 0x7a, 0x68, 0x07, 0x71, 0x54, + 0xd0, 0xb7, 0xbe, 0x36, 0xde, 0x40, 0x5f, 0x7b, 0xc8, 0xd2, 0x22, 0x81, + 0xd6, 0x71, 0x72, 0x9e, 0xf5, 0xe3, 0x8b, 0xb1, 0x74, 0xc0, 0xb2, 0x3c, + 0x97, 0x19, 0xe1, 0x0d, 0x8a, 0x1f, 0x2e, 0xfa, 0xa0, 0x83, 0x7e, 0xb5, + 0x6e, 0x4f, 0x40, 0x7b, 0x93, 0x78, 0xda, 0xde, 0x70, 0x80, 0xf6, 0x61, + 0x9c, 0x69, 0x26, 0x96, 0x3a, 0x23, 0x01, 0xe6, 0x89, 0x1e, 0xda, 0xbe, + 0x17, 0x67, 0x12, 0xe2, 0x5f, 0x7a, 0xc7, 0x3f, 0x33, 0x37, 0xe9, 0xa0, + 0x6f, 0xfc, 0x32, 0x31, 0x8b, 0x3e, 0xe0, 0xc6, 0xdb, 0x09, 0x83, 0xfe, + 0xe6, 0xc1, 0x3b, 0x89, 0x7a, 0xf6, 0x15, 0x64, 0x19, 0x3f, 0xee, 0x1c, + 0x0f, 0xd3, 0xcf, 0xae, 0xe4, 0x21, 0xef, 0x53, 0xd7, 0xc6, 0xbf, 0xa3, + 0xd4, 0xf6, 0xcf, 0x56, 0xab, 0x10, 0xad, 0xd6, 0xf0, 0xf5, 0xf1, 0xcf, + 0xe2, 0x3f, 0x18, 0xb7, 0xd7, 0x26, 0xc1, 0x39, 0x44, 0x88, 0x3c, 0x70, + 0x62, 0x9f, 0x3c, 0x4b, 0x44, 0x5d, 0x74, 0xae, 0x43, 0x67, 0x6e, 0xab, + 0x67, 0x4f, 0x3b, 0x9c, 0xec, 0x93, 0xac, 0x98, 0x65, 0x7f, 0xd9, 0x5f, + 0x8a, 0xbb, 0xf6, 0x1c, 0xa0, 0x8f, 0x14, 0x61, 0xc1, 0xfd, 0x6e, 0x7c, + 0x7d, 0xdf, 0x08, 0xb9, 0x83, 0x8a, 0x99, 0xcc, 0x95, 0x86, 0x48, 0x14, + 0x66, 0x0e, 0x47, 0x70, 0xdb, 0xae, 0x11, 0x0c, 0xe4, 0x79, 0x5e, 0x28, + 0x14, 0xff, 0x9f, 0x2a, 0x0e, 0x90, 0x47, 0x04, 0xda, 0x3f, 0x43, 0x1b, + 0xab, 0x88, 0x04, 0xe2, 0x32, 0xee, 0x16, 0xda, 0x58, 0x0f, 0xe7, 0x33, + 0xcd, 0x71, 0x24, 0x68, 0x63, 0x8f, 0x51, 0xfe, 0xed, 0xb4, 0xb1, 0x38, + 0x6d, 0x2c, 0x4e, 0x7b, 0x8a, 0xd3, 0xc6, 0xe4, 0x9d, 0xfd, 0x38, 0x6d, + 0x2c, 0x4e, 0x1b, 0x8b, 0xa7, 0x17, 0x63, 0x94, 0x4c, 0x63, 0xcb, 0x48, + 0x03, 0x71, 0x4c, 0xb1, 0xa3, 0x52, 0xf6, 0x86, 0xcf, 0x92, 0xb3, 0x5f, + 0xc5, 0x43, 0x41, 0x33, 0x7d, 0xb2, 0x77, 0x68, 0x84, 0x9c, 0xc7, 0x8d, + 0xdf, 0x64, 0x84, 0xe3, 0x37, 0x30, 0x8f, 0x3d, 0x4c, 0x9e, 0xaf, 0xe2, + 0x49, 0x53, 0xf2, 0x60, 0x93, 0xe7, 0x8c, 0x35, 0x29, 0xe1, 0x6b, 0x87, + 0x71, 0x47, 0x3f, 0x70, 0x2d, 0x79, 0x61, 0x35, 0x79, 0xc9, 0xde, 0x05, + 0xfc, 0xfd, 0xf0, 0x01, 0xda, 0xbc, 0xf8, 0x63, 0x6e, 0xaf, 0xeb, 0xf1, + 0xfe, 0x5a, 0xdf, 0xd5, 0xf4, 0xc1, 0x7b, 0x59, 0xd7, 0xf9, 0xb0, 0xd4, + 0x39, 0xc0, 0xb6, 0xf5, 0xf0, 0x6f, 0x38, 0xff, 0xad, 0xf7, 0x57, 0xe3, + 0xed, 0x5d, 0x7a, 0xf8, 0x7d, 0x62, 0x5e, 0xb5, 0xc3, 0x5a, 0xfc, 0x99, + 0x50, 0x60, 0xe3, 0x67, 0xd4, 0x1c, 0xdf, 0x6b, 0xd9, 0xe1, 0xc4, 0xfe, + 0xd0, 0x62, 0x78, 0x16, 0x14, 0x38, 0x1f, 0x6d, 0xa9, 0x5a, 0x38, 0x96, + 0x1e, 0x3e, 0x4d, 0xae, 0x92, 0x64, 0xfb, 0xa3, 0xe9, 0x23, 0xc4, 0x90, + 0xfb, 0xf0, 0x02, 0xf3, 0xf3, 0x91, 0x4f, 0xbf, 0x4e, 0xee, 0xe8, 0xc6, + 0x18, 0x39, 0xe0, 0x81, 0xfe, 0xe8, 0xe7, 0x9c, 0xc4, 0x7d, 0xcf, 0x82, + 0x72, 0xa4, 0x87, 0x84, 0x2b, 0x96, 0xe3, 0xd9, 0x7e, 0x43, 0xbb, 0x56, + 0xc9, 0xf1, 0xc2, 0x2d, 0x3c, 0x7f, 0xb3, 0xdf, 0x38, 0x33, 0x8c, 0xc0, + 0xc4, 0x69, 0x72, 0xc3, 0xf7, 0x87, 0x24, 0x86, 0x1d, 0xa4, 0x8f, 0xfb, + 0x11, 0x4e, 0x6a, 0x38, 0x34, 0x66, 0x60, 0x7e, 0xd2, 0x8b, 0x47, 0xc6, + 0x82, 0xf8, 0x0c, 0x7d, 0x37, 0x43, 0x7e, 0xf8, 0xe9, 0xa4, 0xf8, 0xe2, + 0x2c, 0x8c, 0x8f, 0xcd, 0xb2, 0xf7, 0x54, 0x7a, 0x8c, 0x5f, 0xc0, 0x53, + 0x2d, 0x3e, 0x49, 0x6e, 0x9d, 0xd2, 0x7b, 0x63, 0x1c, 0x4f, 0xcc, 0xab, + 0xef, 0x8f, 0x41, 0x1f, 0x02, 0xae, 0xf8, 0x70, 0xe8, 0x8b, 0x12, 0x1f, + 0xc5, 0x1f, 0x35, 0x8c, 0x93, 0xef, 0x14, 0x13, 0x53, 0x4b, 0x23, 0xb5, + 0xef, 0xbd, 0xac, 0xe8, 0xd9, 0xa7, 0x55, 0xcb, 0x7a, 0x69, 0xa1, 0x06, + 0xdf, 0x3e, 0x8d, 0xdc, 0xc3, 0x64, 0xec, 0x16, 0x3f, 0xd5, 0x30, 0xe3, + 0x81, 0x6a, 0x4c, 0x7b, 0x20, 0x89, 0xbf, 0xad, 0x8e, 0x7f, 0x6e, 0x3a, + 0xe3, 0xfc, 0x74, 0xe2, 0x7a, 0x65, 0xf2, 0xd8, 0x0c, 0x37, 0xf9, 0xf2, + 0x84, 0x5a, 0xd7, 0xba, 0x1f, 0xfa, 0xfe, 0x93, 0x8a, 0xee, 0x7b, 0x8c, + 0xb1, 0xc1, 0x45, 0x1b, 0x75, 0x8c, 0x6b, 0xf4, 0xdd, 0xba, 0x43, 0xd3, + 0x60, 0xc4, 0x2f, 0x57, 0x5d, 0x16, 0x6c, 0x79, 0xae, 0xa8, 0xcc, 0xe5, + 0x45, 0x82, 0x3b, 0x12, 0x17, 0x1c, 0xb2, 0xff, 0x13, 0xed, 0xf4, 0x97, + 0x15, 0x76, 0x2c, 0x3a, 0x60, 0xef, 0x8f, 0xdb, 0x30, 0x1e, 0xa7, 0x8f, + 0x2c, 0x46, 0xd9, 0x80, 0x07, 0x5f, 0xb3, 0xe3, 0xd0, 0x43, 0x56, 0x15, + 0xfd, 0xe5, 0xf6, 0x3d, 0x81, 0xf6, 0xab, 0xe9, 0x2f, 0xb5, 0x97, 0x49, + 0x0c, 0x63, 0xdc, 0x4e, 0x19, 0xe6, 0x30, 0xb1, 0xe5, 0xa1, 0x06, 0x63, + 0xe2, 0x75, 0xe4, 0x7c, 0x66, 0x6b, 0x5f, 0x35, 0xfe, 0xe1, 0xfe, 0xfd, + 0xf6, 0x5a, 0xc8, 0x6d, 0x3c, 0x4f, 0xf6, 0xf9, 0x6c, 0xff, 0x88, 0xf1, + 0xf7, 0x9d, 0x8c, 0x79, 0x31, 0xfa, 0xd1, 0x96, 0x3e, 0x6b, 0xf1, 0xf7, + 0x17, 0xc6, 0x57, 0x56, 0x20, 0xc8, 0x98, 0xe4, 0x46, 0x6f, 0x9f, 0xde, + 0xdf, 0xca, 0x18, 0x74, 0x62, 0xa1, 0x49, 0x59, 0x3c, 0xd8, 0xd1, 0x27, + 0x98, 0x7a, 0xf4, 0xa6, 0x6a, 0xc4, 0xff, 0xa7, 0xc6, 0xf1, 0x7d, 0xcd, + 0x7e, 0xf6, 0x37, 0x0b, 0x6b, 0xf7, 0x5d, 0x46, 0x99, 0xeb, 0xe9, 0x83, + 0xcc, 0xab, 0x99, 0xef, 0xac, 0xde, 0x25, 0x7e, 0x81, 0x46, 0xc9, 0xd3, + 0x3a, 0xcd, 0x80, 0xf9, 0x06, 0x7d, 0xa8, 0x88, 0x5c, 0xe7, 0x41, 0x62, + 0x59, 0x31, 0x21, 0xb3, 0xcc, 0x08, 0x63, 0x21, 0x6d, 0x54, 0xde, 0xe1, + 0x98, 0x46, 0x5e, 0x37, 0x9f, 0xf3, 0x51, 0x92, 0xf1, 0x00, 0xe4, 0x10, + 0x20, 0x3e, 0x61, 0x94, 0x20, 0x38, 0xea, 0xe7, 0x71, 0x31, 0x0f, 0x2a, + 0x22, 0xa3, 0xa2, 0x66, 0x94, 0x75, 0x87, 0x47, 0x6c, 0x5b, 0xfc, 0x07, + 0xce, 0x7b, 0x82, 0xb6, 0x7e, 0x23, 0xb1, 0x7e, 0x62, 0x27, 0xd0, 0xfb, + 0x70, 0xce, 0xb6, 0x53, 0x6c, 0xbf, 0x85, 0x98, 0xf7, 0x1e, 0x6d, 0xb6, + 0x87, 0xf3, 0xbd, 0x63, 0xd0, 0x08, 0xd6, 0xa9, 0x01, 0x6d, 0x9c, 0xf3, + 0xdc, 0x35, 0xa2, 0xa2, 0xaf, 0x7f, 0x31, 0x86, 0x99, 0x07, 0x75, 0x0f, + 0x89, 0x8f, 0x48, 0x99, 0xc3, 0xe8, 0xa4, 0x8f, 0xfc, 0x6a, 0xa1, 0x82, + 0xd8, 0x17, 0xe4, 0x1d, 0x51, 0x27, 0xf3, 0xfd, 0xfb, 0xb0, 0x36, 0x71, + 0xc4, 0x2a, 0x37, 0xf4, 0xde, 0x21, 0x95, 0x79, 0x16, 0x6d, 0xb3, 0x8b, + 0xf9, 0xc9, 0x12, 0xe6, 0x27, 0xdd, 0x79, 0xbb, 0x3c, 0x4e, 0x3b, 0xec, + 0x63, 0x1c, 0x7b, 0x7d, 0x28, 0x17, 0xf7, 0x7e, 0xbc, 0xc3, 0x8f, 0xf9, + 0x97, 0x97, 0xe3, 0x99, 0x87, 0x73, 0xb2, 0xed, 0xa4, 0x4d, 0x3e, 0x4d, + 0x3d, 0xdf, 0x4a, 0xbd, 0xbe, 0x92, 0x12, 0x8c, 0x0a, 0xe2, 0x59, 0xf2, + 0xe8, 0xf5, 0xe4, 0x02, 0x2f, 0xa5, 0x72, 0x36, 0xf9, 0xf5, 0xf1, 0x2b, + 0xab, 0x72, 0xf1, 0xc1, 0x0b, 0xf5, 0x01, 0x79, 0x27, 0xcf, 0xb2, 0x96, + 0x98, 0xd9, 0x76, 0xf2, 0x1a, 0xb6, 0x1d, 0x21, 0x37, 0x72, 0x62, 0x66, + 0x32, 0x82, 0xa5, 0xa9, 0xda, 0xe6, 0xb9, 0xb2, 0x89, 0x63, 0x66, 0x8e, + 0x03, 0xba, 0x92, 0xf2, 0xcd, 0x0f, 0x0d, 0x65, 0xcc, 0x9d, 0xfe, 0x26, + 0xff, 0x9d, 0x91, 0x1b, 0xff, 0x0c, 0xee, 0xb8, 0x82, 0x32, 0xa5, 0xc8, + 0x1d, 0x27, 0xf3, 0xdf, 0x19, 0xb9, 0xc1, 0xfe, 0xce, 0x88, 0x1b, 0xd3, + 0xc6, 0x9d, 0xce, 0x2f, 0xa5, 0x3c, 0x98, 0x31, 0x7e, 0x96, 0x83, 0xba, + 0x8b, 0x22, 0x4d, 0x78, 0x2a, 0xa1, 0x60, 0xba, 0xf1, 0xbf, 0xf1, 0xb2, + 0xbd, 0x26, 0x50, 0x8d, 0x99, 0x0f, 0xc8, 0x7a, 0x42, 0x54, 0xde, 0x89, + 0x69, 0x7e, 0x82, 0xe7, 0x25, 0xc4, 0xd3, 0x8a, 0x07, 0x14, 0x3c, 0x1d, + 0xf0, 0xa2, 0x98, 0xbf, 0x7d, 0xe4, 0x9a, 0xce, 0x85, 0xcb, 0xad, 0xcd, + 0xab, 0xc4, 0xbe, 0x39, 0x87, 0xfb, 0xa6, 0x55, 0x0a, 0x06, 0xee, 0x35, + 0x65, 0xdd, 0xd2, 0x40, 0x4f, 0xa2, 0x9a, 0xfc, 0xba, 0xb6, 0xbd, 0x09, + 0xb5, 0xe6, 0x2f, 0x1c, 0xd5, 0x28, 0xda, 0x77, 0x63, 0x95, 0xac, 0xd9, + 0x7f, 0x9b, 0x73, 0xd6, 0x4d, 0xec, 0xea, 0x4a, 0xe5, 0xe2, 0x67, 0x53, + 0xfa, 0x17, 0x9a, 0xe8, 0xa5, 0x9b, 0xfc, 0x44, 0x4d, 0x9e, 0xb2, 0xcb, + 0x94, 0x45, 0x0e, 0x11, 0x7f, 0x66, 0xe1, 0x10, 0xf3, 0x1a, 0x89, 0xa5, + 0x65, 0x3c, 0xca, 0xc9, 0x1b, 0x7f, 0xc9, 0x58, 0x7a, 0x67, 0x28, 0x1b, + 0x94, 0x2f, 0xd0, 0x54, 0x91, 0x8b, 0xd3, 0x07, 0xb0, 0x2f, 0xa4, 0xb7, + 0xac, 0x76, 0x44, 0x9f, 0x61, 0x0e, 0x16, 0x5e, 0xcc, 0x9c, 0x7c, 0x79, + 0x60, 0x04, 0x5b, 0xc9, 0x03, 0xb7, 0x30, 0x17, 0x6f, 0xa5, 0x6d, 0xb6, + 0xef, 0x62, 0x6c, 0x73, 0x9c, 0xcb, 0xc5, 0xb5, 0x50, 0x7c, 0x35, 0x39, + 0x40, 0x87, 0x47, 0x15, 0x7b, 0x15, 0xdf, 0x09, 0xb4, 0xbe, 0x41, 0x8c, + 0xae, 0x63, 0xdc, 0x10, 0x7b, 0xdf, 0x9e, 0xd2, 0xdb, 0xa9, 0x80, 0xaa, + 0x72, 0xe6, 0x8e, 0x77, 0x8d, 0x35, 0xd0, 0x6f, 0xac, 0x4e, 0x37, 0xed, + 0xda, 0xb9, 0x68, 0x16, 0x73, 0xce, 0xab, 0xd0, 0xbd, 0x83, 0xf6, 0x4f, + 0x5f, 0xba, 0xb7, 0x0f, 0xe4, 0x67, 0xea, 0x16, 0xce, 0x5f, 0x76, 0x1f, + 0x02, 0x67, 0x5a, 0x50, 0xd7, 0x5c, 0xe4, 0x10, 0x19, 0xf4, 0x96, 0xb7, + 0xc9, 0xd3, 0x3a, 0x98, 0x9f, 0xae, 0x67, 0x2e, 0x1f, 0x63, 0x2e, 0x1f, + 0x63, 0xbd, 0xd4, 0x0e, 0x79, 0x4e, 0x64, 0xb4, 0x1c, 0x67, 0xfe, 0xf3, + 0x35, 0xf2, 0x9f, 0x1d, 0xf7, 0x8b, 0x5c, 0xd3, 0x71, 0xd7, 0xde, 0xab, + 0x90, 0xa4, 0x3d, 0xdd, 0xc9, 0x6b, 0x7d, 0xf7, 0x5f, 0x8c, 0x3b, 0x98, + 0xc7, 0xc7, 0xc6, 0x16, 0xa3, 0x9f, 0x99, 0xe8, 0xc6, 0xbd, 0x9f, 0x45, + 0x17, 0xf9, 0xd4, 0x12, 0x62, 0xf4, 0xea, 0x87, 0x47, 0x6c, 0xcc, 0x16, + 0xcc, 0x7f, 0x2d, 0x0d, 0xbc, 0x49, 0x4e, 0xd6, 0x9f, 0x3a, 0x60, 0xf3, + 0x34, 0x17, 0xe3, 0x43, 0x31, 0x71, 0x29, 0xbc, 0xcb, 0xe8, 0x58, 0xa6, + 0x5a, 0x8b, 0x4b, 0x16, 0x06, 0x7a, 0xdf, 0xa6, 0xaf, 0x56, 0xed, 0x53, + 0x51, 0x3d, 0x20, 0xb9, 0x3a, 0xf9, 0x11, 0x31, 0xfa, 0x05, 0x62, 0x74, + 0xf9, 0x9e, 0x5c, 0x5e, 0x9e, 0x60, 0xde, 0x55, 0x6d, 0xe4, 0x72, 0xf3, + 0xed, 0x7d, 0xb2, 0xf7, 0xc6, 0x8d, 0xe7, 0x68, 0xfb, 0x47, 0xf3, 0xb6, + 0x7f, 0x2c, 0x8f, 0xc1, 0x16, 0x73, 0xf3, 0x37, 0x6d, 0xfc, 0xcd, 0xe5, + 0xe6, 0xf3, 0x07, 0x8c, 0x8e, 0x30, 0x31, 0xfa, 0x33, 0x7b, 0xa4, 0x7f, + 0x0d, 0xd5, 0xc4, 0x93, 0x1a, 0x62, 0x49, 0xc5, 0x80, 0xac, 0xcf, 0x04, + 0xda, 0xc7, 0x55, 0x9f, 0xdd, 0xc7, 0x26, 0xca, 0xd6, 0x9d, 0x92, 0x77, + 0x6c, 0x0d, 0x6d, 0x83, 0x12, 0x30, 0xaf, 0xa1, 0x3e, 0xf7, 0xa5, 0xaf, + 0x42, 0x7b, 0xff, 0x2c, 0xec, 0x1f, 0x92, 0xf8, 0x22, 0xed, 0x4b, 0x2e, + 0xee, 0xc4, 0xfb, 0xbb, 0x66, 0xe3, 0xfd, 0x91, 0x73, 0x79, 0xf8, 0xe6, + 0x54, 0xf4, 0x5e, 0x86, 0xd7, 0xe5, 0x92, 0x87, 0xbf, 0xc4, 0x3c, 0xfc, + 0x6d, 0x45, 0xd6, 0x10, 0x55, 0xdc, 0xb8, 0xc0, 0xc1, 0xf8, 0xa2, 0xfb, + 0x5f, 0x74, 0xc4, 0xe5, 0x39, 0xb2, 0xff, 0x7e, 0xde, 0x7f, 0x9e, 0xf1, + 0x7c, 0x80, 0x33, 0x11, 0xad, 0x76, 0xe0, 0x99, 0x85, 0xf1, 0xa8, 0x8b, + 0xd7, 0x7b, 0xc9, 0x53, 0x66, 0x1a, 0x07, 0xe9, 0x9b, 0xb5, 0xe1, 0xf9, + 0x0e, 0x07, 0xce, 0x98, 0x7a, 0xcb, 0x6e, 0x5e, 0x7b, 0x36, 0x23, 0xbe, + 0x18, 0x26, 0x7e, 0x2d, 0xca, 0xfb, 0xa2, 0xbc, 0x8f, 0x01, 0xf7, 0x6c, + 0xda, 0xeb, 0x6b, 0x29, 0xbd, 0xff, 0x59, 0xda, 0x69, 0xf5, 0x59, 0x3b, + 0x2d, 0xec, 0xd3, 0x82, 0xbb, 0x2a, 0xd2, 0x82, 0x50, 0xb2, 0xb0, 0x5f, + 0x6b, 0x3f, 0x7a, 0x32, 0xf7, 0x60, 0xe3, 0x4e, 0x7d, 0xa3, 0xac, 0x11, + 0xbd, 0x10, 0x8a, 0x5b, 0x95, 0x46, 0x27, 0x5c, 0x0b, 0x8c, 0x16, 0xe6, + 0x2f, 0xb1, 0xef, 0x2a, 0xa5, 0xb4, 0xdf, 0xc3, 0xd8, 0x34, 0xac, 0x07, + 0xb7, 0x2b, 0x06, 0xe3, 0x86, 0x86, 0xfd, 0x83, 0x45, 0xb8, 0x75, 0x57, + 0x1b, 0xf6, 0xf5, 0x9b, 0xc4, 0xcf, 0x5a, 0xff, 0x69, 0xbc, 0x87, 0x63, + 0xa6, 0xbc, 0xaf, 0x54, 0x82, 0x36, 0x4d, 0xf6, 0x29, 0x31, 0xfb, 0x9c, + 0x7e, 0xde, 0x3b, 0xe0, 0x9e, 0x12, 0xa3, 0xf0, 0x2e, 0xbf, 0xc1, 0x7c, + 0x71, 0x12, 0x7b, 0x06, 0x65, 0x6d, 0x60, 0x9a, 0x72, 0xa4, 0x7f, 0xae, + 0xaf, 0x8b, 0xd8, 0x7f, 0xaf, 0x99, 0xc5, 0x99, 0x85, 0xd5, 0xc0, 0x0c, + 0x05, 0xa1, 0xcf, 0x04, 0xe4, 0x5b, 0x35, 0xfc, 0x7b, 0xd7, 0xf2, 0x7f, + 0x51, 0xda, 0xa9, 0xa9, 0xc8, 0xad, 0x17, 0xbc, 0x5e, 0x2d, 0xef, 0xf2, + 0x1d, 0x49, 0xcd, 0xac, 0xcc, 0x3d, 0x77, 0xfe, 0xa4, 0x3e, 0x5e, 0xb3, + 0xfc, 0x76, 0x1b, 0x85, 0xba, 0xaf, 0x5a, 0x51, 0xaf, 0x94, 0x2f, 0x62, + 0xdb, 0xe2, 0x9f, 0xd3, 0x94, 0x76, 0xe2, 0xa9, 0x1a, 0x9a, 0xa6, 0xb4, + 0x0d, 0x5d, 0xd8, 0xee, 0x8b, 0x56, 0xb4, 0x45, 0xce, 0x0b, 0xe5, 0xdc, + 0xd3, 0x50, 0x2a, 0x65, 0x0b, 0xf7, 0x9f, 0xc9, 0xb7, 0x55, 0x4c, 0xae, + 0x9a, 0x2b, 0x73, 0x6b, 0xbf, 0xec, 0xad, 0x8a, 0xe2, 0x68, 0xc3, 0xd4, + 0xf6, 0x0a, 0x7d, 0x7f, 0xef, 0xbc, 0xf6, 0x72, 0x65, 0x67, 0xb1, 0x4d, + 0x29, 0x9f, 0xc5, 0xff, 0x6b, 0xaf, 0x23, 0xbc, 0x61, 0xef, 0x93, 0xdc, + 0x6a, 0x36, 0x46, 0x4b, 0xf0, 0x39, 0xa8, 0x97, 0xc6, 0xe7, 0x97, 0xd8, + 0xfc, 0x36, 0xda, 0x52, 0xc2, 0x1c, 0xd7, 0x6d, 0x44, 0xef, 0x75, 0x23, + 0x9b, 0x65, 0x5c, 0x6e, 0x3d, 0xa3, 0xec, 0x57, 0x6e, 0x0d, 0xe8, 0x1b, + 0xdf, 0x25, 0xdf, 0x78, 0x3e, 0x10, 0x27, 0xd6, 0x1b, 0xbe, 0x3e, 0x45, + 0x37, 0xd7, 0x32, 0xa6, 0x3d, 0xcb, 0x1c, 0x72, 0x4d, 0xa0, 0xd7, 0x7e, + 0xc6, 0xa8, 0x44, 0x56, 0xe0, 0x12, 0xfb, 0xbb, 0x2c, 0x2d, 0x30, 0xd2, + 0xcf, 0xcb, 0x9a, 0x17, 0x7f, 0xc7, 0x30, 0xdf, 0xbe, 0xb6, 0x06, 0x41, + 0xfb, 0xff, 0xaa, 0xfc, 0xb7, 0x5b, 0x5a, 0x51, 0x6b, 0xff, 0xbf, 0x19, + 0x73, 0xd3, 0x67, 0xd7, 0x86, 0xd1, 0x6d, 0x5a, 0xd6, 0x53, 0xa6, 0x85, + 0x37, 0xce, 0xed, 0xd1, 0x5e, 0xe1, 0x60, 0xce, 0x41, 0x17, 0x8e, 0xe5, + 0xbe, 0x5d, 0x75, 0xee, 0xfd, 0x8c, 0xa5, 0xe7, 0xed, 0xd1, 0x96, 0xf7, + 0xe2, 0xab, 0xed, 0x6f, 0x93, 0xcd, 0x5b, 0xe4, 0xc4, 0x73, 0x89, 0x8a, + 0x98, 0x87, 0xbf, 0x37, 0x2d, 0x2a, 0xc2, 0xfa, 0x10, 0x39, 0xdf, 0xa5, + 0xc7, 0x71, 0xda, 0xfe, 0x46, 0x43, 0x3c, 0x24, 0xdf, 0x66, 0x38, 0x9a, + 0x50, 0x71, 0x6c, 0xb0, 0x27, 0xb4, 0xc7, 0xee, 0xfb, 0x55, 0x74, 0x8f, + 0xca, 0x73, 0xbf, 0x16, 0xac, 0x4e, 0x4c, 0xda, 0x7b, 0xda, 0x36, 0xa7, + 0x24, 0xf7, 0xd6, 0xb3, 0x6b, 0x98, 0xaf, 0xaa, 0x8e, 0x20, 0x6e, 0x62, + 0x7c, 0x79, 0x21, 0x41, 0x3b, 0x5d, 0xa8, 0x77, 0x7c, 0x97, 0x1c, 0xa1, + 0x22, 0xa2, 0x07, 0xdf, 0x51, 0x5a, 0xc9, 0xc5, 0xdc, 0x98, 0x48, 0x88, + 0x2d, 0xca, 0xb7, 0x9d, 0x6e, 0xc6, 0x7e, 0x72, 0xd2, 0xe7, 0x13, 0x1a, + 0x4e, 0x37, 0x78, 0x90, 0x26, 0x47, 0x7d, 0x2e, 0xe1, 0xc6, 0x63, 0xe4, + 0xa8, 0x8f, 0x0e, 0xca, 0x1a, 0x61, 0x13, 0x1a, 0x13, 0xb2, 0x3e, 0x4c, + 0xde, 0x35, 0xe2, 0xa5, 0x3d, 0x5a, 0x56, 0x37, 0x6d, 0xb7, 0x4d, 0x9b, + 0x60, 0x9f, 0xb2, 0xae, 0x18, 0xc5, 0x35, 0xe4, 0x1d, 0x8f, 0x8e, 0xf8, + 0xf0, 0x7d, 0x72, 0xf3, 0x24, 0xeb, 0xbd, 0x90, 0xf0, 0xa3, 0x2f, 0xed, + 0xc3, 0xd3, 0xe4, 0xe8, 0x5b, 0x78, 0x2e, 0xdf, 0x09, 0x2b, 0x32, 0x82, + 0xe4, 0xc1, 0x87, 0x51, 0xd6, 0x77, 0x11, 0xd6, 0xad, 0x3c, 0x08, 0xb5, + 0xef, 0x10, 0x8f, 0x2b, 0x19, 0xb3, 0xaf, 0x44, 0x6a, 0x30, 0x82, 0xd4, + 0xc8, 0x8f, 0xd0, 0x3b, 0x28, 0xe3, 0x92, 0xef, 0x3d, 0xc9, 0xbe, 0x27, + 0x72, 0xbd, 0x3e, 0x2f, 0x86, 0x46, 0xa4, 0x9f, 0x6a, 0xf6, 0xfd, 0xe7, + 0xb6, 0xff, 0x1f, 0xd6, 0xba, 0x1b, 0xa5, 0xed, 0x83, 0x9f, 0xd0, 0xbe, + 0xe8, 0xaa, 0xf0, 0x9e, 0xa1, 0xac, 0x75, 0xb8, 0xd9, 0xa6, 0x07, 0x8e, + 0x48, 0x76, 0x65, 0x39, 0xf4, 0xe8, 0x36, 0xc5, 0x68, 0x2e, 0x53, 0x26, + 0xb1, 0x2d, 0x23, 0xef, 0x8d, 0x15, 0xe3, 0x69, 0xe2, 0xa3, 0x2b, 0xa4, + 0x6b, 0xdf, 0xa5, 0xed, 0x2c, 0x21, 0xa6, 0xbc, 0x61, 0x7e, 0x06, 0x71, + 0x4d, 0xf4, 0x57, 0x8c, 0x1f, 0xf4, 0xbb, 0xf1, 0x4e, 0x28, 0x82, 0xdc, + 0xb7, 0xbd, 0x3c, 0xf8, 0x71, 0xc2, 0xcb, 0xf9, 0xaa, 0xcb, 0x1a, 0x8e, + 0xb9, 0xc0, 0xb4, 0xdc, 0xb5, 0xa3, 0x89, 0x35, 0xd8, 0x43, 0x79, 0x5f, + 0x48, 0x9c, 0xe1, 0xfc, 0xb4, 0x53, 0xff, 0xa2, 0xef, 0x78, 0x5e, 0xd7, + 0x3d, 0xd4, 0xf5, 0x2c, 0x3c, 0x9b, 0xb8, 0x0f, 0x8f, 0x52, 0xfe, 0x47, + 0xfa, 0x8d, 0xe8, 0xc5, 0xca, 0x61, 0xe2, 0x65, 0x31, 0x8e, 0xb1, 0xed, + 0x5b, 0x99, 0x29, 0x4f, 0x4a, 0x5f, 0x29, 0x59, 0x9f, 0x54, 0xf0, 0xce, + 0xa2, 0xc3, 0x18, 0xe7, 0xbd, 0x1f, 0xf3, 0x77, 0x78, 0x61, 0x25, 0xfb, + 0x10, 0xfd, 0xf8, 0xed, 0x5c, 0xa0, 0x8b, 0x3c, 0x67, 0x79, 0xc3, 0x61, + 0x6c, 0x1d, 0x92, 0x6b, 0x6d, 0xe8, 0xed, 0x7f, 0x0f, 0x8e, 0x10, 0x71, + 0xc8, 0xdb, 0x40, 0x5b, 0xcf, 0x62, 0x5b, 0xfa, 0xc3, 0x69, 0x39, 0x0e, + 0xfa, 0xca, 0x34, 0xd9, 0x8b, 0x7c, 0x34, 0x51, 0x8c, 0xe7, 0x58, 0x67, + 0x5d, 0xc8, 0x95, 0x7f, 0x66, 0x72, 0x98, 0xfc, 0xc9, 0x89, 0x34, 0xfb, + 0x48, 0xd8, 0x6d, 0x4c, 0x53, 0x76, 0xd3, 0x0f, 0x2b, 0x17, 0x4e, 0x53, + 0x52, 0x43, 0xc2, 0xed, 0x7f, 0x84, 0x27, 0xef, 0xcf, 0xe9, 0x70, 0x8f, + 0xb9, 0x06, 0x43, 0xe9, 0x1f, 0x17, 0xda, 0x9b, 0xf2, 0x2e, 0x9c, 0xbc, + 0x9f, 0x53, 0x78, 0x57, 0x27, 0xf7, 0x4c, 0xeb, 0xdb, 0x99, 0x0a, 0xf2, + 0xe7, 0x52, 0xda, 0x5a, 0x51, 0xcc, 0xcb, 0xb8, 0xba, 0x66, 0x81, 0x86, + 0x9d, 0x97, 0xd5, 0x4d, 0x43, 0x85, 0xe6, 0xfc, 0x75, 0xc3, 0xf3, 0xec, + 0xa7, 0x22, 0x56, 0x15, 0xd9, 0x63, 0xef, 0x83, 0x0a, 0x5d, 0x56, 0xc3, + 0xb8, 0x22, 0xcf, 0x86, 0x63, 0x78, 0x2b, 0x51, 0x1d, 0xab, 0x8e, 0x54, + 0x12, 0x6f, 0x4f, 0xa3, 0x6f, 0xd8, 0x89, 0x0a, 0xf2, 0xe6, 0xf2, 0x64, + 0x35, 0xdc, 0xf6, 0x3a, 0xde, 0x45, 0xe4, 0x2b, 0xb3, 0xc9, 0x49, 0x66, + 0xa1, 0x92, 0xbc, 0xc4, 0x13, 0xb2, 0xac, 0x9f, 0x2d, 0xb4, 0xac, 0x4b, + 0x78, 0x94, 0xf0, 0x38, 0x15, 0x12, 0x3f, 0x8d, 0xa2, 0xce, 0xf6, 0x57, + 0x03, 0xf5, 0xf6, 0xff, 0x26, 0xfa, 0x7a, 0x47, 0x68, 0xfe, 0xf8, 0x7d, + 0xa1, 0xb9, 0xe3, 0x35, 0x50, 0x07, 0xa6, 0xc3, 0xc1, 0xb6, 0xbe, 0x70, + 0x99, 0x85, 0x26, 0xfa, 0xf0, 0x5a, 0x53, 0x78, 0xd1, 0x1a, 0xf2, 0xa2, + 0xde, 0x90, 0x31, 0x7e, 0x10, 0x57, 0x33, 0xce, 0xb9, 0x07, 0x7c, 0xec, + 0x47, 0x72, 0x6c, 0x67, 0x76, 0x0e, 0xf9, 0xf6, 0x67, 0x16, 0x0a, 0x47, + 0x6a, 0x25, 0x47, 0x3a, 0x84, 0xd6, 0xf1, 0xc3, 0xb8, 0x9e, 0x65, 0x3c, + 0xe4, 0x2a, 0xc9, 0xcc, 0x8f, 0xd0, 0x97, 0xb1, 0xb0, 0x3d, 0x94, 0xc5, + 0xb5, 0x6c, 0xbb, 0x74, 0xa0, 0x99, 0xdc, 0x70, 0x05, 0xd6, 0x8d, 0xcb, + 0xbb, 0x52, 0x13, 0x58, 0x3e, 0x4e, 0xce, 0x39, 0x5e, 0xf0, 0x57, 0xe1, + 0x4b, 0x2b, 0xc8, 0x97, 0x64, 0x2d, 0x6d, 0x95, 0xbd, 0x96, 0xa6, 0xd2, + 0x0f, 0x1b, 0x13, 0xf2, 0x9e, 0x50, 0x1c, 0xab, 0xc7, 0x05, 0xab, 0xef, + 0x41, 0xf7, 0xb8, 0xac, 0xcd, 0x7e, 0x33, 0x74, 0xf1, 0xf8, 0xab, 0x68, + 0x1c, 0x1f, 0x0a, 0xcd, 0x1b, 0x1f, 0xa1, 0xdc, 0x09, 0xca, 0xd6, 0x1f, + 0xaa, 0x1d, 0x1f, 0x0c, 0x05, 0xc7, 0x77, 0x87, 0x02, 0xe3, 0x2d, 0xd8, + 0x32, 0xbe, 0x0a, 0x9b, 0xc7, 0x37, 0x62, 0xd3, 0xb8, 0xe0, 0xfc, 0x24, + 0x96, 0x8d, 0xbf, 0x81, 0xa5, 0xe3, 0xcf, 0xa3, 0x69, 0xfc, 0x04, 0x96, + 0x8c, 0xff, 0x08, 0xcd, 0xe3, 0xaf, 0x70, 0x2c, 0xb2, 0xd6, 0x2b, 0xeb, + 0xbc, 0x85, 0xe7, 0x6a, 0x53, 0xf7, 0x24, 0xcb, 0x5a, 0x86, 0x7c, 0xbf, + 0x43, 0xe6, 0xd0, 0x85, 0x95, 0xda, 0x6b, 0xe8, 0xd9, 0x25, 0xdf, 0x24, + 0xac, 0xd3, 0xba, 0xe5, 0xf9, 0xa3, 0xf7, 0x79, 0xd9, 0x63, 0x4f, 0x1b, + 0x3b, 0xff, 0xbd, 0xbc, 0xc9, 0xb3, 0xcf, 0x18, 0xe5, 0x1b, 0x18, 0xf2, + 0xec, 0x73, 0x12, 0x5d, 0x99, 0xdf, 0x5a, 0x51, 0x4d, 0xca, 0xca, 0xf7, + 0x3f, 0xc4, 0x1e, 0x5e, 0xc3, 0x43, 0xbb, 0x26, 0xc9, 0x59, 0xb2, 0xf6, + 0x5a, 0xcd, 0xbb, 0xf3, 0xe4, 0x9b, 0x56, 0xf2, 0xce, 0xfe, 0x6b, 0x48, + 0x8d, 0x02, 0xe3, 0x0f, 0x8b, 0x1f, 0xae, 0xa1, 0x1f, 0x66, 0xc5, 0x27, + 0xe3, 0xc4, 0xe4, 0xaf, 0x78, 0x70, 0x0f, 0x79, 0x49, 0x11, 0xb2, 0x23, + 0xa5, 0x78, 0x66, 0x30, 0x6e, 0xcd, 0x31, 0x3c, 0x28, 0x8f, 0x18, 0xd9, + 0x4b, 0x18, 0x67, 0x5f, 0xe1, 0xb5, 0x89, 0x7e, 0xf8, 0x7d, 0x46, 0xc0, + 0x37, 0x87, 0xe7, 0xc7, 0x86, 0xb2, 0xe4, 0x14, 0x1d, 0x98, 0xe4, 0x7f, + 0xc9, 0x41, 0x81, 0x6e, 0x0c, 0x0d, 0x89, 0x3e, 0x5b, 0xa8, 0x4f, 0xc1, + 0x45, 0xbd, 0xa3, 0x89, 0x78, 0x68, 0x29, 0x82, 0x87, 0x2a, 0xca, 0x1e, + 0xe8, 0xa4, 0xbf, 0xea, 0xb1, 0x9f, 0x30, 0x16, 0xf4, 0x29, 0x3f, 0xc2, + 0x73, 0xcc, 0x19, 0x4a, 0x1f, 0x20, 0xff, 0x20, 0x56, 0x56, 0x44, 0x14, + 0x63, 0x79, 0xe0, 0x14, 0x9e, 0x19, 0x71, 0xc2, 0x9d, 0x74, 0x62, 0x82, + 0x38, 0xe9, 0x48, 0xca, 0xf3, 0x7a, 0x8d, 0xb2, 0xc8, 0xba, 0xd0, 0x09, + 0x64, 0xed, 0xe7, 0x69, 0xf2, 0x3c, 0xe4, 0x45, 0xbb, 0x1f, 0x27, 0x65, + 0xef, 0x21, 0x96, 0x76, 0xa5, 0x5e, 0x42, 0xd3, 0x90, 0x07, 0x73, 0x92, + 0x13, 0xcc, 0x5f, 0x5e, 0x45, 0x6a, 0xd7, 0x2c, 0x7c, 0x95, 0x3c, 0x70, + 0x66, 0xd2, 0x84, 0x46, 0xbd, 0xdd, 0x34, 0x66, 0x22, 0xba, 0x77, 0x15, + 0x56, 0xee, 0xfd, 0x22, 0x8f, 0xe9, 0xb8, 0x7e, 0x6f, 0x3b, 0x3e, 0x3f, + 0x16, 0x47, 0xeb, 0x58, 0x0f, 0x8f, 0x36, 0x5c, 0xb7, 0xa3, 0x12, 0xe9, + 0x90, 0xc6, 0x9c, 0xba, 0x8d, 0x39, 0xb5, 0xf0, 0xa1, 0xd5, 0x78, 0x86, + 0xb8, 0x13, 0x0c, 0xad, 0xc6, 0x84, 0xed, 0x8b, 0xb2, 0x97, 0x71, 0x35, + 0x36, 0x31, 0x5f, 0x1e, 0xc6, 0x6a, 0x74, 0xf1, 0xda, 0x0e, 0x7b, 0x0e, + 0x0e, 0x63, 0x31, 0xf3, 0xa1, 0xf7, 0x2f, 0x3f, 0x8c, 0x2b, 0xf6, 0x48, + 0xdf, 0xa7, 0x91, 0xda, 0xb9, 0x86, 0x6d, 0x66, 0xd1, 0x32, 0xf6, 0x43, + 0x7c, 0x7e, 0x07, 0x6e, 0xab, 0x44, 0x25, 0x9e, 0x0f, 0x05, 0x5a, 0xfb, + 0x94, 0x1f, 0xda, 0x6d, 0x6f, 0xa2, 0x1f, 0x6f, 0x65, 0xb9, 0x47, 0xd2, + 0x27, 0xd0, 0x9b, 0x9a, 0x3a, 0xa7, 0xf6, 0x7b, 0xed, 0x8c, 0x07, 0x2f, + 0x63, 0xdf, 0xc8, 0x24, 0xb1, 0xf7, 0x24, 0x8f, 0x0b, 0x9f, 0x5f, 0x7b, + 0xed, 0x7c, 0x26, 0x67, 0x37, 0x92, 0xbf, 0xc8, 0x3a, 0x70, 0x0b, 0x7c, + 0x29, 0xe1, 0x44, 0xd9, 0xad, 0x33, 0xa1, 0x6f, 0x0c, 0xdb, 0x1c, 0xc9, + 0x88, 0x91, 0x1b, 0xb5, 0x7c, 0x57, 0xf1, 0x90, 0x1b, 0x05, 0xb1, 0x22, + 0xa3, 0x47, 0xaf, 0xa5, 0xbe, 0x4b, 0xee, 0x7f, 0x19, 0xce, 0xfb, 0x9d, + 0x28, 0x4e, 0xca, 0xda, 0xc9, 0x04, 0x7a, 0x33, 0xf2, 0xfe, 0x6e, 0x56, + 0x2f, 0x26, 0xae, 0x16, 0x25, 0xb3, 0x8c, 0xfd, 0xd9, 0xf9, 0x45, 0x90, + 0x77, 0xf1, 0xaf, 0xc2, 0x9a, 0xfe, 0x28, 0xba, 0x4c, 0x79, 0x57, 0x27, + 0x37, 0xfe, 0x39, 0x0d, 0x2f, 0xa3, 0x9b, 0xf1, 0xa7, 0x8d, 0x98, 0xf8, + 0x55, 0xfb, 0x59, 0xe8, 0xcb, 0xe8, 0x19, 0x2c, 0xbc, 0xbb, 0x2e, 0x6d, + 0x3e, 0x4f, 0xbd, 0xb9, 0xf2, 0xdf, 0xec, 0x91, 0x36, 0x75, 0xd3, 0xaf, + 0x4e, 0xcb, 0xbd, 0x8b, 0x03, 0xfb, 0x19, 0x36, 0xed, 0xe3, 0x35, 0xf4, + 0xee, 0x2a, 0x8c, 0x99, 0xb9, 0x41, 0xe0, 0x35, 0xf4, 0x8f, 0xca, 0xd8, + 0xaf, 0x9f, 0x96, 0x7b, 0xc7, 0x78, 0xaa, 0x3e, 0x0a, 0x75, 0x1d, 0xb4, + 0xe7, 0xc2, 0xfd, 0x8f, 0xfb, 0x6e, 0xd0, 0xa7, 0xec, 0x6f, 0xf0, 0xe4, + 0xbe, 0x81, 0x04, 0x3c, 0x99, 0x90, 0x77, 0xfb, 0xd5, 0xc5, 0x2e, 0xa8, + 0x5e, 0x17, 0x8a, 0x19, 0x2f, 0x6a, 0xd0, 0xed, 0xb5, 0x70, 0x35, 0xc7, + 0xb2, 0xbf, 0xfe, 0x3a, 0x66, 0x1a, 0xf1, 0x56, 0x97, 0xfd, 0xce, 0xe1, + 0x8a, 0xbf, 0xfe, 0xe8, 0x3b, 0x87, 0x6f, 0x10, 0x67, 0x15, 0x94, 0x1b, + 0x37, 0xe1, 0x05, 0x3b, 0xa6, 0x28, 0x28, 0x9b, 0x2b, 0xeb, 0x98, 0x7e, + 0x3c, 0x6b, 0xd4, 0xf9, 0xab, 0xe4, 0xf9, 0x94, 0x72, 0xca, 0x92, 0x6f, + 0x06, 0x6c, 0xcb, 0xfc, 0xb1, 0x3d, 0xf1, 0x4f, 0x61, 0xcb, 0xce, 0x30, + 0xe4, 0xfd, 0x15, 0xa7, 0xa1, 0x79, 0x73, 0xfc, 0x4a, 0x64, 0x93, 0xbd, + 0xe4, 0xb7, 0x12, 0x9c, 0xde, 0xa0, 0x9f, 0xbe, 0x21, 0x7b, 0xa6, 0xc8, + 0x99, 0xfe, 0x12, 0xc1, 0xaa, 0xc2, 0x38, 0x65, 0xaf, 0xa9, 0x92, 0x1b, + 0xab, 0x5d, 0x47, 0xca, 0x4a, 0xbd, 0x37, 0xec, 0x35, 0x5c, 0x97, 0xf1, + 0x5b, 0xeb, 0x4d, 0x6f, 0x35, 0xcb, 0x1e, 0xce, 0xdf, 0x9f, 0x14, 0x9f, + 0x33, 0xe5, 0x1b, 0x56, 0x4e, 0xbb, 0x8e, 0xe8, 0xf7, 0x5c, 0x9d, 0xee, + 0x94, 0x83, 0xb8, 0x79, 0xc2, 0xea, 0xf4, 0xca, 0x18, 0xee, 0xbc, 0xa0, + 0x8e, 0xac, 0x2b, 0x68, 0xd2, 0x6f, 0x58, 0xc6, 0xdc, 0x95, 0xf9, 0x68, + 0x9f, 0xb2, 0xde, 0x5b, 0x64, 0x94, 0xe1, 0x54, 0x55, 0x6e, 0x1d, 0xe6, + 0x9c, 0x8c, 0x3d, 0x35, 0xb2, 0x4f, 0xaf, 0xd8, 0x3e, 0xb7, 0xfb, 0x35, + 0xcf, 0xd5, 0xfb, 0xbb, 0xfc, 0x78, 0xab, 0xed, 0x77, 0x86, 0x1e, 0xb4, + 0x79, 0x91, 0x63, 0xca, 0xb8, 0x4b, 0x6a, 0xce, 0xef, 0xe7, 0x2b, 0xf9, + 0x7e, 0x45, 0x1e, 0xef, 0x94, 0x3e, 0x44, 0xae, 0x87, 0xf3, 0x75, 0xf4, + 0x70, 0xd4, 0xee, 0x5f, 0x65, 0xbe, 0x55, 0xe8, 0x93, 0xfe, 0xb8, 0xb0, + 0xd0, 0x46, 0x56, 0xec, 0xb3, 0xb3, 0x98, 0xb1, 0xed, 0x54, 0xc3, 0x3d, + 0xd8, 0x94, 0x10, 0x3d, 0xcb, 0xb7, 0x60, 0x89, 0xe1, 0x36, 0x57, 0x73, + 0xd1, 0x5f, 0x2f, 0xc3, 0x90, 0x16, 0xc7, 0x9e, 0x7a, 0x79, 0x47, 0xce, + 0x45, 0x9f, 0x88, 0xa3, 0xc4, 0x28, 0x96, 0xfd, 0xc7, 0xf6, 0x1e, 0x94, + 0x7d, 0xa6, 0x1e, 0x7d, 0x52, 0xbe, 0x55, 0x76, 0xa9, 0xbd, 0x5e, 0xd5, + 0x3c, 0x04, 0xb9, 0x6e, 0xe2, 0xda, 0xf3, 0xf2, 0xfe, 0x12, 0xda, 0x8e, + 0xbd, 0x27, 0xda, 0x94, 0x77, 0xe8, 0xfa, 0x12, 0xf2, 0x2e, 0x57, 0x5d, + 0x8c, 0xfc, 0x12, 0x2f, 0xa4, 0x65, 0xbf, 0xc2, 0xef, 0xac, 0x78, 0x8d, + 0xec, 0x8b, 0x9c, 0x5a, 0xa7, 0x88, 0xb8, 0x16, 0x08, 0x57, 0x28, 0x85, + 0xf7, 0xb9, 0xce, 0xfd, 0x5d, 0x4f, 0x9b, 0x39, 0x6d, 0xbf, 0x83, 0x27, + 0x67, 0x11, 0x34, 0xa6, 0xe4, 0x9b, 0xa7, 0xfa, 0xc4, 0x72, 0xd4, 0x65, + 0x6b, 0x1d, 0xce, 0x3c, 0x7f, 0x09, 0x63, 0x05, 0xed, 0x66, 0x73, 0x20, + 0x6c, 0xbf, 0x6b, 0xb6, 0x2c, 0x55, 0x1b, 0x7c, 0x04, 0x7a, 0xfb, 0xdb, + 0x2c, 0x7f, 0x5d, 0xe6, 0xfb, 0xd6, 0x90, 0x57, 0xc6, 0x54, 0xc0, 0x88, + 0x13, 0xf4, 0x0d, 0xea, 0x31, 0x22, 0xfe, 0xe1, 0x41, 0x55, 0x24, 0x4c, + 0x3f, 0x96, 0xf8, 0x2f, 0xef, 0xa9, 0xe9, 0xbb, 0xe3, 0x30, 0xd1, 0xc8, + 0x1c, 0xdd, 0x65, 0xef, 0x73, 0xd6, 0xfd, 0x2b, 0x19, 0x87, 0x8e, 0x9c, + 0xdd, 0x13, 0x20, 0x7c, 0xe1, 0xc7, 0x35, 0xf9, 0xbd, 0xd0, 0xee, 0x39, + 0x8c, 0x8f, 0x96, 0xfd, 0x9c, 0x7f, 0x8d, 0x8d, 0x2d, 0x9a, 0xa1, 0xef, + 0xff, 0x95, 0xa3, 0x13, 0x4f, 0x2c, 0x30, 0x3a, 0x0e, 0xa8, 0xd9, 0x21, + 0x1f, 0x71, 0xe6, 0x4a, 0x47, 0x74, 0x07, 0xff, 0xfb, 0x5f, 0xb4, 0xbf, + 0xa1, 0x22, 0x75, 0xf5, 0xe0, 0x2a, 0x55, 0xf6, 0x0f, 0xb5, 0x60, 0xac, + 0x4f, 0xde, 0x7d, 0xd0, 0x5b, 0xbf, 0xad, 0x74, 0x62, 0x43, 0xc8, 0x68, + 0xd9, 0xa8, 0xe8, 0xcd, 0x7f, 0xaf, 0xe8, 0xfe, 0x90, 0x22, 0xe5, 0x82, + 0xb2, 0xb6, 0x77, 0x36, 0xf6, 0xba, 0xd8, 0xc7, 0xde, 0x84, 0x1e, 0x9e, + 0xc6, 0xb2, 0xa7, 0x4c, 0xc3, 0xf7, 0x1e, 0xdb, 0xfc, 0x09, 0x8f, 0x1d, + 0xf6, 0x3b, 0xec, 0x52, 0x3e, 0x3a, 0xdf, 0x65, 0x7f, 0x8f, 0xb8, 0x95, + 0x31, 0x45, 0xbe, 0x35, 0x1c, 0x83, 0x96, 0x9c, 0x45, 0x13, 0xd3, 0x7b, + 0x6f, 0x80, 0xe4, 0xc0, 0x37, 0x4f, 0x47, 0xa9, 0x07, 0xde, 0x48, 0x27, 0xe6, 0x2e, 0x30, 0x7c, 0x8b, 0x54, 0xbb, 0x7e, 0x30, 0xaa, 0x4a, 0x7d, - 0xdd, 0x3f, 0x08, 0x69, 0x23, 0x63, 0x69, 0x73, 0xcb, 0xed, 0x3a, 0x0b, - 0xd4, 0xcf, 0xc0, 0x75, 0xf5, 0xaf, 0xe5, 0x5b, 0x46, 0x5a, 0xa5, 0x21, - 0x75, 0xe2, 0x3b, 0x35, 0xfc, 0xb1, 0x7a, 0x82, 0x2b, 0xbf, 0xb2, 0x30, - 0x4d, 0xea, 0xc9, 0x9e, 0xb1, 0x3b, 0x70, 0xaf, 0xfd, 0x3d, 0x16, 0xf1, - 0x47, 0x3d, 0xfa, 0x15, 0xf2, 0xcf, 0x62, 0x45, 0xb8, 0xa7, 0xf0, 0x84, - 0x56, 0x74, 0x33, 0x8e, 0x69, 0x21, 0xbd, 0xe7, 0x0a, 0xd5, 0x83, 0xc2, - 0xc8, 0x63, 0xb2, 0x6f, 0x66, 0xef, 0x3c, 0x35, 0xbb, 0xbf, 0x26, 0xc6, - 0x76, 0x8f, 0xff, 0xd1, 0xe7, 0xb8, 0xec, 0xab, 0xd8, 0x94, 0xf7, 0x5b, - 0xec, 0x35, 0xc5, 0xd6, 0x84, 0x23, 0xb7, 0x5f, 0x30, 0x3f, 0xb7, 0x1a, - 0xda, 0xc8, 0xf5, 0xd7, 0xc8, 0x37, 0x31, 0x39, 0xd6, 0xb5, 0x09, 0x59, - 0x4d, 0xfa, 0xff, 0x00, 0x85, 0x57, 0x0f, 0xe7, 0xe8, 0x59, 0x00, 0x00, + 0xdd, 0x3f, 0x08, 0x69, 0x23, 0x6b, 0x69, 0x73, 0x2b, 0xed, 0x3a, 0x0b, + 0xd4, 0xcf, 0xc1, 0xf5, 0xe9, 0x5f, 0xcb, 0x37, 0x8b, 0xb4, 0x6a, 0x43, + 0xea, 0xc4, 0x77, 0x68, 0xf8, 0x63, 0xf5, 0x04, 0x57, 0x7e, 0x65, 0x61, + 0xba, 0xd4, 0x93, 0x3d, 0x66, 0x37, 0xe3, 0x76, 0xfb, 0xbb, 0x2b, 0xe2, + 0x8f, 0x7a, 0xf4, 0x6e, 0x72, 0xd5, 0x52, 0x45, 0x78, 0xaa, 0xc4, 0xa2, + 0x36, 0xe2, 0x61, 0x27, 0xb4, 0x90, 0xde, 0x7b, 0x91, 0xea, 0x41, 0x71, + 0x64, 0x54, 0xf6, 0xd9, 0xec, 0x9e, 0xa7, 0xe6, 0xf6, 0xe3, 0xc4, 0xd8, + 0xee, 0x91, 0x3f, 0xfa, 0xdc, 0x97, 0x7d, 0x95, 0x9a, 0xf2, 0xce, 0x8e, + 0xfd, 0x9e, 0x48, 0x5b, 0xc2, 0x91, 0xdf, 0x5f, 0x58, 0x98, 0x5b, 0x0d, + 0x6b, 0x98, 0x17, 0xac, 0x95, 0x6f, 0x63, 0x72, 0xac, 0xeb, 0x12, 0xb2, + 0x0a, 0xf5, 0x7f, 0x01, 0x28, 0xfc, 0xfc, 0x40, 0x38, 0x5a, 0x00, 0x00, 0x00 }; static const u32 bnx2_CP_b06FwData[(0x84/4) + 1] = { @@ -2137,48 +2138,48 @@ static const u32 bnx2_CP_b06FwData[(0x84/4) + 1] = { 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000001, 0x00000001, 0x00000001, 0x00000000 }; static const u32 bnx2_CP_b06FwRodata[(0x130/4) + 1] = { - 0x08001f1c, 0x08001da8, 0x08001ef8, 0x08001ed4, 0x08001eb0, 0x08001e8c, - 0x08001e64, 0x08001e3c, 0x08001e10, 0x08002014, 0x08002004, 0x08001dc4, - 0x08001dc4, 0x08001dc4, 0x08001f44, 0x08001f44, 0x08001dc4, 0x08001dc4, - 0x08001ff4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001fe4, - 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, - 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, - 0x08001dc4, 0x08001dc4, 0x08001fd4, 0x08001dc4, 0x08001dc4, 0x08001fc4, - 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, - 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, - 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001fac, - 0x08001dc4, 0x08001dc4, 0x08001f9c, 0x08001f8c, 0x080031e8, 0x080031f0, - 0x080031b8, 0x080031c4, 0x080031d0, 0x080031dc, 0x08005644, 0x08005604, - 0x080055d0, 0x080055a4, 0x08005580, 0x0800553c, 0x00000000 }; + 0x08001e8c, 0x08001d18, 0x08001e68, 0x08001e44, 0x08001e20, 0x08001dfc, + 0x08001dd4, 0x08001dac, 0x08001d80, 0x08001f84, 0x08001f74, 0x08001d34, + 0x08001d34, 0x08001d34, 0x08001eb4, 0x08001eb4, 0x08001d34, 0x08001d34, + 0x08001f64, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001f54, + 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, + 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, + 0x08001d34, 0x08001d34, 0x08001f44, 0x08001d34, 0x08001d34, 0x08001f34, + 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, + 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, + 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001d34, 0x08001f1c, + 0x08001d34, 0x08001d34, 0x08001f0c, 0x08001efc, 0x08003208, 0x08003210, + 0x080031d8, 0x080031e4, 0x080031f0, 0x080031fc, 0x08005694, 0x08005654, + 0x08005620, 0x080055f4, 0x080055d0, 0x0800558c, 0x00000000 }; static struct fw_info bnx2_cp_fw_06 = { - /* Firmware version: 4.0.5 */ + /* Firmware version: 4.4.22 */ .ver_major = 0x4, - .ver_minor = 0x0, - .ver_fix = 0x5, + .ver_minor = 0x4, + .ver_fix = 0x16, - .start_addr = 0x08000078, + .start_addr = 0x08000080, .text_addr = 0x08000000, - .text_len = 0x59e4, + .text_len = 0x5a34, .text_index = 0x0, .gz_text = bnx2_CP_b06FwText, .gz_text_len = sizeof(bnx2_CP_b06FwText), - .data_addr = 0x08005b40, + .data_addr = 0x08005b80, .data_len = 0x84, .data_index = 0x0, .data = bnx2_CP_b06FwData, - .sbss_addr = 0x08005bc4, + .sbss_addr = 0x08005c04, .sbss_len = 0xe9, .sbss_index = 0x0, - .bss_addr = 0x08005cb0, + .bss_addr = 0x08005cf0, .bss_len = 0x5d8, .bss_index = 0x0, - .rodata_addr = 0x080059e4, + .rodata_addr = 0x08005a34, .rodata_len = 0x130, .rodata_index = 0x0, .rodata = bnx2_CP_b06FwRodata, @@ -2201,761 +2202,761 @@ static const struct cpu_reg cpu_reg_cp = { }; static u8 bnx2_RXP_b06FwText[] = { - 0xec, 0x5b, 0x5d, 0x70, 0x5c, 0xd7, 0x5d, 0xff, 0xdf, 0xb3, 0x2b, 0x69, - 0x2d, 0x4b, 0xf2, 0x95, 0xbc, 0x71, 0x56, 0xa9, 0x92, 0xec, 0x5a, 0x57, - 0xd2, 0xa6, 0x12, 0xe1, 0xca, 0x6c, 0x12, 0x75, 0xd8, 0x69, 0xb6, 0xbb, - 0xb2, 0xa3, 0xb4, 0x66, 0x46, 0x49, 0x0d, 0xcd, 0xb4, 0x65, 0x10, 0xbb, - 0x0e, 0xa4, 0x0f, 0x0c, 0xc6, 0x40, 0x26, 0x80, 0xc1, 0xcb, 0x4a, 0x71, - 0x94, 0x74, 0xad, 0xdd, 0xda, 0x0a, 0x86, 0x69, 0x61, 0x94, 0xd5, 0x87, - 0x53, 0x66, 0xad, 0x4d, 0xcb, 0x4b, 0x99, 0xd6, 0xb1, 0xea, 0xb8, 0x26, - 0x0f, 0x3c, 0xa4, 0x94, 0xce, 0x64, 0x20, 0x33, 0x35, 0xb2, 0x63, 0xfb, - 0x81, 0x8f, 0xc0, 0x4c, 0x49, 0x20, 0x6e, 0x2e, 0xbf, 0xdf, 0xb9, 0xf7, - 0xca, 0x2b, 0x45, 0xd0, 0x3c, 0xf0, 0x78, 0xcf, 0x8c, 0xe6, 0xde, 0x7b, - 0xce, 0xff, 0xfc, 0xcf, 0xff, 0xfb, 0xe3, 0xac, 0xfd, 0x3b, 0x1d, 0xd2, - 0x2e, 0xde, 0xe8, 0xc4, 0x5f, 0xea, 0xc8, 0x33, 0x47, 0x47, 0xef, 0x1f, - 0xbd, 0x9f, 0xdf, 0x21, 0xc3, 0x08, 0xf3, 0x69, 0x48, 0x30, 0x82, 0x11, - 0x8c, 0x60, 0x04, 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, - 0x60, 0x04, 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, - 0x04, 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, 0x04, - 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, 0x04, 0x23, - 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, 0x04, 0x23, 0x18, - 0xc1, 0x08, 0x46, 0x30, 0xfe, 0x3f, 0x47, 0x48, 0xc4, 0xe4, 0xb3, 0xd3, - 0xfb, 0x93, 0x88, 0x4a, 0xc7, 0x8f, 0x66, 0x2d, 0x89, 0x84, 0xd2, 0x97, - 0x9e, 0x2e, 0x58, 0x22, 0x99, 0xfa, 0x70, 0x3c, 0x27, 0x3f, 0x71, 0x8a, - 0xd1, 0xb0, 0x70, 0xfe, 0xee, 0xf4, 0xad, 0xe3, 0xe7, 0x1f, 0x4a, 0xbc, - 0xb3, 0x10, 0x92, 0x88, 0x99, 0x7e, 0x63, 0xd4, 0x1c, 0x94, 0x48, 0x1f, - 0xf6, 0x7c, 0x6d, 0x68, 0x6d, 0x97, 0x74, 0xf9, 0xb8, 0x44, 0x6a, 0xe5, - 0x84, 0x7d, 0x40, 0x86, 0xcd, 0x8b, 0x12, 0x96, 0x0c, 0xce, 0x58, 0xa9, - 0x8b, 0x94, 0xca, 0x06, 0x71, 0x48, 0xa9, 0x1e, 0x91, 0x2b, 0x21, 0x42, - 0x7d, 0xcb, 0xc8, 0x56, 0x3e, 0x70, 0x32, 0x61, 0x9c, 0x6b, 0xe1, 0xbd, - 0xe1, 0xcf, 0x47, 0x44, 0xa5, 0x13, 0xc9, 0x6c, 0x68, 0x42, 0x6a, 0xf3, - 0x8e, 0x33, 0x63, 0x7f, 0x0c, 0x38, 0x7a, 0x64, 0xc6, 0x72, 0xbf, 0xb3, - 0xf6, 0xc7, 0xcd, 0x71, 0xb9, 0x13, 0x73, 0x21, 0x51, 0xd6, 0x5d, 0xf8, - 0x8b, 0x1b, 0xb9, 0xd3, 0x5f, 0x36, 0xb2, 0x8b, 0x1d, 0x52, 0xaa, 0x38, - 0x52, 0xb0, 0x25, 0x93, 0xb5, 0x77, 0x60, 0xfd, 0x03, 0xa7, 0xb0, 0xb1, - 0x67, 0xd8, 0xcc, 0x49, 0x8b, 0x64, 0xa2, 0x31, 0xc0, 0xcc, 0x1b, 0xb9, - 0xb3, 0x7f, 0xdd, 0x21, 0xed, 0xa0, 0x27, 0xc5, 0xef, 0x0f, 0x9c, 0x90, - 0x65, 0x61, 0x9d, 0xe7, 0xe3, 0xbb, 0x41, 0xbc, 0x7c, 0x27, 0xce, 0x2b, - 0xce, 0xf9, 0xa1, 0x98, 0x7c, 0xb3, 0x11, 0x95, 0x6f, 0x34, 0x4c, 0x79, - 0xa5, 0xd1, 0x27, 0x17, 0x1a, 0x8e, 0xf3, 0x0d, 0xdb, 0x71, 0xde, 0xc0, - 0xdf, 0x7f, 0xd8, 0x1b, 0x3c, 0x60, 0x14, 0x8d, 0xf1, 0xc6, 0x57, 0x3b, - 0xa4, 0x2b, 0x11, 0x17, 0xd5, 0x21, 0xd3, 0x95, 0x98, 0xcc, 0x54, 0xca, - 0xc6, 0x63, 0x67, 0xe7, 0x8c, 0xc9, 0xb3, 0x55, 0x9c, 0x19, 0xc6, 0x9c, - 0x14, 0x4b, 0xf6, 0xcb, 0x46, 0xae, 0x31, 0x6b, 0x3c, 0x7e, 0xb6, 0x0b, - 0x34, 0xf2, 0xfc, 0x3d, 0x46, 0xf6, 0xf4, 0x2d, 0xc9, 0xda, 0x94, 0x71, - 0xc2, 0xfc, 0x3c, 0xc4, 0x9e, 0x2d, 0x93, 0xe6, 0x56, 0x8f, 0x5e, 0xc7, - 0x51, 0x69, 0xe7, 0x78, 0x36, 0x65, 0x99, 0x25, 0x21, 0x7d, 0x7a, 0xee, - 0x82, 0x4b, 0xf3, 0x8a, 0x91, 0x3d, 0xdb, 0x61, 0xe4, 0xce, 0x84, 0x41, - 0x87, 0xf4, 0x85, 0x84, 0xfb, 0x06, 0x62, 0x79, 0xa9, 0xe3, 0x0c, 0x31, - 0x55, 0x9a, 0x72, 0x05, 0xcd, 0xa0, 0xe5, 0x9b, 0x15, 0xf0, 0x50, 0x01, - 0x0f, 0x15, 0xf2, 0x16, 0x97, 0xf3, 0x43, 0x3e, 0x6f, 0x8e, 0xf3, 0x77, - 0x36, 0x69, 0x4f, 0xc4, 0x33, 0xca, 0xe7, 0xd3, 0x71, 0xfe, 0xdd, 0x26, - 0xaf, 0xe4, 0xc7, 0x71, 0x5e, 0xb1, 0x63, 0xa0, 0xdd, 0xb9, 0xa0, 0xac, - 0x32, 0x78, 0xb1, 0x80, 0x9f, 0xb2, 0x9e, 0x03, 0x0f, 0xb3, 0xe0, 0x6f, - 0x05, 0xbc, 0x55, 0x41, 0xc7, 0x4f, 0x3b, 0xaf, 0x68, 0xe4, 0x86, 0x36, - 0xe4, 0x15, 0xa7, 0x8c, 0xf3, 0x4b, 0x0a, 0xb2, 0xde, 0x29, 0xf9, 0x05, - 0x53, 0xa6, 0x96, 0xfc, 0xfd, 0xbe, 0x1d, 0x1c, 0x91, 0x83, 0x95, 0x1e, - 0xc8, 0x86, 0xb2, 0x4c, 0xd8, 0x22, 0x0e, 0x64, 0x54, 0x4a, 0x2a, 0x11, - 0x23, 0x6f, 0x1f, 0xd7, 0xfa, 0x5f, 0xb2, 0x24, 0x93, 0xb7, 0x29, 0x47, - 0x89, 0xe7, 0xed, 0x62, 0x2c, 0x0c, 0x7b, 0x5b, 0xb2, 0x8a, 0x66, 0x58, - 0x28, 0xc7, 0x44, 0xec, 0xf7, 0x21, 0xcb, 0x27, 0xcb, 0x92, 0xf9, 0x74, - 0xd9, 0x97, 0xb1, 0x2b, 0xdf, 0xcf, 0x94, 0x3f, 0xd5, 0x29, 0xed, 0xea, - 0x9e, 0x16, 0xf9, 0x0d, 0xec, 0x25, 0xee, 0x4d, 0x7b, 0xb1, 0xcf, 0x85, - 0x73, 0xf7, 0x26, 0x9e, 0x10, 0x21, 0x6c, 0xa9, 0xbf, 0x45, 0xfb, 0x88, - 0x18, 0x59, 0xab, 0x18, 0x0b, 0x01, 0x2e, 0x2f, 0xa5, 0x51, 0x6f, 0xae, - 0x25, 0x6b, 0xdd, 0x0a, 0xcd, 0xd8, 0x89, 0x78, 0x49, 0x6e, 0x85, 0x2e, - 0xdb, 0x7a, 0x6e, 0x47, 0xd6, 0x72, 0x64, 0x19, 0xd8, 0x9f, 0x83, 0x3f, - 0x5c, 0x04, 0x47, 0x5f, 0x2a, 0xeb, 0xf9, 0x4e, 0xec, 0x4f, 0xb6, 0x00, - 0x67, 0xbb, 0x24, 0x92, 0x35, 0xcc, 0x5f, 0x76, 0xe7, 0xbb, 0x5d, 0xbc, - 0xa5, 0xfe, 0x76, 0x8d, 0x5b, 0xe4, 0x65, 0x77, 0xfe, 0x0e, 0x17, 0x77, - 0xe9, 0x3e, 0xcc, 0x03, 0xff, 0xe0, 0xc4, 0x90, 0xa1, 0xe7, 0x7b, 0xe9, - 0x4f, 0xbf, 0x5e, 0xbe, 0x15, 0x5a, 0xb6, 0x1d, 0xc9, 0x8d, 0x0e, 0x4e, - 0x0c, 0x1a, 0x2e, 0xbe, 0x13, 0xee, 0xbe, 0xbb, 0x5d, 0x7c, 0x83, 0x13, - 0x49, 0xc3, 0xc5, 0xb7, 0x54, 0xd6, 0x7b, 0x25, 0x5f, 0x26, 0xec, 0xe0, - 0x84, 0x65, 0xdc, 0x2d, 0x53, 0xdd, 0x83, 0x13, 0x7b, 0x0d, 0x75, 0xcf, - 0x4e, 0x97, 0x8f, 0x84, 0x4f, 0xc3, 0x4e, 0x4d, 0x03, 0xcf, 0xd5, 0xf3, - 0x03, 0x59, 0xab, 0x74, 0xdf, 0x4e, 0x7d, 0x3e, 0xcf, 0xd4, 0x73, 0xf7, - 0x91, 0x2e, 0x9e, 0x5d, 0x18, 0xdd, 0x74, 0xee, 0xcf, 0xdc, 0x96, 0xcf, - 0x76, 0x67, 0xf2, 0x3c, 0x89, 0x84, 0xd3, 0xe1, 0xd1, 0x99, 0xf2, 0x11, - 0xc9, 0x56, 0xe2, 0x32, 0x3d, 0xb2, 0x43, 0xa6, 0xcc, 0xfe, 0xa9, 0x83, - 0xc2, 0xd8, 0x13, 0x19, 0x2d, 0x78, 0x3a, 0xcc, 0x89, 0x21, 0xd3, 0xe0, - 0xf1, 0x60, 0x5d, 0x22, 0x06, 0xe0, 0xfb, 0xeb, 0x61, 0x79, 0xbe, 0x61, - 0x48, 0xab, 0xf6, 0xcf, 0x84, 0xb9, 0x06, 0x3b, 0x7c, 0xb6, 0x42, 0x3b, - 0xa6, 0xcd, 0x4a, 0xa6, 0x06, 0x3b, 0xbd, 0xa0, 0x7d, 0xb5, 0x9d, 0x7a, - 0x2d, 0x16, 0x05, 0xae, 0x98, 0xb6, 0xcc, 0x9a, 0xb4, 0x49, 0x66, 0x52, - 0x8a, 0x5c, 0xf7, 0x7c, 0x27, 0xb6, 0x28, 0xdf, 0x85, 0x0d, 0x88, 0x99, - 0x4d, 0x71, 0x9e, 0xf0, 0x4d, 0xb0, 0xa6, 0xeb, 0x77, 0x21, 0xf8, 0x5d, - 0x21, 0x45, 0x58, 0x29, 0xea, 0x58, 0xd1, 0x80, 0x2d, 0x36, 0xee, 0xee, - 0x74, 0x63, 0x5d, 0x04, 0xfe, 0xd9, 0x01, 0x1f, 0xbf, 0x07, 0xfe, 0xd7, - 0x67, 0x64, 0xcf, 0x38, 0x0e, 0x62, 0x4f, 0x54, 0x09, 0xfd, 0x0f, 0xbe, - 0xde, 0xe0, 0x5a, 0x07, 0xe6, 0xc5, 0x9c, 0xb6, 0xbb, 0xc1, 0x9f, 0xe3, - 0x4c, 0xd8, 0x71, 0x29, 0xd9, 0xbb, 0xb0, 0xaf, 0x45, 0xba, 0x2d, 0xda, - 0x3b, 0x7d, 0x7a, 0x27, 0xce, 0x33, 0xf8, 0xdd, 0x85, 0xf3, 0x3a, 0x31, - 0x17, 0x9b, 0xa6, 0x1f, 0xa7, 0x18, 0xb3, 0xdc, 0xf8, 0x29, 0x72, 0x15, - 0xb4, 0x72, 0x8f, 0x86, 0x8b, 0xb4, 0xa5, 0x53, 0x72, 0xa3, 0xdc, 0x2b, - 0x57, 0xa2, 0xe4, 0x1f, 0x38, 0x2b, 0x88, 0x87, 0x51, 0x03, 0xf4, 0x93, - 0x6e, 0xc6, 0xbf, 0xdd, 0xde, 0xb7, 0x71, 0xaf, 0x7b, 0x86, 0x98, 0xa1, - 0x74, 0x97, 0xe4, 0xf4, 0x9c, 0x28, 0x35, 0xba, 0xd3, 0x5b, 0xef, 0x32, - 0x0e, 0x9c, 0x51, 0x32, 0xf4, 0x20, 0x62, 0x16, 0xce, 0xba, 0x6c, 0x39, - 0xce, 0x65, 0xfb, 0xc7, 0xf0, 0x79, 0x25, 0x2d, 0xd6, 0x7a, 0x97, 0xb4, - 0x43, 0x9e, 0x15, 0xa3, 0x49, 0x86, 0x31, 0x39, 0x51, 0xe1, 0x9e, 0xa2, - 0x84, 0x2d, 0xc2, 0x10, 0xfe, 0x47, 0x80, 0x0b, 0x49, 0x1b, 0x7c, 0xf1, - 0xa2, 0x1d, 0x25, 0xbd, 0xbb, 0x5c, 0xf8, 0x6e, 0x9c, 0x41, 0xda, 0xe9, - 0x7b, 0x8e, 0xf6, 0xbd, 0x6c, 0x48, 0x65, 0xc6, 0xe7, 0xe1, 0x49, 0x23, - 0x94, 0x77, 0xb6, 0x1b, 0xa1, 0x5f, 0xa6, 0x87, 0x8a, 0xa6, 0xd2, 0xba, - 0x16, 0xc9, 0x95, 0xef, 0x95, 0x19, 0x1b, 0xe7, 0x59, 0x61, 0xd0, 0xcc, - 0x38, 0x33, 0x50, 0x0c, 0x29, 0x78, 0x58, 0x0f, 0x65, 0xe5, 0xd3, 0xfa, - 0x16, 0xce, 0x2b, 0x1a, 0x61, 0x8b, 0x67, 0xfc, 0xb2, 0x27, 0x1f, 0xda, - 0x9d, 0x2d, 0xd9, 0x72, 0x07, 0xbf, 0x41, 0x47, 0xbb, 0xa6, 0x23, 0x94, - 0xd6, 0xba, 0x33, 0x54, 0xda, 0x8f, 0xff, 0x04, 0xdd, 0x84, 0x07, 0x7c, - 0x70, 0xaf, 0x85, 0xbd, 0x11, 0xd0, 0xd8, 0xd9, 0x44, 0x7f, 0x3b, 0xe1, - 0x21, 0xab, 0x88, 0x77, 0x86, 0xe6, 0xdb, 0x70, 0xf9, 0xf6, 0x65, 0xf5, - 0x2a, 0x64, 0xf5, 0xbe, 0x33, 0xb4, 0x8f, 0x38, 0x52, 0xc0, 0x01, 0xb9, - 0x9b, 0x8c, 0x57, 0x8c, 0x51, 0xe6, 0x06, 0x2e, 0xf8, 0x81, 0x0a, 0xa5, - 0x3b, 0x24, 0x67, 0xea, 0x1c, 0x00, 0xd8, 0x31, 0xd1, 0x31, 0xde, 0x22, - 0x8f, 0xde, 0xb7, 0x95, 0xd0, 0x76, 0x93, 0xaf, 0x32, 0x0f, 0xfc, 0x31, - 0x68, 0x5b, 0x4b, 0x28, 0xcd, 0x5a, 0x07, 0x64, 0x2e, 0x91, 0x96, 0xf4, - 0x1b, 0xb2, 0x5c, 0x56, 0x7b, 0x5a, 0x65, 0x97, 0x4c, 0x42, 0x46, 0xb5, - 0x31, 0xe4, 0xaf, 0x91, 0x0e, 0x09, 0xdd, 0xcf, 0x3c, 0x10, 0x03, 0xad, - 0x6b, 0x09, 0x53, 0x6e, 0x39, 0x6a, 0x10, 0xfb, 0x47, 0xa0, 0x87, 0x43, - 0xd4, 0xa9, 0xf2, 0xe0, 0x08, 0x13, 0xa2, 0xcc, 0x7b, 0x5a, 0x85, 0xb8, - 0xb9, 0x36, 0x1c, 0x33, 0x85, 0xf3, 0xc8, 0x95, 0x93, 0xdc, 0x4b, 0xfe, - 0xdc, 0x3d, 0x1f, 0xe6, 0xcf, 0x5f, 0xa7, 0xcc, 0x28, 0x3b, 0xd8, 0x18, - 0x78, 0xcc, 0xda, 0xbf, 0xe0, 0xc9, 0xe6, 0x4e, 0xb9, 0x62, 0x8a, 0x51, - 0xb3, 0xef, 0x68, 0x92, 0x1f, 0x79, 0xee, 0xde, 0xc2, 0x33, 0x71, 0x6c, - 0xcf, 0xf7, 0xe1, 0x2a, 0xcf, 0x74, 0xcf, 0x9e, 0xb1, 0xd6, 0x12, 0x61, - 0xd9, 0x2c, 0x5f, 0xe8, 0x52, 0x0a, 0x65, 0xda, 0x46, 0xab, 0xe4, 0x51, - 0x8f, 0xd8, 0xfb, 0x10, 0x54, 0x1e, 0x57, 0x32, 0xfa, 0x20, 0x71, 0xfe, - 0x23, 0x79, 0x1a, 0x8b, 0x2b, 0x43, 0xf2, 0x3a, 0xf7, 0xfb, 0xfa, 0xe2, - 0x5c, 0xb3, 0x6d, 0xbf, 0xea, 0xd9, 0xf6, 0xfb, 0xce, 0xe8, 0x3e, 0x5f, - 0xef, 0x90, 0xd7, 0x87, 0xf6, 0x08, 0xf4, 0xfc, 0x7f, 0xed, 0xa1, 0xad, - 0x44, 0xb6, 0xec, 0x29, 0x6e, 0xb3, 0x67, 0xb7, 0xc8, 0x2f, 0xd1, 0x87, - 0xba, 0xbd, 0x98, 0xe1, 0xfb, 0x94, 0x8f, 0x07, 0xba, 0xd1, 0xb6, 0xca, - 0xb9, 0xed, 0x7c, 0x91, 0x38, 0x88, 0x8b, 0x7b, 0x09, 0xe3, 0xe7, 0x54, - 0xa8, 0x43, 0xb6, 0xcd, 0xab, 0x18, 0x13, 0x78, 0x57, 0x88, 0x43, 0xcd, - 0xf9, 0x95, 0x73, 0x26, 0xbe, 0xc7, 0xf1, 0xb4, 0x24, 0x5f, 0xa7, 0x3f, - 0x71, 0x3f, 0xf3, 0xed, 0x4d, 0x2f, 0x7e, 0x76, 0x4c, 0x85, 0xd3, 0x51, - 0xc4, 0x4f, 0x99, 0x2c, 0x95, 0x8f, 0xa3, 0x26, 0x92, 0xe2, 0x5d, 0x69, - 0xda, 0x47, 0xc7, 0x18, 0x62, 0xe4, 0x64, 0xa9, 0xce, 0xba, 0x08, 0x61, - 0x0c, 0xfb, 0x90, 0xa3, 0x23, 0x6a, 0x2e, 0x52, 0xfc, 0x58, 0x9a, 0x71, - 0x39, 0x2e, 0xf1, 0xfa, 0x3b, 0xa8, 0x3b, 0x4c, 0xc9, 0x6a, 0x5b, 0xfb, - 0xb3, 0x5e, 0xd2, 0x5b, 0x42, 0x0d, 0x11, 0x4e, 0x4b, 0x58, 0xa5, 0x5b, - 0x23, 0xd3, 0xa9, 0x0e, 0xd4, 0x5a, 0x13, 0xbd, 0x6a, 0xf5, 0x60, 0x6f, - 0x68, 0x75, 0xcf, 0x54, 0x4b, 0xba, 0xd8, 0xab, 0xe6, 0x44, 0x16, 0xcb, - 0xa2, 0x50, 0xd7, 0xc4, 0x0e, 0x0b, 0xbe, 0x57, 0x3f, 0xfb, 0x59, 0x95, - 0x0e, 0x41, 0xb7, 0x72, 0x6c, 0x29, 0x15, 0x66, 0x0d, 0x19, 0x9f, 0x94, - 0x63, 0xa8, 0x1b, 0x9f, 0x91, 0xe9, 0x32, 0xe8, 0xd2, 0x7c, 0xc7, 0xc0, - 0x6f, 0x1f, 0x70, 0x93, 0xf6, 0x28, 0x62, 0xac, 0x4b, 0x3b, 0x68, 0xce, - 0xe4, 0x58, 0x27, 0xa5, 0x98, 0x57, 0xde, 0x81, 0xfd, 0xd0, 0x5f, 0xfe, - 0x59, 0x96, 0xad, 0x1d, 0x92, 0x77, 0xe3, 0x03, 0xed, 0x15, 0x6b, 0x37, - 0xbd, 0xb5, 0x6b, 0x58, 0xa3, 0xfd, 0xee, 0x6c, 0xd2, 0xe1, 0x97, 0x75, - 0xad, 0x73, 0xd9, 0xe6, 0x3b, 0x61, 0xff, 0x76, 0xd4, 0x85, 0x7d, 0x7d, - 0x74, 0xd9, 0xfa, 0xdc, 0x2e, 0x69, 0x37, 0xa9, 0x37, 0x9c, 0x13, 0x65, - 0x8c, 0xc5, 0xfa, 0x15, 0x0f, 0xd7, 0x5b, 0xc0, 0xd5, 0x41, 0xba, 0x31, - 0xc2, 0x58, 0x07, 0x7d, 0xa8, 0x79, 0xf2, 0x1b, 0xb1, 0x86, 0xb0, 0xdf, - 0xf1, 0x70, 0x7d, 0xab, 0x09, 0x17, 0xd7, 0xf8, 0xe4, 0x99, 0x38, 0xbb, - 0x9d, 0xbc, 0x91, 0x1f, 0xea, 0x80, 0xfa, 0x48, 0x1a, 0x93, 0x88, 0xed, - 0x93, 0x0d, 0x5d, 0xdb, 0x19, 0xb9, 0x0a, 0x6a, 0xae, 0xc6, 0x8b, 0xa0, - 0x11, 0xb5, 0x58, 0x63, 0xd0, 0xab, 0xb7, 0x69, 0x47, 0x6b, 0xda, 0x1e, - 0x19, 0x77, 0x4a, 0xda, 0xae, 0x2e, 0xb9, 0x76, 0x65, 0x51, 0x37, 0x97, - 0x64, 0x6f, 0xbd, 0xba, 0xcb, 0xfd, 0xbf, 0xdb, 0xa6, 0x84, 0xb4, 0x3e, - 0x99, 0xdf, 0x68, 0x63, 0x77, 0x22, 0xae, 0x3b, 0xef, 0x32, 0xcf, 0x4c, - 0x32, 0x07, 0x4d, 0x32, 0x77, 0x18, 0x5e, 0x3c, 0x8c, 0x37, 0xe1, 0x88, - 0x03, 0xc7, 0x8a, 0x67, 0xbf, 0x73, 0x1e, 0x2e, 0xbf, 0xfe, 0xf4, 0x63, - 0xea, 0x9f, 0xdf, 0xb5, 0x79, 0x5d, 0x99, 0xee, 0x77, 0xab, 0x8e, 0xc7, - 0xb0, 0x75, 0xd0, 0x1f, 0x9f, 0x52, 0xb0, 0xaf, 0x5c, 0xdd, 0xd5, 0x07, - 0x7c, 0x1f, 0xb6, 0xc7, 0x57, 0x5f, 0xb7, 0x6e, 0xfd, 0xed, 0xca, 0x80, - 0x3a, 0xcd, 0x90, 0xef, 0x4c, 0x98, 0xb4, 0x34, 0x26, 0xb0, 0x5f, 0x8e, - 0x30, 0x37, 0xe6, 0xc1, 0xc7, 0x61, 0x73, 0xd8, 0x9c, 0x26, 0xee, 0xa8, - 0x00, 0x27, 0x6a, 0xc9, 0x74, 0x9b, 0xa7, 0xe7, 0x6f, 0xf3, 0x7c, 0xe0, - 0xde, 0xc9, 0x6f, 0x3c, 0xbf, 0xed, 0xd1, 0x73, 0xa3, 0xcb, 0xa5, 0xc7, - 0x5f, 0x1f, 0x34, 0x37, 0x7f, 0xaf, 0xf4, 0x7a, 0xf2, 0xc4, 0xfb, 0x33, - 0x1e, 0x5d, 0xd4, 0x4d, 0x33, 0x4d, 0xd4, 0xcb, 0xbb, 0xc0, 0xa3, 0x6b, - 0x8d, 0xa2, 0x4a, 0xa3, 0x76, 0x49, 0x31, 0x67, 0x25, 0xc6, 0x32, 0x62, - 0x41, 0x27, 0x09, 0x7b, 0x0a, 0xbb, 0x6e, 0x96, 0xa9, 0xe7, 0x5b, 0x88, - 0xd5, 0xd4, 0xfb, 0x7b, 0x32, 0x53, 0xee, 0xb7, 0x5b, 0x0d, 0xfa, 0x6b, - 0x22, 0xb9, 0x22, 0xc3, 0xf6, 0x8a, 0xae, 0xa1, 0x12, 0xf1, 0x13, 0x42, - 0xd9, 0xde, 0x92, 0x01, 0x5d, 0xdb, 0xbc, 0x27, 0x16, 0xe4, 0x32, 0x59, - 0x81, 0x8f, 0xed, 0xfb, 0x57, 0x47, 0xd7, 0xa4, 0x08, 0x6f, 0xd7, 0xb7, - 0xc1, 0xf5, 0xba, 0xc6, 0x43, 0x7c, 0xcd, 0xb8, 0x0c, 0x69, 0xdb, 0xe7, - 0xe3, 0xb3, 0x64, 0xb6, 0xe1, 0xe3, 0x0c, 0x23, 0x2e, 0x23, 0x06, 0xec, - 0xfb, 0xbc, 0x67, 0x2f, 0x7c, 0xff, 0xbe, 0xc3, 0x5a, 0x48, 0xa5, 0xbf, - 0xea, 0xcd, 0x7d, 0x8f, 0x32, 0xc0, 0xb7, 0x2f, 0xf7, 0x17, 0xbd, 0x78, - 0x53, 0x34, 0x32, 0x0d, 0xca, 0x80, 0xb6, 0x02, 0xfd, 0x6b, 0xfb, 0x84, - 0xcf, 0x54, 0x3e, 0x89, 0x98, 0xd5, 0xed, 0xd6, 0x0f, 0xe8, 0xaf, 0x32, - 0x0d, 0xce, 0xad, 0xb5, 0x65, 0xed, 0x16, 0xcf, 0x97, 0x0e, 0x62, 0x6e, - 0x12, 0x7f, 0x94, 0x1d, 0x61, 0x0e, 0xe1, 0x3d, 0xe3, 0xc1, 0xc9, 0x58, - 0x16, 0xb9, 0x2b, 0x73, 0x68, 0x1c, 0xdf, 0x86, 0xd7, 0x67, 0x69, 0xb9, - 0x57, 0x51, 0xab, 0x40, 0x9e, 0x03, 0xe0, 0x27, 0x2e, 0xe3, 0x0d, 0xe8, - 0x7c, 0x23, 0x9e, 0x6d, 0xc0, 0x14, 0x6f, 0xc3, 0xb8, 0xb1, 0x6f, 0xbc, - 0xf1, 0xa6, 0xc3, 0x78, 0xf0, 0x57, 0xda, 0x5f, 0xe2, 0xa0, 0xdd, 0xef, - 0xd5, 0x32, 0xc6, 0x63, 0x95, 0x09, 0xe3, 0xf1, 0x0a, 0xf7, 0xa8, 0xaf, - 0xf5, 0x88, 0x15, 0xcf, 0x2a, 0xd4, 0xa9, 0xfb, 0xba, 0x70, 0xe6, 0x09, - 0xd8, 0x46, 0xd1, 0x98, 0x1c, 0xda, 0x25, 0xf9, 0x64, 0x0f, 0x68, 0x7e, - 0x08, 0xcf, 0x56, 0xcc, 0xff, 0x3c, 0xe6, 0x61, 0x47, 0x49, 0xfa, 0xc7, - 0x0e, 0xdd, 0x5b, 0x4e, 0x99, 0xa4, 0x71, 0xc0, 0xb3, 0xad, 0x37, 0x4d, - 0xd7, 0x96, 0x9e, 0xc6, 0xf7, 0x4e, 0xcc, 0x7f, 0x01, 0x4f, 0xe4, 0xb2, - 0x7d, 0xfe, 0x3c, 0x7d, 0x70, 0x0c, 0xf3, 0x0f, 0x00, 0xc7, 0x1f, 0xe0, - 0xfd, 0x5e, 0xbc, 0xff, 0xde, 0x96, 0xbd, 0xbf, 0xcb, 0xb3, 0x31, 0x9f, - 0xdd, 0x32, 0xef, 0xc7, 0x6f, 0x9e, 0x27, 0xd2, 0xbd, 0x0a, 0xc6, 0x57, - 0x23, 0xb2, 0x7b, 0xa5, 0x5d, 0x54, 0xcd, 0x8d, 0xe1, 0xaa, 0x66, 0x4a, - 0xcf, 0x0a, 0xe3, 0xf7, 0x0f, 0xb0, 0xc7, 0x12, 0xb5, 0x0a, 0xa5, 0x51, - 0xb7, 0xda, 0x47, 0x9f, 0x39, 0xba, 0x77, 0x81, 0xcf, 0xe2, 0xd1, 0xd1, - 0x3a, 0x61, 0xf8, 0x7e, 0xec, 0xe8, 0xde, 0xfa, 0x3f, 0x00, 0x16, 0x72, - 0xa9, 0xf8, 0xf8, 0x09, 0x7f, 0x7e, 0xcb, 0x99, 0x5a, 0xb6, 0x38, 0x93, - 0x7e, 0xff, 0xcc, 0xd1, 0x6c, 0x95, 0x75, 0x42, 0x22, 0x26, 0xba, 0x16, - 0x2f, 0x1e, 0x2d, 0x20, 0x3f, 0x86, 0x34, 0x2d, 0xfe, 0x3a, 0xd7, 0xa8, - 0x87, 0xed, 0x68, 0x23, 0x5d, 0xcd, 0x78, 0x98, 0x67, 0x88, 0xe7, 0x18, - 0xf0, 0x24, 0x81, 0x87, 0xf9, 0xc6, 0xa5, 0x37, 0xbe, 0xb0, 0x1d, 0x6d, - 0xc4, 0xc5, 0xb3, 0x7c, 0x7c, 0x3d, 0xa2, 0x56, 0x7e, 0x48, 0x7a, 0x4d, - 0xd6, 0xb6, 0x6e, 0xac, 0x69, 0x91, 0xfc, 0x69, 0xe6, 0xec, 0x7d, 0xde, - 0x37, 0xca, 0x18, 0xf4, 0xdc, 0x71, 0xc5, 0x79, 0x3e, 0xb1, 0x96, 0x62, - 0xb9, 0x82, 0xef, 0x45, 0x1f, 0x56, 0x79, 0xb0, 0x9d, 0x4d, 0x7c, 0xb7, - 0x78, 0xb2, 0xe6, 0x99, 0x7e, 0xef, 0xd9, 0x4c, 0x0b, 0x40, 0xa1, 0x87, - 0xee, 0x0d, 0x3d, 0xf8, 0x7c, 0x62, 0x61, 0x95, 0xb4, 0x25, 0xc1, 0xab, - 0x4f, 0xdb, 0x47, 0xd5, 0x1f, 0xf7, 0x26, 0xf1, 0xe7, 0x9f, 0xe7, 0xcb, - 0x80, 0x74, 0xf1, 0x09, 0x5b, 0xfe, 0x50, 0xef, 0x9c, 0x84, 0xdf, 0xf1, - 0x1e, 0xc4, 0x71, 0x96, 0x6d, 0xca, 0xbe, 0x0d, 0x7a, 0x27, 0x2f, 0x06, - 0x7a, 0x09, 0xc5, 0x9a, 0x2e, 0xce, 0x9e, 0xf5, 0x49, 0xb9, 0x0a, 0x5c, - 0x19, 0xf4, 0x95, 0x6e, 0x6f, 0x34, 0x85, 0xf8, 0xb8, 0x06, 0xfb, 0xbc, - 0x6c, 0xf1, 0x3e, 0x26, 0xcc, 0x7c, 0x27, 0xa5, 0xfa, 0xbf, 0x00, 0x86, - 0xf5, 0xd5, 0xed, 0xbb, 0x96, 0x05, 0xc0, 0x2c, 0x62, 0xed, 0x84, 0x1b, - 0x97, 0x19, 0xdb, 0x1d, 0x85, 0xda, 0xa3, 0x60, 0xfd, 0xb7, 0xc3, 0x3a, - 0xeb, 0x36, 0xec, 0x76, 0x77, 0x21, 0xc8, 0x39, 0xf3, 0x89, 0xd9, 0x05, - 0xc4, 0xf0, 0xaa, 0xa5, 0x76, 0x2b, 0x6d, 0x91, 0x89, 0x2a, 0x62, 0x12, - 0xba, 0xde, 0x44, 0x7c, 0x41, 0xfe, 0x53, 0xeb, 0xa1, 0xc5, 0x1a, 0x36, - 0x7b, 0xd4, 0xe7, 0x68, 0x57, 0x9a, 0xf2, 0xd0, 0x29, 0xe4, 0xe5, 0x91, - 0xc7, 0x90, 0x73, 0x20, 0xaf, 0x53, 0x45, 0x74, 0xf2, 0xb4, 0x91, 0x37, - 0x7e, 0xab, 0x60, 0xb9, 0x7d, 0x80, 0xce, 0x67, 0xe2, 0xf2, 0x18, 0x3a, - 0xd5, 0xa1, 0xe3, 0x4c, 0x5e, 0xc7, 0x9b, 0x7e, 0x73, 0x52, 0xb5, 0xa3, - 0xc6, 0x40, 0x01, 0x8a, 0x0a, 0xc7, 0x1c, 0x14, 0xd9, 0x3b, 0x87, 0xb8, - 0x82, 0x38, 0xbc, 0x77, 0x15, 0xd1, 0xed, 0x14, 0xe1, 0x95, 0x84, 0x4f, - 0x85, 0xa4, 0xe5, 0x14, 0xef, 0x43, 0x64, 0x0f, 0xfa, 0x31, 0xe2, 0xdc, - 0x1b, 0xc6, 0x73, 0x1c, 0x7f, 0xfb, 0x51, 0x5b, 0x99, 0xa8, 0x91, 0xb7, - 0x81, 0x07, 0x2c, 0xf7, 0x6c, 0x07, 0x6f, 0x76, 0x4b, 0x7b, 0x04, 0x7b, - 0x08, 0x1f, 0x06, 0x1d, 0x7b, 0x40, 0x8f, 0x7b, 0x3e, 0x71, 0x84, 0x4f, - 0x89, 0xf4, 0xcf, 0x49, 0x8f, 0xd2, 0x7b, 0xc2, 0x52, 0x48, 0x71, 0xad, - 0x03, 0xf0, 0xdc, 0x87, 0x35, 0xbd, 0xcf, 0xbd, 0x57, 0xca, 0xdf, 0xa6, - 0x1b, 0x73, 0x06, 0xde, 0x51, 0x4f, 0xa5, 0x4c, 0xe9, 0xaf, 0xb9, 0xb0, - 0x7b, 0x57, 0xbf, 0xd4, 0xcd, 0xbb, 0x29, 0x65, 0xb9, 0xb4, 0x29, 0xd4, - 0xc4, 0x79, 0x48, 0x35, 0x3c, 0xc8, 0xfb, 0x19, 0xc2, 0xb0, 0xaf, 0x35, - 0x35, 0x8c, 0x39, 0x48, 0xf9, 0xb9, 0x73, 0x4a, 0xfd, 0x6f, 0xf7, 0x2e, - 0xcd, 0x35, 0x85, 0xf6, 0x15, 0xec, 0xff, 0x43, 0xed, 0x2b, 0xa2, 0xe2, - 0x9e, 0xaf, 0xe0, 0x7b, 0x91, 0xdf, 0x7e, 0x2e, 0xfe, 0xed, 0xbb, 0xdc, - 0x78, 0xef, 0xc8, 0xb4, 0xcd, 0x3b, 0x0c, 0x47, 0x2e, 0xdb, 0x45, 0xe3, - 0x91, 0x4d, 0x75, 0x66, 0x52, 0xe7, 0xe7, 0x02, 0x64, 0xbf, 0x5e, 0xd7, - 0x3d, 0x9b, 0x5c, 0xa9, 0x47, 0xe4, 0xea, 0x52, 0xbb, 0xac, 0x2f, 0xb8, - 0x36, 0xbf, 0xbe, 0x40, 0x3b, 0x37, 0xe5, 0xed, 0x25, 0x0b, 0x6b, 0x49, - 0xfc, 0xf5, 0xc8, 0xf5, 0xa5, 0xcd, 0x75, 0xe7, 0x85, 0xc6, 0xc3, 0xa0, - 0xa5, 0x47, 0x42, 0x96, 0xa3, 0xfb, 0xaf, 0x1c, 0x72, 0x5f, 0x51, 0xc6, - 0x25, 0x5f, 0xe9, 0x47, 0x0f, 0x88, 0xe4, 0x1c, 0x66, 0x0e, 0x82, 0xfe, - 0x2b, 0x9f, 0x40, 0x6d, 0x92, 0x80, 0xf3, 0xf4, 0xeb, 0x7b, 0xc5, 0x4f, - 0x85, 0x7b, 0xa4, 0xd5, 0xfa, 0xa3, 0x6e, 0x37, 0x57, 0x99, 0x6e, 0x9f, - 0x6a, 0xf9, 0xf9, 0xfa, 0x75, 0xe0, 0x1e, 0x81, 0x9d, 0xd2, 0x36, 0x6d, - 0xd8, 0xac, 0x29, 0xcb, 0x43, 0x89, 0x6a, 0x51, 0x18, 0x1f, 0x52, 0x38, - 0xd3, 0xc0, 0xbe, 0x24, 0xe4, 0xb1, 0x43, 0xd7, 0x42, 0x19, 0x05, 0xdd, - 0xce, 0xcd, 0x48, 0xbe, 0xf1, 0x9b, 0x98, 0xcf, 0xc8, 0x54, 0x63, 0x0c, - 0x67, 0x9d, 0xa4, 0xdd, 0xf6, 0x48, 0x3b, 0xcf, 0x49, 0x81, 0xc6, 0x87, - 0xa4, 0x70, 0x7a, 0x46, 0x0e, 0x57, 0x48, 0x27, 0xef, 0x19, 0x13, 0xc9, - 0x9c, 0x0c, 0xc7, 0x97, 0x50, 0x3b, 0xb9, 0xfe, 0x98, 0x96, 0xc2, 0x19, - 0xe0, 0xa8, 0xf0, 0x1e, 0xa0, 0x1f, 0x76, 0x33, 0xac, 0xfb, 0x9a, 0x29, - 0x1d, 0x77, 0x38, 0xff, 0x43, 0xe8, 0xa9, 0xbf, 0xb8, 0x1f, 0x70, 0x79, - 0xf4, 0x40, 0x93, 0xa8, 0x97, 0x17, 0x2b, 0xe8, 0xf7, 0xec, 0x10, 0x6b, - 0x2f, 0xa5, 0xee, 0xef, 0x93, 0x5a, 0x65, 0xd8, 0x54, 0x8a, 0x35, 0x15, - 0x75, 0xc1, 0x35, 0xfa, 0x77, 0x4c, 0x85, 0xad, 0x3e, 0x59, 0xaa, 0x14, - 0xd1, 0x37, 0x2b, 0xef, 0x5e, 0x03, 0x16, 0x60, 0xb9, 0x71, 0x2f, 0xa3, - 0xc8, 0x37, 0xea, 0xcf, 0xc6, 0x27, 0x41, 0x63, 0x26, 0x6e, 0xca, 0x71, - 0xd0, 0x87, 0xf7, 0x45, 0xd8, 0xf8, 0x1c, 0x6b, 0xb8, 0x0c, 0xd6, 0xd2, - 0x72, 0xe4, 0xec, 0x24, 0x68, 0xe8, 0x92, 0xfe, 0x3f, 0xa1, 0x8f, 0x3d, - 0x81, 0x39, 0x7e, 0x27, 0x60, 0xaf, 0x5f, 0xc4, 0x3b, 0x61, 0x63, 0x78, - 0x52, 0x0e, 0x7d, 0x78, 0x9a, 0xa0, 0x25, 0xe2, 0xf6, 0x26, 0x87, 0xe2, - 0x52, 0x3b, 0xfd, 0xa0, 0x4c, 0x2d, 0x3e, 0x08, 0xfc, 0x3f, 0x42, 0x5f, - 0x80, 0xfc, 0xb6, 0xc8, 0xb3, 0x58, 0xff, 0xf1, 0x9c, 0x9d, 0x3d, 0xda, - 0x37, 0xe6, 0x38, 0xcf, 0xe7, 0x41, 0xec, 0x47, 0x8f, 0x51, 0xc9, 0x48, - 0xa1, 0xc2, 0xb3, 0xa0, 0x3b, 0xd4, 0x53, 0xf9, 0xd3, 0x93, 0x9e, 0x8e, - 0x7b, 0x24, 0x17, 0x2d, 0xb2, 0xbf, 0x40, 0x9e, 0x58, 0x18, 0xcd, 0x96, - 0x13, 0x66, 0x56, 0x11, 0x57, 0x52, 0x98, 0x1b, 0xdc, 0xb9, 0x88, 0x58, - 0x73, 0xe8, 0x6d, 0xd3, 0x5c, 0x3b, 0xee, 0xdd, 0x1d, 0x10, 0xd7, 0x9b, - 0x32, 0x0e, 0x1b, 0xeb, 0x9f, 0x1b, 0x41, 0x2d, 0xfc, 0x16, 0x6a, 0xc9, - 0x84, 0x27, 0x83, 0x31, 0xcf, 0x36, 0xda, 0x9b, 0x6c, 0x02, 0x7a, 0xae, - 0x40, 0xf7, 0x15, 0xd8, 0x01, 0x62, 0xf5, 0x2b, 0x1b, 0xf6, 0x31, 0xd6, - 0x54, 0x63, 0x76, 0xca, 0xdf, 0x54, 0x13, 0xc9, 0x35, 0xd8, 0xcf, 0x75, - 0xf4, 0x02, 0x6b, 0xe8, 0x55, 0xd7, 0xd1, 0xd7, 0x2d, 0x96, 0x0f, 0x81, - 0x7e, 0xd6, 0x94, 0xfc, 0x8e, 0xe9, 0x5a, 0xa7, 0xcd, 0x7a, 0xe1, 0x2e, - 0x7d, 0xb7, 0x2b, 0x4f, 0xf4, 0xb0, 0xd7, 0x64, 0x5f, 0xce, 0x7b, 0xe9, - 0xab, 0xd0, 0xe3, 0x9a, 0xc9, 0x75, 0x7f, 0x1f, 0x7b, 0x01, 0xdf, 0x7e, - 0x48, 0x0b, 0xed, 0x87, 0x7b, 0x08, 0xd3, 0xa3, 0xfd, 0x24, 0xaf, 0xf1, - 0xd1, 0x66, 0xeb, 0xdd, 0xae, 0x9f, 0xe9, 0x3a, 0xcb, 0xbc, 0x22, 0xbe, - 0xfd, 0xbe, 0xe7, 0xb0, 0xaf, 0xcb, 0x0e, 0x21, 0x76, 0x37, 0x1c, 0x79, - 0xc1, 0xde, 0xec, 0x77, 0x07, 0x2a, 0xbe, 0x9c, 0x28, 0xc7, 0x43, 0x72, - 0xa2, 0x91, 0x80, 0x4f, 0x50, 0x86, 0x56, 0x93, 0x0c, 0x45, 0xbe, 0x5e, - 0x11, 0x79, 0xb9, 0xc2, 0x35, 0x2d, 0xc3, 0x58, 0x36, 0xd4, 0xce, 0xbb, - 0x75, 0xd8, 0xe5, 0xdf, 0xcb, 0xe1, 0x79, 0x91, 0xb3, 0x58, 0x5f, 0xae, - 0xd0, 0x57, 0x47, 0x50, 0xbf, 0xee, 0x94, 0xda, 0x02, 0x7a, 0xb2, 0x8a, - 0x4c, 0x65, 0x1f, 0x60, 0xbe, 0x89, 0xc8, 0xba, 0xbe, 0x93, 0x15, 0x19, - 0x3c, 0x17, 0x96, 0xf0, 0x39, 0x34, 0x7f, 0x90, 0xfd, 0xf9, 0x21, 0xff, - 0x8e, 0xd6, 0xf5, 0xf9, 0x52, 0x19, 0x7b, 0x2b, 0xfd, 0x3a, 0x4e, 0x96, - 0xea, 0x05, 0xc9, 0x57, 0x79, 0x16, 0x9e, 0x0b, 0x71, 0xac, 0xa5, 0x64, - 0xfa, 0xf4, 0x88, 0x3c, 0x8b, 0x33, 0xd0, 0xff, 0xe1, 0x8c, 0x71, 0x29, - 0x9e, 0xc5, 0x7c, 0xfd, 0x9a, 0x2c, 0x2c, 0x15, 0xa4, 0x56, 0xbd, 0xd0, - 0x74, 0xf7, 0x8e, 0xef, 0x85, 0xe6, 0x5e, 0xf6, 0x10, 0xfb, 0x19, 0xf4, - 0xaa, 0x16, 0xbe, 0x21, 0xb3, 0xfa, 0xf4, 0xd4, 0xe6, 0x3b, 0xe3, 0xe6, - 0x1e, 0x76, 0x42, 0x66, 0x2b, 0x29, 0x29, 0x9d, 0x1e, 0xd1, 0x77, 0x0d, - 0x6d, 0xe9, 0xea, 0xd3, 0x37, 0x90, 0x2b, 0x26, 0xf4, 0x9d, 0xf1, 0x2d, - 0x79, 0xd4, 0x9e, 0x95, 0x27, 0xad, 0x83, 0x72, 0x02, 0xf5, 0xf5, 0xa7, - 0xd1, 0xeb, 0xc7, 0xbb, 0xa9, 0x47, 0xd0, 0x6b, 0xb1, 0x07, 0x75, 0x64, - 0xdc, 0xfe, 0xb8, 0xf9, 0x3c, 0x24, 0x7b, 0xb5, 0xce, 0x3c, 0xf9, 0x5f, - 0x4e, 0x06, 0x79, 0xef, 0x06, 0x7a, 0xc7, 0x8c, 0x86, 0x33, 0x5c, 0xb8, - 0x2a, 0xe1, 0x86, 0xcd, 0x17, 0x08, 0xb7, 0x60, 0x78, 0x70, 0x06, 0xe0, - 0x42, 0x72, 0xd1, 0x0e, 0xc3, 0x46, 0x26, 0xc0, 0x27, 0x62, 0xfc, 0x68, - 0xa7, 0x57, 0x07, 0xef, 0x40, 0x6e, 0xbd, 0xbd, 0xff, 0x35, 0x6f, 0xff, - 0xb3, 0xde, 0xfe, 0xcb, 0x1b, 0xfb, 0xfd, 0xfc, 0xfa, 0x13, 0x47, 0x9a, - 0xe8, 0x7a, 0xad, 0xec, 0xc2, 0xcf, 0x7a, 0x74, 0x5d, 0xde, 0xa0, 0xcb, - 0x87, 0x87, 0x3c, 0x35, 0xcf, 0x8c, 0xcd, 0x8c, 0xd1, 0xfd, 0x90, 0xa3, - 0x23, 0x39, 0x1b, 0xbe, 0x51, 0x49, 0x8c, 0x15, 0xf5, 0x9d, 0x9a, 0x92, - 0xb5, 0xe8, 0xac, 0x4c, 0x58, 0x89, 0xb1, 0x69, 0x09, 0xc1, 0x96, 0x19, - 0x5b, 0x42, 0x52, 0x63, 0xcc, 0xc1, 0x33, 0x6f, 0x6f, 0x4f, 0xeb, 0xd5, - 0x26, 0x5a, 0x43, 0x2f, 0x91, 0x46, 0x97, 0xd6, 0xc8, 0xc0, 0x6d, 0x5a, - 0x5d, 0x78, 0x97, 0xd6, 0xab, 0xe5, 0x26, 0xf8, 0x73, 0x61, 0x0f, 0x3e, - 0xdc, 0x04, 0x4f, 0x7b, 0x66, 0x5d, 0x41, 0x7b, 0x26, 0x6d, 0x3f, 0x0b, - 0xdf, 0x90, 0xc8, 0x8e, 0x74, 0xf5, 0xe8, 0x7d, 0x03, 0x8e, 0x44, 0x50, - 0x6f, 0xb4, 0x62, 0x6d, 0xbd, 0xca, 0x5a, 0x44, 0xed, 0x6d, 0x95, 0x41, - 0xd8, 0x2c, 0x75, 0xe7, 0xde, 0x0d, 0x3e, 0xaa, 0x6b, 0x02, 0x47, 0x9e, - 0xb4, 0x49, 0xcb, 0x8f, 0x9d, 0x97, 0xa3, 0x83, 0x76, 0x49, 0x86, 0xcc, - 0x56, 0x9c, 0x5f, 0x6b, 0x68, 0x9c, 0x49, 0xd2, 0xb2, 0x32, 0xd4, 0x6f, - 0x7e, 0x0f, 0x7c, 0x8e, 0x57, 0x0d, 0xa9, 0x59, 0x89, 0xd8, 0x79, 0xe0, - 0xd8, 0x0f, 0xdd, 0xd4, 0x46, 0x48, 0x8f, 0xc8, 0x61, 0xd8, 0x77, 0x4d, - 0xe7, 0x45, 0xda, 0x71, 0x62, 0xa2, 0x88, 0x5a, 0xe7, 0x2f, 0x75, 0x6e, - 0x73, 0x9c, 0x1b, 0xc8, 0x6f, 0x13, 0x5b, 0x6c, 0x4f, 0x9d, 0x73, 0x6d, - 0x4f, 0x9d, 0x43, 0x0f, 0x7c, 0x32, 0x22, 0x6d, 0xcb, 0xf0, 0x9f, 0x97, - 0xf6, 0xb8, 0xf5, 0xdc, 0x4b, 0xfc, 0xdd, 0x09, 0xf1, 0xee, 0x64, 0x58, - 0xac, 0x93, 0x3a, 0x1f, 0x40, 0xde, 0xe3, 0x32, 0x7d, 0x86, 0x31, 0xd5, - 0x92, 0x81, 0x93, 0xd4, 0x07, 0xeb, 0x9a, 0x85, 0xd1, 0x02, 0x7c, 0x64, - 0x06, 0x71, 0x41, 0x2d, 0xdf, 0x94, 0x82, 0x45, 0x39, 0x74, 0x49, 0xfb, - 0x32, 0xfa, 0xf1, 0x65, 0xc4, 0x86, 0xe5, 0x98, 0xb4, 0xc0, 0xb7, 0xd4, - 0xb9, 0xa8, 0x51, 0x9a, 0x7f, 0x17, 0xfe, 0xc0, 0xdf, 0x70, 0x50, 0x5b, - 0x9e, 0x8b, 0x19, 0xf4, 0x2d, 0x75, 0x8e, 0x76, 0x8e, 0x72, 0xea, 0x1c, - 0xed, 0x9c, 0x74, 0xf8, 0xfe, 0x82, 0xf7, 0x73, 0x23, 0xfa, 0x9e, 0xfa, - 0x86, 0x4d, 0x5e, 0x7e, 0x20, 0xd9, 0x2a, 0x6b, 0x44, 0xf2, 0x23, 0xdd, - 0xa8, 0x65, 0x76, 0x65, 0xed, 0x81, 0xb1, 0x75, 0xf9, 0xa8, 0x7c, 0xdd, - 0xf9, 0x11, 0xf8, 0x22, 0x1f, 0xcd, 0x7c, 0x91, 0xa7, 0x2e, 0x69, 0xd1, - 0x7c, 0xf9, 0xfc, 0x40, 0xd0, 0xe0, 0x67, 0xef, 0xc9, 0x18, 0xf0, 0x7f, - 0x11, 0x31, 0xa0, 0x0f, 0xcf, 0x27, 0xf0, 0x44, 0x4a, 0x3b, 0x47, 0xde, - 0xc9, 0xeb, 0x75, 0xd4, 0x8d, 0x3e, 0x9f, 0x53, 0x78, 0x7f, 0x55, 0xa6, - 0xe7, 0x9d, 0xe3, 0xc8, 0xab, 0xbc, 0x43, 0xef, 0x71, 0xef, 0x83, 0xb7, - 0xf2, 0xfe, 0xaa, 0xb8, 0xf2, 0x49, 0x98, 0x35, 0xc1, 0xfb, 0xd2, 0x56, - 0x59, 0x34, 0xc7, 0x8e, 0x98, 0xae, 0xc3, 0x0f, 0xd7, 0x19, 0x27, 0x28, - 0xa3, 0xeb, 0x92, 0x9d, 0xe7, 0xfd, 0x97, 0x8b, 0x6f, 0xaa, 0xee, 0xc7, - 0x8d, 0xe6, 0x3d, 0x36, 0xe0, 0xfa, 0x00, 0x47, 0xba, 0xd6, 0x28, 0x3f, - 0xc4, 0x9c, 0xde, 0xa6, 0x58, 0xd3, 0xbc, 0x6f, 0x4c, 0x9e, 0x43, 0x1d, - 0xf0, 0x9a, 0xbd, 0x49, 0xae, 0x53, 0xac, 0x85, 0x6a, 0xf5, 0x49, 0xf8, - 0x64, 0x0b, 0x62, 0x99, 0x29, 0xeb, 0xe5, 0x56, 0xa9, 0xa1, 0xde, 0x59, - 0x5c, 0x62, 0x2c, 0x24, 0xed, 0xed, 0x98, 0x77, 0xe3, 0x17, 0x63, 0xed, - 0x7a, 0x19, 0x79, 0x16, 0xbe, 0xbd, 0x5e, 0x8e, 0xe2, 0xd9, 0x87, 0xa7, - 0x85, 0x67, 0x1c, 0xcf, 0x24, 0x9e, 0x23, 0x78, 0x8e, 0xe0, 0x69, 0x61, - 0x6f, 0x0c, 0x4f, 0xbf, 0x67, 0x20, 0xae, 0xdb, 0x7c, 0x97, 0xf4, 0x79, - 0xa8, 0x15, 0x2d, 0xe6, 0xb4, 0xb0, 0x9d, 0x43, 0x1f, 0x91, 0x1d, 0x61, - 0xad, 0xc7, 0x9a, 0xef, 0x03, 0xc7, 0xb4, 0xd8, 0x97, 0x17, 0x8d, 0xfd, - 0x43, 0xcc, 0x0b, 0x55, 0xe4, 0x85, 0xf7, 0x76, 0xa3, 0x7f, 0x34, 0x0f, - 0xe8, 0xbb, 0xa3, 0x79, 0x7c, 0xf3, 0x1d, 0x3d, 0x6f, 0x74, 0x06, 0x79, - 0x8a, 0xf1, 0xd3, 0xc1, 0x9e, 0x3c, 0xe2, 0xf8, 0x2e, 0xf8, 0x5f, 0x06, - 0x71, 0x1b, 0xef, 0x0b, 0x97, 0x76, 0xbb, 0x39, 0x15, 0xf9, 0x56, 0x6d, - 0xbd, 0xaf, 0xb1, 0xb1, 0x67, 0xbb, 0xde, 0xa0, 0x13, 0x38, 0x12, 0xd5, - 0x05, 0xf8, 0xe0, 0xf7, 0xed, 0xe3, 0xba, 0xb6, 0xa3, 0x2e, 0x9e, 0x45, - 0x8d, 0x9a, 0x9b, 0x63, 0x0d, 0x73, 0x0c, 0x7d, 0x09, 0xfa, 0xb3, 0x28, - 0x7b, 0x72, 0xe6, 0x02, 0x5d, 0x8b, 0x46, 0xa5, 0x9d, 0x79, 0xe0, 0x06, - 0xce, 0x03, 0x5f, 0x8b, 0x0e, 0x64, 0xf6, 0x08, 0x6a, 0x42, 0xc7, 0x09, - 0x5b, 0xfb, 0x25, 0xfe, 0x38, 0x63, 0x8e, 0x60, 0xbf, 0x29, 0xee, 0xbd, - 0x3a, 0xe2, 0xee, 0xa4, 0xfe, 0xbd, 0x18, 0xc6, 0x65, 0x63, 0xef, 0x1d, - 0xc0, 0xc5, 0x79, 0xde, 0x69, 0x8b, 0xec, 0x9f, 0x73, 0x6b, 0x5a, 0x65, - 0x35, 0xe3, 0xfb, 0x39, 0x0f, 0x1f, 0xd7, 0x95, 0xf7, 0xdb, 0xc6, 0x1e, - 0xc8, 0x08, 0xfe, 0x00, 0x1d, 0x9f, 0x40, 0xfd, 0x7c, 0x11, 0x7a, 0x79, - 0x0d, 0x3a, 0xb9, 0x54, 0xa6, 0xad, 0x0f, 0xc3, 0xee, 0x21, 0xc3, 0x49, - 0xe2, 0x1a, 0xd1, 0x67, 0x5f, 0x2c, 0x23, 0x76, 0x32, 0xfe, 0xa9, 0x5f, - 0x8d, 0xb2, 0x3e, 0x64, 0x1e, 0x74, 0xf1, 0xf4, 0xb9, 0x70, 0xe2, 0xaf, - 0xed, 0xd6, 0xf4, 0xd4, 0xf4, 0x3d, 0x18, 0xe5, 0x04, 0x1b, 0xe4, 0x6f, - 0x04, 0x1a, 0xe6, 0x0b, 0x51, 0x7d, 0x0f, 0xaf, 0x38, 0x47, 0x3e, 0x46, - 0x24, 0x3b, 0xe7, 0xef, 0xeb, 0xc6, 0xbe, 0x1d, 0x4d, 0xb8, 0xee, 0xdc, - 0xc2, 0x83, 0xf2, 0x78, 0xe0, 0xfa, 0xd6, 0xba, 0x3f, 0x61, 0x16, 0x37, - 0xee, 0x86, 0x99, 0x7f, 0xa9, 0x9b, 0x14, 0xf6, 0xfb, 0xfa, 0xe9, 0xf3, - 0x7a, 0x81, 0xc4, 0x6c, 0x51, 0x58, 0xab, 0x50, 0x47, 0x63, 0xf0, 0x6b, - 0x13, 0xf8, 0x6d, 0xa9, 0x96, 0xdb, 0x44, 0xf5, 0xb0, 0x37, 0x66, 0xad, - 0xdc, 0x7c, 0xe6, 0xaf, 0x78, 0x67, 0xa2, 0x9f, 0x3e, 0xc5, 0xba, 0x59, - 0xe7, 0x19, 0xc0, 0x74, 0x6c, 0xa1, 0xed, 0x17, 0x3d, 0x38, 0xae, 0x27, - 0xa5, 0x88, 0x3a, 0x34, 0x37, 0x87, 0x8a, 0x1e, 0xf1, 0x5b, 0xa5, 0xf9, - 0xbb, 0x16, 0xef, 0xf0, 0x86, 0xe3, 0xd3, 0xa0, 0xb1, 0x68, 0x66, 0x78, - 0x6f, 0x06, 0x1c, 0xbd, 0x5b, 0x70, 0x8c, 0x7b, 0x38, 0xc6, 0xa5, 0x74, - 0x66, 0x02, 0xbe, 0x96, 0x41, 0x7e, 0xef, 0x37, 0x1f, 0x91, 0x4f, 0xa0, - 0xb9, 0xc6, 0xdc, 0xd9, 0x11, 0xe8, 0xc9, 0x71, 0xf6, 0xdb, 0x87, 0x40, - 0xf7, 0x77, 0x90, 0x5b, 0xfd, 0x9a, 0xa7, 0x14, 0x0b, 0x21, 0x87, 0x1d, - 0xd1, 0xbf, 0xc3, 0x16, 0x4d, 0x13, 0xf6, 0xaa, 0x8c, 0xe1, 0x24, 0xda, - 0x7b, 0xe4, 0xb7, 0x59, 0xe4, 0x2a, 0xf2, 0xd9, 0x29, 0x25, 0xd3, 0x78, - 0x38, 0x84, 0xba, 0x26, 0x3b, 0x47, 0x3f, 0x92, 0x81, 0x50, 0xba, 0x15, - 0x35, 0xa9, 0x23, 0x6f, 0xdb, 0xfc, 0x77, 0x0a, 0xb3, 0x72, 0xb1, 0x6e, - 0xe2, 0xf9, 0x5d, 0xe8, 0xe1, 0x4f, 0xf1, 0xfe, 0x76, 0x0f, 0xea, 0x3e, - 0xac, 0x64, 0x60, 0xbb, 0x49, 0x5d, 0xcf, 0xb0, 0x8e, 0xa8, 0x21, 0xdf, - 0x2a, 0xe4, 0x1a, 0xd4, 0x55, 0x63, 0xac, 0x5d, 0x9f, 0x5b, 0xbc, 0x26, - 0x97, 0xe6, 0xf9, 0x3b, 0x28, 0xf3, 0xf2, 0x41, 0xc6, 0x03, 0x73, 0x26, - 0x85, 0xb9, 0x25, 0xc6, 0x32, 0x7c, 0x37, 0xe0, 0x40, 0x3d, 0xa8, 0x11, - 0x50, 0x6b, 0xaf, 0x5b, 0x49, 0xf0, 0x79, 0x4d, 0x2e, 0xce, 0x87, 0x65, - 0xd1, 0x62, 0x5d, 0x24, 0xf1, 0x2c, 0x60, 0x2f, 0x2e, 0xfd, 0x93, 0x6b, - 0x13, 0x84, 0x47, 0xcf, 0x53, 0x44, 0x5d, 0xf7, 0x88, 0xde, 0xfb, 0xd3, - 0xf4, 0x4c, 0x9a, 0x9a, 0xfb, 0xbc, 0x82, 0x5c, 0xa4, 0x3f, 0xe9, 0xdf, - 0x28, 0x58, 0x1b, 0x1c, 0x83, 0xcd, 0xb2, 0x76, 0x67, 0x3f, 0x80, 0xf7, - 0x3a, 0xd7, 0xc9, 0x3b, 0x9e, 0x0b, 0xfd, 0x90, 0x0d, 0xfd, 0x9e, 0x77, - 0x62, 0xc8, 0xa3, 0x8a, 0xbe, 0x5e, 0xd2, 0xb1, 0xa0, 0x54, 0x29, 0x20, - 0xa7, 0x20, 0x06, 0xd8, 0xbd, 0xb0, 0xc5, 0x49, 0xe8, 0x72, 0x0c, 0x70, - 0x5b, 0x72, 0xc9, 0x6a, 0x49, 0xd7, 0x65, 0x6a, 0xe5, 0xf6, 0xfd, 0x4d, - 0x1e, 0xfe, 0xa3, 0x56, 0x61, 0x5b, 0xf0, 0x21, 0xb5, 0x1a, 0xc5, 0x13, - 0xf1, 0x78, 0x15, 0xfd, 0x45, 0x99, 0xf7, 0x43, 0xe8, 0x0d, 0xca, 0xbc, - 0x3b, 0x49, 0xe2, 0x39, 0xc2, 0xfb, 0x22, 0x2f, 0xae, 0x11, 0x3f, 0xe9, - 0xf0, 0xe3, 0x0b, 0x6b, 0x49, 0xc6, 0x17, 0xbf, 0x9e, 0x74, 0x6d, 0xe1, - 0x44, 0x85, 0x31, 0x84, 0x76, 0xdd, 0x8f, 0xb8, 0x45, 0x5b, 0x70, 0x6b, - 0xc9, 0xa5, 0xaa, 0x2b, 0xb3, 0xe9, 0xc6, 0x05, 0x9d, 0x23, 0x0e, 0x88, - 0x05, 0x1b, 0xa3, 0xec, 0xb0, 0xa6, 0x73, 0xc0, 0x79, 0xc9, 0xe8, 0x27, - 0x65, 0xf6, 0xaa, 0x64, 0x96, 0x46, 0xe4, 0x05, 0x1d, 0xb7, 0xfc, 0x98, - 0xc5, 0x1a, 0x92, 0xbf, 0x1f, 0x27, 0xe5, 0xf9, 0xd3, 0xd7, 0x24, 0xfb, - 0x22, 0xe3, 0xd6, 0x70, 0x6c, 0x87, 0xc1, 0x58, 0xe5, 0x48, 0x1d, 0xb9, - 0xe9, 0x11, 0x9b, 0xff, 0x16, 0x20, 0x84, 0x9e, 0xce, 0x91, 0xd6, 0xd1, - 0x84, 0x1d, 0x37, 0xfa, 0x9f, 0xd8, 0x61, 0x30, 0x37, 0x0e, 0x9b, 0x4f, - 0x89, 0x7f, 0x1f, 0xd5, 0x26, 0x4f, 0xe9, 0xbb, 0x0a, 0xb8, 0xed, 0xdc, - 0xfb, 0xfa, 0x77, 0x94, 0x1b, 0x29, 0xca, 0x1a, 0xdf, 0xab, 0x9c, 0x2f, - 0x46, 0x6e, 0xa4, 0x5a, 0xa4, 0x74, 0x87, 0xe3, 0x3c, 0x39, 0xfa, 0xc0, - 0x6e, 0xf7, 0xdf, 0x8b, 0x3c, 0x7d, 0x87, 0x1b, 0x0b, 0x7e, 0xcd, 0xfb, - 0xfe, 0x3a, 0x9e, 0xb4, 0x6d, 0xe6, 0x5b, 0xe6, 0x47, 0xea, 0x0d, 0xcf, - 0x25, 0xbe, 0x33, 0xf7, 0xce, 0x22, 0xf7, 0x32, 0x5f, 0xee, 0x92, 0x1c, - 0x7f, 0xe7, 0x53, 0x7a, 0xbe, 0xe8, 0xd6, 0xd2, 0x1e, 0x5c, 0x75, 0x4a, - 0xa6, 0xab, 0xac, 0xa1, 0x2e, 0x22, 0x97, 0x0d, 0xc1, 0x56, 0x99, 0xd3, - 0x8e, 0x23, 0x9f, 0xf3, 0xf7, 0x69, 0xac, 0x2d, 0x70, 0x5f, 0x22, 0x19, - 0x57, 0xcd, 0xbf, 0x2b, 0xdd, 0x8c, 0xf2, 0x3e, 0xea, 0xfc, 0x10, 0xf4, - 0xfe, 0x15, 0xf6, 0x16, 0x03, 0xda, 0x46, 0xb2, 0x2f, 0x51, 0xf6, 0xee, - 0xef, 0xd7, 0xd2, 0xed, 0xfa, 0x00, 0xeb, 0x80, 0xcf, 0x40, 0x2e, 0x07, - 0xec, 0x6b, 0xcc, 0xdd, 0xff, 0xa6, 0xac, 0xe1, 0xe4, 0x53, 0x06, 0x7d, - 0x1b, 0xdf, 0x4b, 0x21, 0x59, 0x88, 0x92, 0x7f, 0xc8, 0xcb, 0xa0, 0xef, - 0x6c, 0x27, 0x87, 0xad, 0x32, 0xf8, 0x0b, 0xc8, 0x80, 0xb2, 0xf4, 0x65, - 0xc0, 0xf7, 0x09, 0xe8, 0x8b, 0x3d, 0x43, 0xbf, 0xee, 0x23, 0x4b, 0x0d, - 0xf7, 0xec, 0x52, 0xa5, 0x99, 0x66, 0xd2, 0x4b, 0x9d, 0x9e, 0x97, 0x9c, - 0xd6, 0xef, 0xac, 0xe4, 0xaa, 0xe7, 0x65, 0x7f, 0x75, 0x56, 0x1e, 0xb5, - 0x1e, 0x06, 0xbf, 0x57, 0x9c, 0x82, 0xa5, 0x7b, 0x95, 0xb1, 0x3c, 0xce, - 0x2e, 0x8c, 0xf4, 0xca, 0x4d, 0xd4, 0x1d, 0xcf, 0x2e, 0x9a, 0xf2, 0x3f, - 0x9d, 0x5b, 0x5f, 0x6c, 0x5b, 0xd5, 0x19, 0xff, 0x7c, 0x6d, 0x27, 0x69, - 0x68, 0xc2, 0xad, 0xeb, 0x24, 0x6e, 0x9a, 0x51, 0x3b, 0xbe, 0x6d, 0x23, - 0x92, 0xa2, 0xdb, 0x10, 0x68, 0xd4, 0x65, 0x8a, 0x71, 0x42, 0x17, 0xb6, - 0x22, 0xd2, 0xae, 0xab, 0x2a, 0x8d, 0x81, 0xe5, 0xa6, 0x7f, 0xd8, 0xc3, - 0x0a, 0x85, 0x75, 0x08, 0x21, 0xd5, 0xb8, 0xe9, 0xd6, 0x69, 0x21, 0x4e, - 0xff, 0x2d, 0x8c, 0x87, 0xcd, 0x4a, 0xd2, 0x96, 0x4d, 0x11, 0x2e, 0x88, - 0xb2, 0x3d, 0x6c, 0xa3, 0x4a, 0x01, 0xed, 0x79, 0x7b, 0x99, 0x34, 0x36, - 0x65, 0x05, 0x36, 0x5e, 0x36, 0xf5, 0x81, 0x07, 0xa6, 0xd1, 0x79, 0xbf, - 0xdf, 0x77, 0xee, 0x75, 0x6c, 0x13, 0x84, 0xb4, 0x48, 0x91, 0xef, 0x39, - 0xf7, 0xdc, 0x73, 0xce, 0x3d, 0xdf, 0xff, 0xef, 0xfb, 0xdd, 0x8c, 0x3d, - 0x28, 0x3f, 0xd2, 0x5c, 0x3e, 0xe3, 0x93, 0x00, 0x7c, 0x52, 0x83, 0x2d, - 0x90, 0x36, 0x27, 0x76, 0x53, 0xe8, 0x53, 0x86, 0x41, 0xeb, 0xb8, 0xf1, - 0x9b, 0x6d, 0x73, 0x7f, 0xcb, 0x59, 0xf8, 0xee, 0xee, 0x7d, 0x6d, 0x7e, - 0xce, 0xd7, 0xf8, 0xb7, 0x7f, 0xf2, 0x6a, 0x68, 0x83, 0x32, 0x83, 0xfd, - 0xbc, 0xa1, 0x7a, 0xd6, 0x01, 0x2f, 0x31, 0x37, 0x1d, 0xd3, 0xfc, 0x43, - 0x78, 0x9a, 0x3a, 0xea, 0x2a, 0x74, 0xd4, 0x10, 0x75, 0xd7, 0xf0, 0xbc, - 0xcb, 0xfc, 0x40, 0x54, 0xfe, 0x38, 0x45, 0x3d, 0x1c, 0x97, 0x3f, 0x4c, - 0x3d, 0x8b, 0xfd, 0x24, 0x8a, 0xcc, 0x51, 0xde, 0x98, 0xc9, 0xd1, 0x4f, - 0x52, 0x7f, 0x3e, 0xed, 0x3e, 0xad, 0x76, 0x20, 0x6e, 0xe5, 0xd7, 0x87, - 0x55, 0xdf, 0x1c, 0xd3, 0xda, 0x6e, 0xdc, 0xea, 0x92, 0x1b, 0x17, 0x8c, - 0x8e, 0x0d, 0x4f, 0x47, 0x03, 0x23, 0x0b, 0xb4, 0x4b, 0xc9, 0x58, 0xd6, - 0x6a, 0x94, 0x43, 0x51, 0xe6, 0x9e, 0x53, 0xd4, 0xcf, 0xb0, 0x85, 0xbd, - 0x76, 0xd6, 0x6a, 0xf2, 0xec, 0x4f, 0xac, 0x4e, 0xcf, 0x1e, 0xf3, 0xf4, - 0x2c, 0xef, 0xa5, 0x68, 0x03, 0x20, 0x93, 0x89, 0x99, 0x51, 0x2b, 0x09, - 0x9b, 0x87, 0xeb, 0x45, 0xce, 0x1f, 0x97, 0xe3, 0x8b, 0x47, 0xe1, 0x7f, - 0xf7, 0xda, 0x7b, 0x69, 0x57, 0xed, 0x21, 0xe2, 0x71, 0xb0, 0xfe, 0x97, - 0xea, 0xe6, 0x7a, 0xd4, 0x9b, 0x8b, 0xf7, 0x21, 0xe7, 0xd3, 0xac, 0xd7, - 0x36, 0x32, 0x9f, 0xa3, 0x7b, 0xad, 0x1d, 0xbb, 0xa7, 0xb2, 0xee, 0x64, - 0xc1, 0xf1, 0xb0, 0x61, 0xf8, 0x85, 0x2f, 0xf4, 0x8d, 0x08, 0xd7, 0xe4, - 0x7a, 0xad, 0x92, 0xde, 0x0f, 0xfd, 0x32, 0xcd, 0xff, 0x9c, 0x57, 0xbb, - 0x42, 0xbc, 0x12, 0xed, 0x5c, 0xc5, 0x36, 0x7d, 0xc5, 0x9b, 0xaf, 0xbf, - 0x5d, 0x9a, 0xa3, 0x55, 0xe3, 0x99, 0x5b, 0x61, 0x3b, 0x2e, 0xb9, 0x45, - 0xfe, 0x96, 0xcb, 0x11, 0xa7, 0x41, 0xf6, 0xda, 0x1b, 0xeb, 0xe6, 0xd8, - 0x86, 0x3e, 0xe3, 0x13, 0x04, 0xa7, 0x03, 0x9e, 0x6f, 0xb1, 0x89, 0x7e, - 0x93, 0x77, 0xdd, 0xa4, 0x39, 0x99, 0xb8, 0xd5, 0x59, 0xf7, 0x1e, 0x9b, - 0x2a, 0x76, 0x38, 0x6e, 0x51, 0x77, 0x36, 0x46, 0xa5, 0x95, 0x3c, 0x54, - 0x56, 0x3f, 0x3e, 0xe4, 0x18, 0xcc, 0x45, 0xd4, 0x39, 0xd2, 0xce, 0x9c, - 0xfd, 0x5b, 0x7a, 0x6e, 0x2d, 0xf4, 0x09, 0x70, 0x0d, 0x3e, 0xf9, 0x4c, - 0xbe, 0x97, 0xb9, 0x5e, 0xcc, 0xdf, 0xcc, 0xf9, 0x5d, 0xef, 0x9c, 0x13, - 0x6e, 0xce, 0xba, 0x5f, 0xb2, 0x17, 0x0c, 0xff, 0xa5, 0x1d, 0xf0, 0x5e, - 0x2b, 0xda, 0x0b, 0xb4, 0x09, 0x9f, 0x37, 0x8f, 0x6f, 0x1b, 0x7a, 0xd4, - 0x36, 0x9c, 0x2a, 0x90, 0x3f, 0xc9, 0x97, 0x3e, 0x3f, 0xfa, 0x3a, 0x8f, - 0x3c, 0x4a, 0x3d, 0x3b, 0x28, 0x67, 0x0b, 0x3c, 0x9b, 0x94, 0xd6, 0xb4, - 0x36, 0x9f, 0x3b, 0xa8, 0x98, 0xac, 0xee, 0xe9, 0xc4, 0x4b, 0x39, 0x19, - 0x96, 0xab, 0x2e, 0xcf, 0x2c, 0x51, 0xcc, 0x04, 0x5b, 0xaa, 0xde, 0x7f, - 0xbf, 0x9e, 0x59, 0x58, 0x7d, 0xc6, 0x18, 0xc6, 0x3e, 0xef, 0xd1, 0xbb, - 0x55, 0xcf, 0x36, 0x53, 0x43, 0x9f, 0xaf, 0xeb, 0x39, 0x85, 0xa1, 0x13, - 0x59, 0xdf, 0x0f, 0x47, 0xf8, 0x0c, 0xd7, 0xa5, 0xcf, 0xc7, 0xb5, 0xc8, - 0x7b, 0xdd, 0xb0, 0xd8, 0xfd, 0x12, 0xdc, 0x09, 0xd1, 0xdf, 0xc9, 0x3a, - 0x72, 0x00, 0xb2, 0xba, 0xd9, 0x60, 0x60, 0xc6, 0x8d, 0xaf, 0x91, 0xb1, - 0xae, 0xe1, 0x1c, 0x11, 0xab, 0xc0, 0x8f, 0x3e, 0xf5, 0x93, 0xdb, 0x98, - 0x2f, 0xe3, 0xf9, 0xeb, 0x03, 0x98, 0xdf, 0xf1, 0xea, 0xea, 0x53, 0xdb, - 0xc9, 0xab, 0xa3, 0x5a, 0x1f, 0xe4, 0x33, 0x94, 0x63, 0x9e, 0x19, 0xe9, - 0xf2, 0x1e, 0x9e, 0x67, 0x7b, 0x5b, 0x1d, 0x1d, 0x93, 0xde, 0xfe, 0xfc, - 0xfb, 0x61, 0x09, 0xb7, 0x53, 0xc7, 0x45, 0x25, 0x39, 0xcd, 0x98, 0x05, - 0xb6, 0x6b, 0x9c, 0x73, 0x7d, 0xb1, 0x2e, 0xce, 0xfc, 0x9f, 0xba, 0x38, - 0x63, 0x7d, 0xa4, 0xbc, 0x13, 0xd6, 0x3c, 0xd6, 0xe7, 0xd3, 0xb5, 0x58, - 0x43, 0x57, 0xbf, 0x76, 0x1f, 0xad, 0xd0, 0xf1, 0x87, 0x05, 0xda, 0xab, - 0x94, 0xe6, 0x94, 0xff, 0x3e, 0xc5, 0xb3, 0xe5, 0x1e, 0xaf, 0x72, 0x8f, - 0xc3, 0x4b, 0x8a, 0x83, 0x7c, 0x58, 0x65, 0xf8, 0x74, 0x81, 0x3a, 0xa6, - 0x45, 0xe6, 0x67, 0x7c, 0x3d, 0x33, 0xe6, 0xf9, 0xb8, 0xf9, 0xf5, 0x0d, - 0xaa, 0x67, 0xe0, 0xdd, 0x38, 0x23, 0x9e, 0x7d, 0xe9, 0x92, 0xb9, 0x0b, - 0xb4, 0xbb, 0x49, 0xf4, 0x45, 0x03, 0x73, 0x0b, 0xac, 0x4d, 0x12, 0x8b, - 0x32, 0x2c, 0xac, 0xfb, 0x8f, 0xd8, 0xa7, 0x20, 0x6f, 0x31, 0x79, 0x7f, - 0x8a, 0x3e, 0x7d, 0x03, 0x7c, 0xe3, 0xd6, 0xba, 0xf3, 0xdd, 0x51, 0xf1, - 0x09, 0x6b, 0xe9, 0x1e, 0xef, 0x90, 0x66, 0xf2, 0xb9, 0x63, 0xdf, 0x10, - 0xfa, 0x60, 0xbc, 0xce, 0x22, 0x16, 0x60, 0xec, 0x11, 0xd7, 0xd8, 0x63, - 0xae, 0xc8, 0xbe, 0x16, 0x2f, 0xaf, 0xd4, 0xa2, 0xbc, 0x42, 0x7e, 0xcb, - 0xa8, 0xff, 0x3d, 0xa4, 0x3a, 0x2b, 0x3f, 0xd5, 0x6b, 0x70, 0x2c, 0x76, - 0x4c, 0x79, 0x4f, 0x6a, 0x78, 0x2f, 0xe6, 0xad, 0x3d, 0xd6, 0x61, 0x7c, - 0x2b, 0x5b, 0xf5, 0x4d, 0x58, 0xc7, 0xd1, 0xae, 0x70, 0x7e, 0xf2, 0x06, - 0x79, 0x84, 0x3a, 0xcf, 0x1f, 0xe7, 0xd3, 0xc3, 0x6f, 0x73, 0x3c, 0xf9, - 0xbf, 0x1a, 0x8b, 0xe0, 0xcb, 0xaa, 0xdf, 0xe7, 0xcb, 0x1d, 0xef, 0x55, - 0xdb, 0x04, 0xca, 0x5d, 0x75, 0x7d, 0xd2, 0x96, 0xc8, 0xf4, 0x0a, 0x5d, - 0xd2, 0xfd, 0xdc, 0xff, 0xf3, 0xcc, 0xed, 0x42, 0xde, 0x56, 0xa3, 0xcd, - 0x09, 0xa5, 0x4d, 0x06, 0xb4, 0x89, 0x28, 0x6d, 0x18, 0xef, 0x3d, 0xe5, - 0xf1, 0x5b, 0x0b, 0xce, 0x8b, 0xb9, 0x5a, 0xe8, 0xba, 0x7d, 0xd4, 0xf9, - 0xcf, 0x76, 0x68, 0x7d, 0xd0, 0xa1, 0xee, 0x5b, 0x0b, 0x7d, 0xc6, 0xf6, - 0x56, 0xf5, 0x47, 0x4c, 0xbc, 0x15, 0xd7, 0x3c, 0x68, 0x10, 0xfa, 0x79, - 0x6e, 0x0a, 0xbe, 0x1a, 0x71, 0x6f, 0x35, 0xb4, 0xfa, 0x8e, 0x77, 0x5e, - 0xf3, 0x4a, 0x1b, 0xca, 0x00, 0xf5, 0xe6, 0x3a, 0xcc, 0xb7, 0x27, 0xda, - 0x07, 0xfe, 0xfa, 0x19, 0xfa, 0x37, 0x6b, 0x3c, 0x11, 0x84, 0xcc, 0xdf, - 0x9c, 0x6a, 0xf7, 0x62, 0x38, 0x07, 0x6d, 0xc4, 0xad, 0x53, 0x11, 0xc6, - 0x14, 0x68, 0xf7, 0x48, 0xc3, 0x34, 0xe2, 0x57, 0xe8, 0xf1, 0x25, 0xb5, - 0x47, 0x7d, 0xb8, 0x7f, 0x07, 0x71, 0x7e, 0xb8, 0x3e, 0x8a, 0xe7, 0x7a, - 0x0d, 0x16, 0x21, 0xba, 0x45, 0xcf, 0x74, 0x6e, 0x2a, 0x11, 0x3b, 0x2c, - 0x5e, 0xdf, 0xb8, 0xab, 0xfa, 0x60, 0x65, 0x5f, 0x0f, 0xca, 0x9e, 0x8a, - 0xbd, 0x60, 0x1c, 0x0d, 0x1f, 0x7e, 0xc6, 0xd8, 0x83, 0x7c, 0xb1, 0x4f, - 0xf1, 0x51, 0xc1, 0xa1, 0x45, 0x9c, 0x25, 0x7d, 0xd2, 0x65, 0xf8, 0xe1, - 0x2e, 0xce, 0x90, 0x7e, 0x77, 0xf9, 0xe4, 0xa4, 0x9b, 0x62, 0x7d, 0x0c, - 0xfa, 0xe0, 0xa4, 0x8c, 0x20, 0x2e, 0x18, 0x09, 0xb6, 0x32, 0xaf, 0x0c, - 0xdf, 0x30, 0xe7, 0xe5, 0x1e, 0xfb, 0x98, 0x33, 0x95, 0x73, 0x0b, 0xdc, - 0x3b, 0x65, 0xdb, 0xc4, 0xde, 0x73, 0x53, 0xdc, 0xaf, 0xc9, 0x43, 0xb0, - 0x6d, 0x4d, 0xbb, 0xf8, 0xe5, 0x59, 0x0c, 0xe0, 0x77, 0x10, 0xf2, 0xc0, - 0xb1, 0xf8, 0x5d, 0x58, 0x96, 0x77, 0x2f, 0xf8, 0xb6, 0x3d, 0x20, 0x6f, - 0x3b, 0xe5, 0x93, 0xa7, 0xdc, 0xf5, 0x3c, 0x03, 0x37, 0xc7, 0x9a, 0xb5, - 0xe3, 0xb8, 0x79, 0x29, 0x97, 0x97, 0xdc, 0xa5, 0xf5, 0x96, 0xd2, 0x92, - 0xf2, 0xbf, 0x8c, 0x33, 0xbc, 0x7e, 0xaf, 0x25, 0x86, 0x7e, 0xa4, 0xcd, - 0x67, 0x6b, 0x7f, 0xd5, 0xb6, 0xc0, 0xd7, 0x7f, 0xe4, 0x47, 0xf2, 0xe5, - 0xb2, 0xec, 0x52, 0xfd, 0xbf, 0xda, 0x73, 0xd5, 0xba, 0xdf, 0xf7, 0x6f, - 0xa9, 0xdf, 0xb5, 0xfe, 0xa3, 0xf1, 0xc1, 0x96, 0xe9, 0x7a, 0x9d, 0xf0, - 0x98, 0x57, 0x57, 0x58, 0x8d, 0xf7, 0x0e, 0x78, 0x7a, 0x21, 0xa5, 0xbe, - 0x73, 0xca, 0xa6, 0x7e, 0xe0, 0x7e, 0x9a, 0xe5, 0xe0, 0xec, 0x6d, 0xd0, - 0xc4, 0xd7, 0xc1, 0x8c, 0xfb, 0x7c, 0xdd, 0xd1, 0xea, 0xf9, 0xc2, 0x96, - 0x74, 0x9f, 0xa3, 0xef, 0xe4, 0x40, 0x8f, 0xb6, 0x49, 0x66, 0x3c, 0x28, - 0xc9, 0x73, 0x1b, 0x62, 0xc6, 0xd7, 0x25, 0xff, 0x41, 0xde, 0xb4, 0x4f, - 0x7d, 0x51, 0xf4, 0xdf, 0x29, 0x5c, 0xdb, 0xf0, 0x33, 0xe4, 0x79, 0x9f, - 0x7f, 0xcf, 0xae, 0xe3, 0xd1, 0x9d, 0x1e, 0x8f, 0xf2, 0xbe, 0x65, 0xea, - 0x1f, 0x18, 0xdb, 0x7d, 0x8e, 0x7b, 0x34, 0xcf, 0x75, 0x9f, 0x33, 0xf1, - 0x7a, 0xed, 0x73, 0x7d, 0x95, 0xe7, 0x70, 0xbf, 0x47, 0xb1, 0x61, 0x98, - 0x7b, 0xd7, 0x20, 0x7c, 0xba, 0x3e, 0xda, 0x1c, 0xda, 0xef, 0xcd, 0xee, - 0x2e, 0x21, 0xbf, 0x27, 0x3c, 0x9e, 0xa3, 0xbe, 0x89, 0x78, 0xfa, 0x66, - 0xc5, 0xbe, 0x8c, 0x18, 0xfc, 0x09, 0x73, 0x22, 0x55, 0xf6, 0xe5, 0x71, - 0xf3, 0x6e, 0x35, 0xf6, 0xe5, 0x4e, 0x6f, 0x1e, 0xff, 0x9e, 0xaf, 0x57, - 0xfc, 0xb6, 0xaf, 0x57, 0xea, 0x7d, 0x5a, 0x9f, 0xf6, 0xb5, 0xb8, 0xaf, - 0xea, 0x98, 0x2f, 0xbf, 0x6a, 0xde, 0x25, 0x8b, 0x98, 0x8d, 0x3e, 0x65, - 0x22, 0x67, 0x30, 0xd3, 0xd6, 0x59, 0x8b, 0xb8, 0x0f, 0xe7, 0xc7, 0x92, - 0x8e, 0xdc, 0xd6, 0xd8, 0xfa, 0xf4, 0xec, 0x98, 0xe6, 0x79, 0xe6, 0x5c, - 0x4f, 0xef, 0x44, 0x77, 0x43, 0xae, 0x5e, 0x89, 0xac, 0x60, 0x8a, 0x66, - 0x4e, 0xa4, 0x61, 0x87, 0x52, 0x5a, 0x2f, 0xfb, 0x2e, 0xf6, 0x3b, 0xa8, - 0x78, 0xae, 0x35, 0xce, 0x73, 0xf2, 0x90, 0x5d, 0xd6, 0xda, 0x4d, 0xd3, - 0x50, 0xf1, 0x44, 0xd3, 0x8b, 0x3e, 0xdf, 0x93, 0x9f, 0x66, 0x4e, 0x1c, - 0x9c, 0x29, 0x0f, 0x87, 0xb6, 0xf7, 0xda, 0x79, 0x21, 0x66, 0x7f, 0x58, - 0x8e, 0x28, 0x76, 0xf8, 0x15, 0xdc, 0xdf, 0xc7, 0xf8, 0x32, 0x11, 0x52, - 0x4c, 0x70, 0x22, 0x36, 0x01, 0x59, 0xcc, 0xba, 0xc4, 0xf8, 0xaf, 0x55, - 0xac, 0xff, 0x9c, 0xd0, 0xcf, 0x22, 0xa6, 0xe0, 0x59, 0x39, 0xec, 0x6e, - 0x76, 0x97, 0xc4, 0xf8, 0xbf, 0x59, 0xad, 0x09, 0x35, 0xca, 0x84, 0x1b, - 0x6a, 0x4a, 0x97, 0x8c, 0x0c, 0x8c, 0x06, 0x53, 0x6b, 0x26, 0x9d, 0x68, - 0xd3, 0xae, 0x12, 0x64, 0xbc, 0x04, 0xfd, 0x5f, 0x8a, 0x05, 0x46, 0x14, - 0x9b, 0xf6, 0x65, 0x49, 0xb7, 0xd3, 0xcf, 0xa7, 0x3e, 0xf9, 0x8a, 0xdc, - 0xb4, 0xb7, 0xca, 0xcd, 0x1e, 0xe2, 0x31, 0xfb, 0xd1, 0xa6, 0x2e, 0x19, - 0x44, 0x5f, 0x12, 0x7d, 0x4d, 0xca, 0x8f, 0x1a, 0x9f, 0x41, 0x67, 0xdd, - 0xb4, 0xa9, 0xab, 0xee, 0xe2, 0x2f, 0xde, 0xf5, 0x6f, 0xa0, 0x09, 0xb1, - 0x1d, 0xdb, 0xd0, 0xa6, 0x8e, 0xb3, 0xeb, 0xfa, 0x3b, 0xd1, 0xbe, 0x17, - 0x73, 0x34, 0xe8, 0xfb, 0x59, 0xce, 0x76, 0x53, 0xe7, 0xac, 0x19, 0xb3, - 0xae, 0xae, 0xfd, 0xfb, 0x36, 0x83, 0x4f, 0xf8, 0x94, 0xf4, 0xce, 0xa5, - 0xe4, 0xe1, 0x8e, 0xda, 0xf6, 0xbf, 0xea, 0xda, 0xad, 0xb2, 0xa6, 0x8d, - 0x64, 0x38, 0xd6, 0x5e, 0xdb, 0xef, 0xf3, 0x93, 0xdf, 0xee, 0xc0, 0xfb, - 0x42, 0x66, 0xac, 0xa4, 0xc6, 0x52, 0x37, 0xa3, 0x5c, 0xeb, 0xc3, 0xba, - 0x67, 0x78, 0xcd, 0x67, 0xf8, 0x2c, 0xf3, 0x7a, 0xb7, 0xd9, 0x8f, 0x67, - 0x98, 0x13, 0x60, 0x5e, 0x83, 0x3c, 0xbb, 0x5a, 0x9c, 0xc5, 0x31, 0x9f, - 0xcd, 0x37, 0x64, 0x2a, 0xbc, 0xe7, 0xeb, 0x95, 0x58, 0x05, 0xab, 0xb6, - 0xab, 0xe0, 0xe7, 0x84, 0x49, 0x3b, 0xad, 0x49, 0xc5, 0x6e, 0x80, 0xce, - 0x87, 0x40, 0xe7, 0x07, 0x83, 0x8c, 0x0b, 0x9b, 0x3d, 0x5a, 0x3b, 0x32, - 0x52, 0xfa, 0x0d, 0x64, 0x9c, 0x3c, 0x0a, 0x9f, 0xa2, 0x64, 0x79, 0xf8, - 0x8c, 0x01, 0xd8, 0x34, 0x57, 0x82, 0x9a, 0x77, 0x40, 0x7c, 0x3f, 0x7f, - 0x5d, 0x46, 0xa6, 0x98, 0x13, 0x20, 0x3f, 0x33, 0xae, 0x4f, 0xe1, 0xde, - 0x2d, 0x8c, 0x75, 0x21, 0xc3, 0x63, 0xe0, 0xd7, 0x90, 0x38, 0xd3, 0xdb, - 0x24, 0x37, 0x3e, 0xa6, 0x3e, 0x40, 0x37, 0x6c, 0xd4, 0x29, 0x77, 0x54, - 0x26, 0xaf, 0x6c, 0x82, 0xac, 0x32, 0xee, 0xd7, 0x9c, 0x46, 0x39, 0xac, - 0xbe, 0x39, 0x7d, 0x0e, 0xe6, 0xe1, 0x4c, 0x8d, 0xd9, 0xc8, 0xed, 0xa1, - 0x98, 0xb4, 0x8e, 0xca, 0xcc, 0xac, 0xad, 0x78, 0x97, 0x94, 0xdc, 0x2e, - 0x93, 0x76, 0xd9, 0x7d, 0x71, 0xe8, 0x2a, 0xfa, 0xf2, 0x3f, 0x88, 0x98, - 0xb3, 0xdc, 0xbd, 0x81, 0x31, 0x71, 0x72, 0xba, 0x7a, 0x0e, 0xc5, 0xc8, - 0xe0, 0xde, 0x2f, 0xdb, 0x8c, 0xcc, 0x30, 0x3e, 0xfe, 0xa0, 0x9c, 0x8a, - 0x72, 0x4d, 0x8e, 0x65, 0xed, 0x96, 0x3c, 0xc2, 0xbd, 0xfd, 0xc7, 0xe3, - 0xe5, 0x97, 0x31, 0x5f, 0x5c, 0xba, 0x5f, 0x1d, 0xd3, 0xb8, 0xfe, 0x54, - 0x4d, 0x0c, 0x6b, 0xf2, 0x05, 0x26, 0x8e, 0xbd, 0x2e, 0x13, 0x8b, 0xa4, - 0x0f, 0x6d, 0x7c, 0x40, 0x7e, 0xe1, 0xf4, 0xda, 0x4f, 0x68, 0xad, 0x31, - 0x91, 0x62, 0x7d, 0xa6, 0xd9, 0x49, 0xda, 0xf3, 0x12, 0x1a, 0xfc, 0x1a, - 0xae, 0x19, 0xd7, 0xe6, 0xdd, 0x5e, 0xf7, 0x09, 0xf1, 0x71, 0x20, 0x9b, - 0x53, 0x8d, 0x81, 0x4f, 0xca, 0xd7, 0xf7, 0x71, 0x8c, 0xc1, 0x81, 0x48, - 0x80, 0xb4, 0x7a, 0xef, 0x2e, 0xe2, 0x67, 0x6a, 0xf3, 0x7f, 0x0f, 0x1c, - 0xdb, 0x3b, 0x90, 0x38, 0xc3, 0x18, 0x36, 0xec, 0x3c, 0xba, 0xc1, 0xbc, - 0x6b, 0x2e, 0xb7, 0x4e, 0xb4, 0x7e, 0x76, 0xfc, 0x1f, 0x0e, 0xf1, 0x10, - 0x89, 0x58, 0xa3, 0xc5, 0x3c, 0x38, 0x75, 0x1c, 0x6b, 0x2a, 0xcc, 0xb9, - 0x11, 0xcb, 0xdf, 0x24, 0x97, 0xfb, 0x2c, 0x79, 0x20, 0x94, 0x8a, 0x5b, - 0xb2, 0x25, 0x7e, 0x4e, 0xb0, 0x26, 0xeb, 0x2b, 0x8b, 0x89, 0x1c, 0xc7, - 0x87, 0xa6, 0x39, 0x5f, 0x5c, 0xe3, 0x95, 0xe4, 0x96, 0x72, 0xf9, 0x29, - 0x57, 0x02, 0xc9, 0x7b, 0x3e, 0x2c, 0xb3, 0x16, 0x6e, 0xbd, 0xfa, 0x79, - 0x38, 0x05, 0xea, 0x0a, 0x7b, 0xc2, 0x60, 0x0e, 0x27, 0x8f, 0x77, 0x2f, - 0xb2, 0xfd, 0xe4, 0x43, 0xa6, 0x7d, 0x06, 0xed, 0x06, 0x0f, 0xeb, 0x34, - 0x75, 0xbc, 0xbb, 0x78, 0x6c, 0x83, 0x89, 0xbf, 0x97, 0x15, 0xff, 0xf5, - 0x56, 0x4d, 0x4c, 0x93, 0x0a, 0x8c, 0x17, 0xc6, 0x02, 0x63, 0x05, 0xab, - 0xaf, 0x09, 0xb4, 0x5a, 0x70, 0x99, 0xab, 0xf1, 0x73, 0x56, 0xcc, 0xf7, - 0x8b, 0x3c, 0xa9, 0x18, 0x29, 0xd6, 0x14, 0x2d, 0xf5, 0x85, 0x0e, 0x2d, - 0x30, 0xc7, 0x1f, 0x51, 0x7d, 0x70, 0x78, 0xb1, 0x55, 0xf2, 0xf6, 0x7a, - 0xc9, 0xab, 0x8c, 0x47, 0x55, 0x07, 0x58, 0xce, 0x3d, 0xe8, 0xe3, 0xbe, - 0x1f, 0x57, 0x5c, 0xc4, 0xeb, 0x85, 0x4e, 0xb4, 0x99, 0x6b, 0xde, 0x51, - 0xd7, 0x5f, 0x5d, 0x97, 0x4d, 0xd8, 0x96, 0x55, 0x5f, 0x93, 0x65, 0x5f, - 0x7d, 0x2d, 0xf6, 0xb4, 0x5c, 0x27, 0xdf, 0x94, 0xfc, 0x9c, 0xbb, 0xeb, - 0xe5, 0xdc, 0x1f, 0xc3, 0x9c, 0x9c, 0x5b, 0x32, 0xa1, 0xa1, 0xa6, 0xbe, - 0x53, 0x53, 0xc1, 0x5b, 0x2b, 0xf9, 0x53, 0xb4, 0x17, 0x2b, 0xb5, 0x72, - 0xdc, 0x7b, 0x06, 0xbe, 0x48, 0x1e, 0x7e, 0x45, 0xce, 0xfb, 0xfe, 0x80, - 0xf7, 0x2b, 0xcf, 0x7f, 0xc1, 0x9e, 0x9a, 0xb5, 0xce, 0x6e, 0xd5, 0xd4, - 0xd9, 0xbf, 0x8d, 0x67, 0x59, 0x63, 0xcf, 0x95, 0x1b, 0xc0, 0xbb, 0x0d, - 0xc4, 0x89, 0x54, 0xc6, 0x53, 0xc7, 0xab, 0x2e, 0xd7, 0xb9, 0x76, 0x79, - 0x73, 0x05, 0xa1, 0xe7, 0x0f, 0x4e, 0xf9, 0x63, 0x4e, 0x4a, 0x63, 0x7f, - 0x22, 0x16, 0xb4, 0x38, 0xc6, 0xe8, 0xfb, 0xb4, 0x7b, 0x12, 0x7a, 0x9c, - 0x3a, 0x9f, 0xef, 0xed, 0xc0, 0xd7, 0xa3, 0x2e, 0xa0, 0x3e, 0x57, 0x1b, - 0x10, 0xcf, 0x43, 0xd7, 0x8f, 0x94, 0x34, 0x97, 0x1f, 0xfb, 0x6a, 0x30, - 0x31, 0x93, 0x55, 0xdd, 0x00, 0x7f, 0xaf, 0xf4, 0x26, 0xf3, 0x41, 0x67, - 0x24, 0x50, 0x5d, 0xa7, 0x61, 0x6c, 0xc6, 0x9a, 0x46, 0x0b, 0x74, 0x83, - 0xc8, 0x55, 0xf0, 0xc6, 0x6b, 0x0b, 0xe4, 0xd7, 0x60, 0xbb, 0x89, 0xaf, - 0x96, 0x76, 0x58, 0xd2, 0xae, 0xb5, 0xcf, 0xbc, 0x13, 0xa1, 0x7f, 0x32, - 0x9c, 0xec, 0x87, 0x9f, 0xad, 0xd8, 0x03, 0xe6, 0x2b, 0x0f, 0x22, 0x1e, - 0xab, 0xce, 0xb1, 0x40, 0xbe, 0xc6, 0xd9, 0x9f, 0x85, 0x5f, 0xb9, 0x52, - 0xf7, 0xc8, 0x17, 0x27, 0x35, 0xb7, 0x39, 0xb7, 0xd0, 0xa2, 0x3a, 0x76, - 0xae, 0x38, 0x86, 0x73, 0x91, 0xad, 0xd6, 0x50, 0xde, 0xeb, 0x0f, 0x4b, - 0xb1, 0xc8, 0xb6, 0x74, 0x35, 0xe8, 0xb9, 0xfb, 0xb5, 0x1d, 0x5b, 0xe6, - 0xe1, 0x2b, 0x16, 0x17, 0x1d, 0xfc, 0xf7, 0xe0, 0xbf, 0x0f, 0xff, 0xbb, - 0x25, 0x3d, 0x4d, 0xff, 0x95, 0xb5, 0x9c, 0x96, 0xba, 0xf5, 0xe9, 0x23, - 0x75, 0x29, 0x0e, 0x2c, 0xef, 0xc5, 0x39, 0xf9, 0x62, 0xbd, 0x9c, 0x30, - 0x4f, 0xea, 0xeb, 0x08, 0xe6, 0x4b, 0xfd, 0x5a, 0x5f, 0x75, 0x0d, 0xcb, - 0xf2, 0xea, 0x5e, 0xe4, 0xe9, 0x66, 0x39, 0x5c, 0xf4, 0x6b, 0x57, 0x31, - 0x39, 0x52, 0xa9, 0x5d, 0x49, 0x26, 0x38, 0xf4, 0xc9, 0x23, 0xd9, 0x29, - 0xc5, 0x13, 0x58, 0xd6, 0xd0, 0xf5, 0x47, 0x26, 0x16, 0xdf, 0x7e, 0x64, - 0x05, 0x13, 0x8e, 0x7b, 0x8b, 0xab, 0x61, 0x86, 0x88, 0xa5, 0xe3, 0xb7, - 0x72, 0xea, 0xbb, 0x61, 0xdf, 0x7e, 0xcc, 0x43, 0x9c, 0x1d, 0xf4, 0x4c, - 0xf3, 0x0a, 0x76, 0xd7, 0xc4, 0xa3, 0xc4, 0x91, 0xf2, 0xb9, 0x6a, 0xec, - 0x47, 0x08, 0xe7, 0x2f, 0x01, 0xcb, 0xc9, 0x61, 0x1f, 0x3f, 0xed, 0x34, - 0x7e, 0x20, 0x71, 0xa6, 0x89, 0x2a, 0xec, 0x91, 0x8f, 0x35, 0x7d, 0x09, - 0x73, 0x65, 0xe4, 0x77, 0xa5, 0x47, 0xe5, 0x57, 0xa5, 0x31, 0xc8, 0xf7, - 0x04, 0xe6, 0x3c, 0x20, 0x6f, 0x96, 0xf6, 0xc9, 0xb5, 0xd2, 0xb8, 0xbc, - 0x51, 0xda, 0x8d, 0x98, 0x6a, 0x94, 0x58, 0x4f, 0x0f, 0x2b, 0x3d, 0x2c, - 0x07, 0xcf, 0x2b, 0x06, 0xf0, 0x16, 0xfd, 0x9e, 0xe3, 0xea, 0x67, 0x13, - 0x5f, 0x9f, 0xf8, 0x35, 0xe3, 0x79, 0x62, 0x33, 0x8b, 0x25, 0x1f, 0xc3, - 0x71, 0xb4, 0x0b, 0x6b, 0xdb, 0xfc, 0x36, 0x65, 0xe4, 0x7c, 0x24, 0x30, - 0x7a, 0x3e, 0x14, 0x78, 0x50, 0xbf, 0x73, 0x61, 0xbd, 0xb3, 0x2c, 0x93, - 0xae, 0x43, 0xde, 0x1c, 0x1c, 0x81, 0x2c, 0x8c, 0x42, 0xd5, 0x3f, 0xe4, - 0xac, 0x17, 0x90, 0x34, 0xf5, 0x11, 0xfc, 0xcc, 0xe4, 0x8b, 0xae, 0x64, - 0x0b, 0xf3, 0x01, 0x83, 0x47, 0xb3, 0xd1, 0xee, 0x43, 0xfb, 0xe7, 0x5e, - 0x7b, 0xa7, 0x64, 0x67, 0x25, 0xf5, 0xbe, 0xfa, 0xc3, 0x2f, 0x7b, 0x7d, - 0x83, 0xe8, 0x03, 0x67, 0x5e, 0x64, 0xdf, 0x45, 0xaf, 0x8f, 0x67, 0xc2, - 0x5a, 0x7d, 0x5c, 0xf9, 0x2a, 0x6b, 0x8f, 0x8b, 0x7e, 0xd7, 0xa0, 0xb5, - 0xf8, 0x0f, 0x3a, 0x8d, 0x6e, 0x23, 0x26, 0xf0, 0x9f, 0x9d, 0x8c, 0xc1, - 0x8a, 0x90, 0xaf, 0xbb, 0xa0, 0x13, 0xff, 0xba, 0x75, 0xa5, 0x6d, 0x0d, - 0x7d, 0x5c, 0x85, 0xd1, 0xfe, 0x58, 0xba, 0x17, 0xff, 0xed, 0xe1, 0x79, - 0x9f, 0xc0, 0xbb, 0xe1, 0xac, 0x0a, 0xc4, 0x8d, 0xc7, 0x21, 0xdb, 0x2d, - 0xb2, 0xfe, 0x2c, 0xe9, 0xd5, 0x0b, 0x5d, 0x9d, 0x82, 0xdc, 0xba, 0xb2, - 0x50, 0x0a, 0x05, 0x46, 0x0a, 0x29, 0x31, 0x78, 0x6a, 0x4b, 0x32, 0xd1, - 0x94, 0x9c, 0x1e, 0x48, 0xf4, 0x30, 0x0f, 0x99, 0xed, 0x77, 0xe5, 0x52, - 0x89, 0xf6, 0x38, 0x27, 0x97, 0x07, 0x12, 0x6e, 0x51, 0x88, 0x8b, 0x71, - 0xe5, 0x32, 0x64, 0xf3, 0x9d, 0xf3, 0xbb, 0xe5, 0x48, 0x41, 0xfd, 0xe0, - 0xde, 0xb0, 0xbc, 0x20, 0x97, 0x06, 0x5e, 0xb8, 0x75, 0xc9, 0x3d, 0x84, - 0x33, 0x25, 0x1f, 0x1e, 0xee, 0x32, 0xfb, 0x56, 0x1c, 0x92, 0x30, 0x1f, - 0xa2, 0x35, 0x35, 0xa7, 0x51, 0xd2, 0xfb, 0x23, 0x5e, 0x5c, 0x0e, 0x9f, - 0x3b, 0x30, 0x60, 0xea, 0x29, 0x01, 0x7f, 0x9f, 0x61, 0xf8, 0x31, 0x7c, - 0xce, 0xa7, 0x8d, 0x3f, 0x4f, 0x67, 0x20, 0x3d, 0xdb, 0x2a, 0xa1, 0x8b, - 0xf7, 0x81, 0xae, 0x21, 0x39, 0xd4, 0x5f, 0x2e, 0x7f, 0xd3, 0x0d, 0xc5, - 0x27, 0x10, 0xa3, 0x60, 0xff, 0xb2, 0xee, 0xc5, 0x36, 0xd0, 0xa4, 0x49, - 0xa2, 0x2f, 0xfa, 0xeb, 0x35, 0x7a, 0x58, 0x86, 0x8b, 0xeb, 0x8c, 0x2d, - 0xf3, 0xb1, 0x0d, 0xfe, 0x7c, 0x06, 0x53, 0xd6, 0x6d, 0xf5, 0x07, 0xbc, - 0xef, 0x24, 0xbc, 0xf6, 0x3d, 0x81, 0x07, 0x42, 0xed, 0x12, 0x72, 0x9e, - 0xdf, 0x48, 0x6c, 0xe4, 0x52, 0xc1, 0xef, 0x87, 0x9f, 0x18, 0xf2, 0xfd, - 0x61, 0xd9, 0xbe, 0x72, 0xd6, 0xb2, 0xbd, 0x7b, 0xf1, 0x5b, 0xde, 0x9c, - 0x29, 0x6f, 0x2c, 0x62, 0x8e, 0xd8, 0x5a, 0xb5, 0x4f, 0x66, 0xec, 0xa7, - 0xf2, 0x74, 0x7f, 0xe2, 0x15, 0xc5, 0xc9, 0x56, 0x9e, 0xe1, 0x7d, 0xc4, - 0x90, 0x25, 0x7d, 0x26, 0xb6, 0x07, 0xf4, 0xcd, 0xc4, 0xee, 0xb6, 0xe7, - 0xad, 0x60, 0xc0, 0xf8, 0x23, 0x0d, 0xf2, 0xbd, 0x28, 0xec, 0x36, 0xbf, - 0x61, 0x61, 0xfe, 0xcb, 0xbd, 0xed, 0xf9, 0x29, 0xec, 0x4b, 0x9c, 0x49, - 0x5a, 0x13, 0xd8, 0x1f, 0xcf, 0x80, 0x18, 0x50, 0x0b, 0x74, 0xea, 0xc4, - 0xfb, 0x21, 0x7e, 0xea, 0xf7, 0xdf, 0x7f, 0x1d, 0x74, 0x18, 0xf7, 0x6f, - 0x70, 0x61, 0x62, 0x31, 0x17, 0x32, 0xec, 0x61, 0x60, 0xab, 0xe5, 0xd6, - 0xc7, 0xc6, 0xfa, 0x78, 0x3a, 0x62, 0x94, 0x62, 0xf0, 0x03, 0x29, 0x13, - 0xe4, 0xcd, 0x0e, 0xf4, 0xaf, 0xf9, 0x24, 0xa5, 0xaf, 0xee, 0xf7, 0x7d, - 0x58, 0xc1, 0x76, 0x4f, 0x14, 0xf6, 0x19, 0x6c, 0x9e, 0xb5, 0x2c, 0xa9, - 0xae, 0xa4, 0x3d, 0x89, 0xfd, 0xa6, 0x43, 0x89, 0x62, 0x4e, 0x62, 0x32, - 0x0f, 0x7d, 0xf1, 0x1a, 0x64, 0xff, 0x5a, 0x29, 0x1e, 0x48, 0x63, 0x4f, - 0x87, 0x0b, 0x43, 0x32, 0x31, 0xab, 0xdf, 0x7e, 0x41, 0xef, 0x0f, 0xc9, - 0x5c, 0x21, 0xd1, 0x33, 0x0f, 0xfe, 0x9b, 0x2f, 0x10, 0x5f, 0xd4, 0x1b, - 0x1f, 0xc5, 0x8c, 0x4b, 0x85, 0xcd, 0xb0, 0x0f, 0x92, 0xba, 0x04, 0xff, - 0xe7, 0x52, 0xa9, 0x07, 0x7c, 0x86, 0xfb, 0x25, 0x07, 0xbf, 0xd0, 0x99, - 0xa5, 0x01, 0xc8, 0x39, 0xf7, 0x62, 0xcb, 0xc2, 0x56, 0x9c, 0x1d, 0x71, - 0x44, 0x8a, 0x1f, 0xff, 0x2f, 0xce, 0xd7, 0x7f, 0xef, 0x1d, 0x6a, 0xa7, - 0xe7, 0x75, 0x5f, 0xb0, 0xcb, 0x88, 0x01, 0xb2, 0xfd, 0xc6, 0x6e, 0xa7, - 0x23, 0x6d, 0x92, 0xbe, 0x9b, 0x76, 0xbc, 0x5d, 0x63, 0x44, 0xe5, 0xc5, - 0x08, 0xef, 0xbf, 0xb3, 0xd1, 0xd0, 0x2f, 0x5c, 0xd7, 0xbe, 0x8e, 0xdf, - 0x56, 0xe9, 0x70, 0xf8, 0x6b, 0xe3, 0xf7, 0xed, 0x8d, 0xac, 0xef, 0x76, - 0x38, 0x49, 0xac, 0xf5, 0x5b, 0x2f, 0x5f, 0x80, 0xeb, 0x79, 0x3e, 0xb3, - 0xc1, 0x5b, 0x97, 0xf3, 0xb6, 0x62, 0x9e, 0x16, 0x6f, 0xad, 0x56, 0xcd, - 0x4f, 0x9a, 0xb5, 0x10, 0xe3, 0x16, 0xfe, 0xb2, 0x51, 0xbf, 0x35, 0x86, - 0xbd, 0xa8, 0x6d, 0xff, 0x79, 0x23, 0x71, 0x73, 0x1d, 0x4e, 0xab, 0x62, - 0x3c, 0x6f, 0xb6, 0xb7, 0xe3, 0x9a, 0x6b, 0x72, 0x8c, 0xc9, 0x87, 0xcf, - 0x95, 0x38, 0x3f, 0xdb, 0x29, 0x39, 0xa1, 0xf9, 0x0c, 0x83, 0xe5, 0x9b, - 0x2b, 0xdc, 0x2f, 0x13, 0xe7, 0x15, 0x5f, 0x37, 0x93, 0xb7, 0xf8, 0xdd, - 0x0b, 0xbf, 0x97, 0xa3, 0x2f, 0x31, 0x26, 0x07, 0x71, 0x7e, 0x97, 0xe1, - 0x53, 0x2d, 0x99, 0xef, 0x62, 0xf1, 0x77, 0x00, 0xe7, 0x12, 0x82, 0x8c, - 0x51, 0x46, 0x29, 0x53, 0x38, 0xbf, 0x71, 0x5b, 0xde, 0x1d, 0xa0, 0x3c, - 0x0f, 0xc8, 0x95, 0x8a, 0x3c, 0xe7, 0x20, 0xcf, 0x94, 0xe5, 0x1c, 0x64, - 0xda, 0xf0, 0xf5, 0x7e, 0x7e, 0x67, 0x1d, 0x83, 0xbd, 0x52, 0x1f, 0xe2, - 0x25, 0xf0, 0xb5, 0xed, 0x7d, 0x2b, 0x15, 0xd0, 0x1c, 0x4e, 0x76, 0xb6, - 0xc1, 0xfb, 0x0e, 0x00, 0xd7, 0x57, 0x9e, 0x93, 0xf4, 0x6c, 0x33, 0xbf, - 0xe7, 0xea, 0xe2, 0x99, 0x65, 0xaf, 0xf0, 0xdf, 0xe7, 0x45, 0xe2, 0x4d, - 0xe9, 0xcf, 0xf2, 0x9a, 0x71, 0xde, 0x26, 0x8c, 0x19, 0x04, 0x9d, 0x9b, - 0x31, 0x3f, 0xf7, 0xb8, 0xda, 0x38, 0xde, 0x0f, 0x55, 0xe1, 0x53, 0x7d, - 0x7a, 0xaf, 0xd5, 0x35, 0xb3, 0xfd, 0xcd, 0xde, 0xfb, 0xf1, 0x1c, 0x94, - 0xef, 0xc1, 0xb7, 0xf4, 0x89, 0xc9, 0x2f, 0x29, 0x3d, 0x87, 0xb9, 0x02, - 0xf9, 0x37, 0xa4, 0x39, 0x8c, 0x2c, 0x6c, 0xcb, 0x5e, 0x1d, 0x1f, 0x5b, - 0x91, 0xef, 0xae, 0x80, 0xc6, 0xdd, 0xd9, 0xc2, 0x1a, 0xe9, 0x56, 0x1d, - 0xd4, 0xe5, 0xf1, 0x36, 0xec, 0x85, 0x62, 0xb9, 0x0f, 0xc8, 0xf1, 0xd2, - 0x20, 0xe8, 0x10, 0x93, 0xa7, 0xe0, 0x37, 0x3f, 0x53, 0xba, 0x43, 0x96, - 0x23, 0xd8, 0x57, 0x45, 0xc6, 0x86, 0xe5, 0xfb, 0xf3, 0x09, 0xef, 0x3a, - 0xe1, 0x2e, 0x5b, 0x3b, 0xb0, 0x07, 0xca, 0x13, 0xe5, 0x8a, 0xe3, 0x82, - 0x88, 0x45, 0x38, 0xef, 0xd3, 0x46, 0xb7, 0x61, 0xde, 0x62, 0x84, 0xf2, - 0xcb, 0xbd, 0x85, 0x3c, 0x99, 0x65, 0x5c, 0xc5, 0x77, 0x36, 0x36, 0x29, - 0x53, 0x73, 0x16, 0x09, 0xc5, 0x81, 0xae, 0x9c, 0x81, 0x3f, 0x8f, 0x2f, - 0x97, 0xfe, 0x77, 0x14, 0xd4, 0xa3, 0xb0, 0x95, 0x05, 0xd8, 0xca, 0x02, - 0x6c, 0x24, 0x64, 0xe1, 0x5a, 0x01, 0x36, 0xb2, 0x00, 0x1b, 0x09, 0x7d, - 0xf6, 0x3a, 0x62, 0xbb, 0xd7, 0xc0, 0x43, 0xc6, 0xd7, 0x3e, 0x4a, 0x5f, - 0x1b, 0x7f, 0xff, 0x03, 0x4c, 0x03, 0x3a, 0xe1, 0xd4, 0x71, 0x00, 0x00, - 0x00 }; + 0xec, 0x5b, 0x5f, 0x6c, 0x5b, 0xd7, 0x79, 0xff, 0xee, 0x21, 0x25, 0x51, + 0xb2, 0xfe, 0x5c, 0xc9, 0x8c, 0x43, 0x27, 0x4a, 0x43, 0x4a, 0x57, 0x12, + 0x13, 0x69, 0xe9, 0x95, 0xc6, 0x26, 0x2a, 0x46, 0x34, 0x2c, 0x29, 0xdb, + 0x4a, 0xe3, 0x07, 0xc5, 0xf5, 0xda, 0xac, 0xeb, 0x30, 0x81, 0xb2, 0xb1, + 0xec, 0x61, 0x83, 0x67, 0xac, 0x41, 0xb6, 0xb9, 0x30, 0x41, 0x29, 0x8e, + 0x92, 0xd2, 0x22, 0x67, 0x2b, 0x73, 0xb1, 0x65, 0x80, 0x42, 0x49, 0x76, + 0xb6, 0xd1, 0x62, 0xda, 0xbd, 0x74, 0x45, 0x1c, 0x0b, 0x8a, 0xe7, 0xe5, + 0xa1, 0x0f, 0x69, 0x17, 0x60, 0xed, 0xd0, 0x61, 0x86, 0xe2, 0xda, 0x79, + 0x28, 0xb6, 0x6c, 0x40, 0x96, 0x6c, 0x71, 0x73, 0xf7, 0xfb, 0x9d, 0x7b, + 0xaf, 0x4c, 0x2b, 0x1a, 0x9a, 0x87, 0x3d, 0xde, 0x03, 0x08, 0xe7, 0x9e, + 0x73, 0xbe, 0xf3, 0x9d, 0xef, 0xfb, 0xce, 0xf7, 0xf7, 0xd0, 0xfe, 0xc3, + 0x76, 0x69, 0x13, 0xaf, 0x75, 0xe0, 0x2f, 0x75, 0xec, 0x99, 0xe3, 0x63, + 0x0f, 0xa5, 0x1e, 0xe2, 0x38, 0xa4, 0xc2, 0x61, 0xf6, 0x86, 0x04, 0x2d, + 0x68, 0x41, 0x0b, 0x5a, 0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68, + 0x41, 0x0b, 0x5a, 0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68, 0x41, + 0x0b, 0x5a, 0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68, 0x41, 0x0b, + 0x5a, 0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68, 0x41, 0x0b, 0x5a, + 0xd0, 0x82, 0x16, 0xb4, 0xa0, 0x05, 0x2d, 0x68, 0x41, 0x0b, 0x5a, 0xd0, + 0x82, 0x16, 0xb4, 0xa0, 0x05, 0xed, 0xff, 0xb3, 0x85, 0x44, 0x4c, 0xf6, + 0x1d, 0xde, 0x9f, 0x44, 0x54, 0x3a, 0x7e, 0x3c, 0x6b, 0x49, 0x24, 0x94, + 0xbe, 0xf2, 0xf4, 0x8c, 0x25, 0x92, 0xa9, 0x0d, 0xc7, 0x73, 0xf2, 0x0b, + 0xa7, 0x10, 0x0d, 0x0b, 0xe7, 0xef, 0x4b, 0xdf, 0x3a, 0x79, 0xe9, 0x91, + 0xc4, 0x7b, 0x4b, 0x21, 0x89, 0x98, 0xe9, 0xb7, 0x46, 0xcd, 0x41, 0x89, + 0xf4, 0x62, 0xcf, 0x4b, 0x43, 0x97, 0xbb, 0xa4, 0xd3, 0xc7, 0x25, 0x52, + 0x2d, 0x25, 0xec, 0xfd, 0x32, 0x6c, 0x6e, 0x48, 0x58, 0x32, 0x38, 0xe3, + 0x7c, 0x4d, 0xa4, 0x58, 0x32, 0x88, 0x43, 0x8a, 0xb5, 0x88, 0x5c, 0x0b, + 0x11, 0xea, 0x7b, 0x46, 0xb6, 0xfc, 0xb1, 0x93, 0x09, 0xe3, 0x5c, 0x0b, + 0xdf, 0x75, 0x7f, 0x3e, 0x22, 0x2a, 0x9d, 0x48, 0x66, 0x43, 0x93, 0x52, + 0x5d, 0x74, 0x9c, 0x39, 0xfb, 0x5e, 0xe0, 0xe8, 0x91, 0x39, 0xcb, 0x1d, + 0x67, 0xed, 0x07, 0xcd, 0x09, 0xb9, 0x1b, 0x73, 0x21, 0x51, 0xd6, 0x3d, + 0xf8, 0x8b, 0x1b, 0xb9, 0xb3, 0xdf, 0x32, 0xb2, 0xcb, 0xed, 0x52, 0x2c, + 0x3b, 0x32, 0x63, 0x4b, 0x26, 0x6b, 0xb7, 0x62, 0xfd, 0x63, 0x67, 0x66, + 0x6b, 0xcf, 0xb0, 0x99, 0x93, 0x26, 0xc9, 0x44, 0x63, 0x80, 0x59, 0x34, + 0x72, 0x17, 0xfe, 0xae, 0x5d, 0xda, 0x40, 0x4f, 0x8a, 0xe3, 0x8f, 0x9d, + 0x90, 0x65, 0x61, 0x9d, 0xe7, 0x63, 0x5c, 0x27, 0x5e, 0x7e, 0x13, 0xe7, + 0x35, 0xe7, 0xd2, 0x50, 0x4c, 0xbe, 0x5b, 0x8f, 0xca, 0x77, 0xea, 0xa6, + 0xbc, 0x5a, 0xef, 0x95, 0xcb, 0x75, 0xc7, 0xf9, 0x8e, 0xed, 0x38, 0x6f, + 0xe1, 0xef, 0x3f, 0xed, 0x2d, 0x1e, 0xd0, 0x0a, 0xc6, 0x44, 0xfd, 0x2f, + 0xda, 0xa5, 0x33, 0x11, 0x17, 0xd5, 0x2e, 0xb3, 0xe5, 0x98, 0xcc, 0x95, + 0x4b, 0xc6, 0x13, 0x17, 0x16, 0x8c, 0xa9, 0x0b, 0x15, 0x9c, 0x19, 0xc6, + 0x9c, 0x14, 0x8a, 0xf6, 0x2b, 0x46, 0xae, 0x3e, 0x6f, 0x1c, 0xba, 0xd0, + 0x09, 0x1a, 0x79, 0xfe, 0x1e, 0x23, 0x7b, 0xf6, 0x96, 0x64, 0x6d, 0xca, + 0x38, 0x61, 0x7e, 0x0d, 0x62, 0xcf, 0x96, 0x48, 0x73, 0xb3, 0x47, 0xaf, + 0xe3, 0xa8, 0xb4, 0x73, 0x32, 0x9b, 0xb2, 0xcc, 0xa2, 0x90, 0x3e, 0x3d, + 0x77, 0xd9, 0xa5, 0xf9, 0xbc, 0x91, 0xbd, 0xd0, 0x6e, 0xe4, 0xce, 0x85, + 0x41, 0x87, 0xf4, 0x86, 0x84, 0xfb, 0x06, 0x62, 0x79, 0xa9, 0xe1, 0x0c, + 0x31, 0x55, 0x9a, 0x72, 0x05, 0xcd, 0xa0, 0xe5, 0xbb, 0x65, 0xf0, 0x50, + 0x06, 0x0f, 0x65, 0xf2, 0x16, 0x97, 0x4b, 0x43, 0x3e, 0x6f, 0x8e, 0xf3, + 0x23, 0x9b, 0xb4, 0x27, 0xe2, 0x19, 0xe5, 0xf3, 0xe9, 0x38, 0xff, 0x61, + 0x93, 0x57, 0xf2, 0xe3, 0x38, 0xaf, 0xda, 0x31, 0xd0, 0xee, 0x5c, 0x56, + 0x56, 0x09, 0xbc, 0x58, 0xc0, 0x4f, 0x59, 0x2f, 0x80, 0x87, 0x79, 0xf0, + 0x77, 0x1e, 0xbc, 0x55, 0x40, 0xc7, 0x2f, 0x3b, 0xaf, 0x60, 0xe4, 0x86, + 0xb6, 0xe4, 0x15, 0xa7, 0x8c, 0xf3, 0x2b, 0x0a, 0xb2, 0xde, 0x25, 0xf9, + 0x25, 0x53, 0xa6, 0x57, 0xfc, 0xfd, 0xbe, 0x1e, 0x1c, 0x93, 0x83, 0xe5, + 0x1e, 0xc8, 0x86, 0xb2, 0x4c, 0xd8, 0x22, 0x0e, 0x64, 0x54, 0x4c, 0x2a, + 0x11, 0x23, 0x6f, 0x9f, 0xd4, 0xf7, 0xbf, 0x62, 0x49, 0x26, 0x6f, 0x53, + 0x8e, 0x12, 0xcf, 0xdb, 0x85, 0x58, 0x18, 0xfa, 0xb6, 0x62, 0x15, 0xcc, + 0xb0, 0x50, 0x8e, 0x89, 0xd8, 0x1f, 0x43, 0x96, 0x47, 0x4b, 0x92, 0xf9, + 0x52, 0xc9, 0x97, 0xb1, 0x2b, 0xdf, 0xc7, 0x4b, 0x5f, 0xec, 0x90, 0x36, + 0xf5, 0x99, 0x26, 0xf9, 0x3d, 0xec, 0x25, 0xee, 0x3b, 0xf6, 0x62, 0x9f, + 0x0b, 0xe7, 0xee, 0x4d, 0x3c, 0x29, 0x42, 0xd8, 0x62, 0x7f, 0x93, 0xb6, + 0x11, 0x31, 0xb2, 0x56, 0x21, 0x16, 0x02, 0x5c, 0x5e, 0x8a, 0xa3, 0xde, + 0x5c, 0x53, 0xd6, 0xba, 0x15, 0x9a, 0xb3, 0x13, 0xf1, 0xa2, 0xdc, 0x0a, + 0x5d, 0xb5, 0xf5, 0x5c, 0x6b, 0xd6, 0x72, 0x64, 0x15, 0xd8, 0x9f, 0x83, + 0x3d, 0x6c, 0x80, 0xa3, 0xdf, 0x2d, 0xe9, 0xf9, 0x0e, 0xec, 0x4f, 0x36, + 0x01, 0x67, 0x9b, 0x24, 0x92, 0x55, 0xcc, 0x5f, 0x75, 0xe7, 0xbb, 0x5d, + 0xbc, 0xc5, 0xfe, 0x36, 0x8d, 0x5b, 0xe4, 0x15, 0x77, 0xfe, 0x2e, 0x17, + 0x77, 0xf1, 0x01, 0xcc, 0x03, 0xff, 0xe0, 0xe4, 0x90, 0xa1, 0xe7, 0xf7, + 0xd2, 0x9e, 0x7e, 0xa7, 0x74, 0x2b, 0xb4, 0x6a, 0x3b, 0x92, 0x1b, 0x1d, + 0x9c, 0x1c, 0x34, 0x5c, 0x7c, 0xa7, 0xdc, 0x7d, 0xf7, 0xb9, 0xf8, 0x06, + 0x27, 0x93, 0x86, 0x8b, 0x6f, 0xa5, 0xa4, 0xf7, 0x4a, 0xbe, 0x44, 0xd8, + 0xc1, 0x49, 0xcb, 0xb8, 0x4f, 0xa6, 0xbb, 0x07, 0x27, 0xfb, 0x0c, 0xf5, + 0x99, 0x5d, 0x2e, 0x1f, 0x09, 0x9f, 0x86, 0x5d, 0x9a, 0x06, 0x9e, 0xab, + 0xe7, 0x07, 0xb2, 0x56, 0xf1, 0x81, 0x5d, 0xfa, 0x7c, 0x9e, 0xa9, 0xe7, + 0x1e, 0x20, 0x5d, 0x3c, 0x7b, 0x66, 0xf4, 0x8e, 0x73, 0x7f, 0xe5, 0xb6, + 0x7c, 0x76, 0x3a, 0x93, 0xe7, 0x49, 0x24, 0x9c, 0x0e, 0x8f, 0xce, 0x95, + 0x8e, 0x49, 0xb6, 0x1c, 0x97, 0xd9, 0x91, 0x56, 0x99, 0x36, 0xfb, 0xa7, + 0x0f, 0x0a, 0x7d, 0x4f, 0x64, 0x74, 0xc6, 0xbb, 0xc3, 0x9c, 0x18, 0x32, + 0x0b, 0x1e, 0x0f, 0xd6, 0x24, 0x62, 0x00, 0xbe, 0xbf, 0x16, 0x96, 0xe7, + 0xeb, 0x86, 0x34, 0x6b, 0xfb, 0x4c, 0x98, 0xeb, 0xd0, 0xc3, 0x67, 0xcb, + 0xd4, 0x63, 0xea, 0xac, 0x64, 0xaa, 0x5a, 0x67, 0x7d, 0x7b, 0x6d, 0xe3, + 0xdd, 0x16, 0x0a, 0x02, 0x73, 0x4c, 0x5b, 0x66, 0x55, 0x5a, 0x24, 0x33, + 0x25, 0x85, 0xaa, 0xbd, 0x65, 0x3f, 0xb1, 0x65, 0xd9, 0x80, 0x1e, 0x88, + 0x99, 0x4d, 0x71, 0x9e, 0xf0, 0x0d, 0xb0, 0xa6, 0x6b, 0x7b, 0x21, 0xd8, + 0xde, 0x4c, 0x8a, 0xb0, 0x52, 0xd0, 0xfe, 0xa2, 0x0e, 0x7d, 0xac, 0xdf, + 0xd7, 0xe1, 0xfa, 0xbb, 0x08, 0x6c, 0xb4, 0x1d, 0x76, 0xfe, 0x19, 0xd8, + 0x60, 0xaf, 0x91, 0x3d, 0xe7, 0x38, 0xf0, 0x3f, 0x51, 0x25, 0xb4, 0x41, + 0xd8, 0x7b, 0x9d, 0x6b, 0xed, 0x98, 0x17, 0x73, 0xd6, 0xee, 0x06, 0x8f, + 0x8e, 0x33, 0x69, 0xc7, 0xa5, 0x68, 0x77, 0x61, 0x5f, 0x93, 0xf4, 0x58, + 0xd4, 0x79, 0xda, 0xf5, 0x2e, 0x9c, 0x67, 0x70, 0xdc, 0x89, 0xf3, 0x3a, + 0x30, 0x17, 0x9b, 0xa5, 0x2d, 0xa7, 0xe8, 0xb7, 0x5c, 0x1f, 0x2a, 0x72, + 0x1d, 0xb4, 0x72, 0x8f, 0x86, 0x8b, 0xb4, 0xa4, 0x53, 0x72, 0xb3, 0xb4, + 0x57, 0xae, 0x45, 0x29, 0x03, 0xe0, 0x2c, 0xc3, 0x27, 0x46, 0x0d, 0xd0, + 0x4f, 0xba, 0xe9, 0x03, 0x77, 0x7b, 0x63, 0xe3, 0x7e, 0xf7, 0x0c, 0x31, + 0x43, 0xe9, 0x4e, 0xc9, 0xe9, 0x39, 0x51, 0x6a, 0x74, 0x97, 0xb7, 0xde, + 0x69, 0xec, 0x3f, 0xa7, 0xe4, 0xc0, 0xc3, 0xf0, 0x5b, 0x38, 0xeb, 0xaa, + 0xe5, 0x38, 0x57, 0xed, 0xf7, 0x61, 0xf7, 0x4a, 0x9a, 0xac, 0x6b, 0x9d, + 0xd2, 0x46, 0x7b, 0x36, 0x1a, 0x64, 0x18, 0x93, 0x53, 0x65, 0xee, 0x29, + 0x48, 0xd8, 0x22, 0x0c, 0xe1, 0xff, 0x05, 0x70, 0x21, 0x69, 0x81, 0x3d, + 0x6e, 0xd8, 0x51, 0xd2, 0xdb, 0xe5, 0xc2, 0x77, 0xe3, 0x0c, 0xd2, 0x4e, + 0xfb, 0x73, 0xb4, 0xfd, 0x65, 0x43, 0x2a, 0x33, 0xb1, 0x08, 0x6b, 0x1a, + 0xa1, 0xbc, 0xb3, 0xdd, 0x70, 0xff, 0x32, 0x3b, 0x54, 0x30, 0x95, 0xbe, + 0x6f, 0x91, 0x5c, 0xe9, 0x7e, 0x99, 0xb3, 0x71, 0x9e, 0x15, 0x06, 0xcd, + 0xf4, 0x35, 0x03, 0x85, 0x90, 0x82, 0x95, 0xf5, 0x50, 0x56, 0x3e, 0xad, + 0xff, 0x8c, 0xf3, 0x0a, 0x46, 0xd8, 0xe2, 0x19, 0xbf, 0xe5, 0xc9, 0x87, + 0xba, 0x67, 0x4b, 0xb6, 0xd4, 0xce, 0x31, 0xe8, 0x68, 0xd3, 0x74, 0x84, + 0xd2, 0xfa, 0xee, 0x0c, 0x95, 0xf6, 0x63, 0x00, 0x41, 0xef, 0xc0, 0x03, + 0x3e, 0xb8, 0xd7, 0xc2, 0xde, 0x08, 0x68, 0xec, 0x68, 0xa0, 0xbf, 0x8d, + 0xf0, 0x90, 0x55, 0xc4, 0x3b, 0x43, 0xf3, 0x6d, 0xb8, 0x7c, 0xfb, 0xb2, + 0x7a, 0x1d, 0xb2, 0xfa, 0xc8, 0x39, 0x30, 0x46, 0x1c, 0x29, 0xe0, 0x80, + 0xdc, 0x4d, 0xfa, 0x2c, 0xfa, 0x29, 0x73, 0x0b, 0x17, 0x6c, 0x41, 0x85, + 0xd2, 0xed, 0x92, 0x33, 0x75, 0x1c, 0x00, 0xec, 0xb8, 0x68, 0x3f, 0x6f, + 0x91, 0x47, 0x6f, 0x6c, 0x25, 0xb4, 0xde, 0xe4, 0x2b, 0x8c, 0x05, 0x45, + 0xd0, 0xb6, 0x9e, 0x50, 0x9a, 0xb5, 0x76, 0xc8, 0x5c, 0x22, 0x4d, 0xe9, + 0xb7, 0x64, 0xb5, 0xa4, 0xf6, 0x34, 0x4b, 0x97, 0x4c, 0x41, 0x46, 0xd5, + 0x71, 0xc4, 0xb0, 0x91, 0x76, 0x09, 0x3d, 0xc4, 0x58, 0x10, 0x03, 0xad, + 0xeb, 0x09, 0x53, 0x6e, 0x39, 0x6a, 0x10, 0xfb, 0x47, 0x70, 0x0f, 0x87, + 0x79, 0xa7, 0xca, 0x83, 0x23, 0x4c, 0x88, 0x32, 0xef, 0x69, 0x16, 0xe2, + 0xe6, 0xda, 0x70, 0xcc, 0x14, 0xce, 0x23, 0x5e, 0x4e, 0x71, 0x2f, 0xf9, + 0x73, 0xf7, 0x7c, 0x92, 0x3f, 0x7f, 0x9d, 0x32, 0xa3, 0xec, 0xa0, 0x63, + 0xa0, 0xa9, 0x1b, 0x72, 0x1b, 0x5d, 0x80, 0x4f, 0xb4, 0x1f, 0xd7, 0x3a, + 0xdc, 0x37, 0x76, 0xaf, 0x5c, 0x83, 0xdd, 0xc5, 0x95, 0x18, 0x55, 0x7b, + 0xaf, 0x9e, 0x53, 0x96, 0x2f, 0x4f, 0xca, 0x60, 0xf7, 0x36, 0x19, 0x10, + 0xe7, 0xce, 0x72, 0x38, 0x52, 0x21, 0x0d, 0x2e, 0x2d, 0x73, 0xd6, 0x7a, + 0x22, 0x2c, 0x8d, 0xf4, 0x7c, 0xec, 0x28, 0xcb, 0x2a, 0xf4, 0x29, 0xe2, + 0x6f, 0x16, 0xb5, 0x27, 0x2c, 0x4f, 0x8c, 0x19, 0x12, 0x3f, 0xa4, 0xe4, + 0xd0, 0xc3, 0xc4, 0xf9, 0x13, 0xf2, 0x38, 0x9e, 0xe1, 0xfa, 0x18, 0x75, + 0x21, 0x8c, 0x5e, 0xf3, 0x87, 0xb9, 0x46, 0x5d, 0x7f, 0xdd, 0xd3, 0xf5, + 0x8f, 0x9c, 0x43, 0x63, 0x61, 0x0f, 0x36, 0xd2, 0x00, 0x2b, 0xb8, 0xef, + 0x9d, 0x60, 0x09, 0xd3, 0xa8, 0x17, 0x84, 0x2d, 0xec, 0x00, 0x8b, 0xe0, + 0xf4, 0x15, 0xda, 0x50, 0xb7, 0xe7, 0x33, 0x7c, 0x9b, 0xe2, 0x39, 0xec, + 0x77, 0xb2, 0x3f, 0xee, 0xe3, 0x7e, 0xc2, 0x6f, 0x8f, 0xa7, 0xb8, 0x06, + 0xd9, 0x31, 0xa6, 0xa2, 0x4d, 0xe2, 0x5b, 0xc1, 0xff, 0x34, 0xc6, 0x56, + 0xce, 0x99, 0x18, 0x4f, 0xa0, 0xb7, 0x24, 0x5f, 0xa3, 0x1d, 0x71, 0x3f, + 0x63, 0xed, 0xbb, 0x9e, 0xef, 0x6c, 0x9f, 0x0e, 0xa7, 0xa3, 0xf0, 0x9d, + 0x32, 0x55, 0x2c, 0x9d, 0x44, 0x3e, 0x24, 0x85, 0x7b, 0xd2, 0xd4, 0x8b, + 0xf6, 0x71, 0xf8, 0xc6, 0xa9, 0x62, 0x8d, 0x39, 0x11, 0xdc, 0x17, 0xf6, + 0x21, 0x3e, 0x47, 0xd4, 0x42, 0xa4, 0x70, 0x6f, 0x9a, 0x3e, 0x39, 0x2e, + 0xf1, 0xda, 0x7b, 0xc8, 0x39, 0x4c, 0xc9, 0x6a, 0x1d, 0xfb, 0xf6, 0x5e, + 0xd2, 0x5c, 0x44, 0xfe, 0x10, 0x4e, 0x4b, 0x58, 0xa5, 0x9b, 0x23, 0xb3, + 0xa9, 0x76, 0xe4, 0x59, 0x93, 0x7b, 0xd5, 0xda, 0xc1, 0xbd, 0xa1, 0xb5, + 0x3d, 0xd3, 0x4d, 0xe9, 0xc2, 0x5e, 0xb5, 0x20, 0xb2, 0x5c, 0x12, 0x85, + 0x9c, 0x26, 0x76, 0x44, 0x30, 0x5e, 0xfb, 0xf2, 0x97, 0x55, 0x3a, 0x24, + 0xf9, 0xa8, 0x9c, 0x58, 0x49, 0x85, 0x99, 0x3f, 0xc6, 0xa7, 0xe4, 0x04, + 0x72, 0xc6, 0x67, 0x64, 0xb6, 0x04, 0xba, 0x34, 0xdf, 0x31, 0xf0, 0xdb, + 0x0b, 0xdc, 0xa4, 0x3d, 0x0a, 0xdf, 0xea, 0xd2, 0x0e, 0x9a, 0x33, 0x39, + 0xe6, 0x48, 0x29, 0xc6, 0x94, 0xf7, 0xa0, 0x27, 0xb4, 0x93, 0x9f, 0xcb, + 0xaa, 0xd5, 0x2a, 0x79, 0xd7, 0x2f, 0x68, 0x3d, 0x0d, 0xa7, 0xdf, 0xf5, + 0xd6, 0xae, 0x63, 0x8d, 0xfa, 0xba, 0xab, 0xe1, 0xee, 0xbe, 0xa5, 0xf3, + 0x9c, 0xab, 0x36, 0xbf, 0x09, 0xfb, 0x83, 0x51, 0x17, 0xf6, 0xcd, 0xd1, + 0x55, 0xeb, 0x2b, 0x5d, 0xd2, 0x86, 0x73, 0xca, 0x3c, 0x27, 0x4a, 0xdf, + 0x8a, 0xf5, 0x6b, 0x1e, 0xae, 0x9f, 0x02, 0x57, 0x3b, 0xe9, 0x46, 0x0b, + 0x63, 0x1d, 0xf4, 0x21, 0xdf, 0xc9, 0x6f, 0xf9, 0x18, 0xc2, 0xbe, 0xe6, + 0xe1, 0xfa, 0x5e, 0x03, 0x2e, 0xae, 0xb1, 0xe7, 0x99, 0x38, 0xbb, 0x8d, + 0xbc, 0x91, 0x1f, 0xde, 0x01, 0xef, 0x23, 0x69, 0x4c, 0xc1, 0xa7, 0x4f, + 0xd5, 0x75, 0x5e, 0x67, 0xe4, 0xca, 0xc8, 0xb7, 0xea, 0x2f, 0x82, 0x46, + 0xe4, 0x61, 0xf5, 0x01, 0x2f, 0xd7, 0xa6, 0xad, 0xac, 0x6b, 0x9f, 0x45, + 0x7f, 0x53, 0xd4, 0xf6, 0x74, 0x05, 0x63, 0x9d, 0x67, 0xe3, 0x6e, 0xae, + 0x48, 0x5f, 0xad, 0xdc, 0xe5, 0xfe, 0xbf, 0x6d, 0x53, 0x42, 0xfa, 0x3e, + 0x19, 0xd7, 0xa8, 0x67, 0x77, 0xc3, 0x9f, 0x3b, 0x1f, 0x30, 0xbe, 0x4c, + 0x31, 0xf6, 0x4c, 0x31, 0x66, 0x18, 0x9e, 0x1f, 0x8c, 0x37, 0xe0, 0x88, + 0x03, 0xc7, 0x79, 0x4f, 0x6f, 0x4f, 0x7b, 0xb8, 0xfc, 0xdc, 0xd3, 0xf7, + 0xa5, 0x2f, 0xdd, 0x73, 0xe7, 0xba, 0x61, 0xba, 0xe3, 0x66, 0xed, 0x87, + 0x61, 0xf7, 0xa0, 0x3f, 0x3e, 0xad, 0xa0, 0x5f, 0xb9, 0x9a, 0x7b, 0x1f, + 0xb0, 0x71, 0xe8, 0x1e, 0x3f, 0xfd, 0xbb, 0x75, 0x73, 0x6f, 0x57, 0x06, + 0xbc, 0xd3, 0x0c, 0xf9, 0xce, 0x84, 0x49, 0x4b, 0x7d, 0x12, 0xfb, 0xe5, + 0x18, 0x63, 0x62, 0x1e, 0x7c, 0x1c, 0x31, 0x87, 0xcd, 0x59, 0xe2, 0x8e, + 0x0a, 0x70, 0x22, 0x8f, 0x4c, 0xb7, 0x78, 0xf7, 0xfc, 0x7d, 0x9e, 0x0f, + 0xdc, 0xbb, 0x38, 0x46, 0xff, 0x7d, 0x8f, 0x9e, 0x1b, 0x9d, 0x2e, 0x3d, + 0xfe, 0xfa, 0x80, 0x79, 0xe7, 0x78, 0x75, 0xaf, 0x27, 0x4f, 0x7c, 0x3f, + 0xe3, 0xd1, 0xc5, 0xbb, 0x69, 0xa4, 0x89, 0xf7, 0xf2, 0x5f, 0xc0, 0xa3, + 0xf3, 0x8c, 0x82, 0x4a, 0x23, 0x6f, 0x49, 0x31, 0x56, 0xc1, 0xe6, 0xc5, + 0xc2, 0x9d, 0x24, 0xec, 0x69, 0xec, 0x7a, 0xb7, 0xc4, 0x7b, 0xbe, 0x05, + 0x1f, 0xcd, 0x7b, 0xff, 0x50, 0xe6, 0x4a, 0xfd, 0x76, 0xb3, 0x41, 0x7b, + 0x4d, 0x24, 0xcf, 0xcb, 0xb0, 0x7d, 0x5e, 0xe7, 0x4f, 0x89, 0xf8, 0x29, + 0xa1, 0x6c, 0x6f, 0xc9, 0x80, 0xce, 0x6b, 0x3e, 0x14, 0x0b, 0x72, 0x99, + 0x2a, 0xc3, 0xc6, 0xc6, 0xfe, 0xcd, 0xd1, 0xf9, 0x28, 0xf2, 0xa5, 0x1b, + 0x3b, 0xe0, 0x7a, 0x53, 0xe3, 0x21, 0xbe, 0x46, 0x5c, 0x86, 0xb4, 0x8c, + 0xf9, 0xf8, 0x2c, 0x99, 0xaf, 0xfb, 0x38, 0xc3, 0xf0, 0xc3, 0xf0, 0x01, + 0x63, 0xbf, 0xe1, 0xe9, 0x0b, 0xbf, 0x7f, 0xe8, 0x30, 0x07, 0x52, 0xe9, + 0x3f, 0xf7, 0xe6, 0xae, 0x50, 0x06, 0x18, 0xfb, 0x72, 0x7f, 0xd1, 0xf3, + 0x39, 0x05, 0x23, 0x53, 0xa7, 0x0c, 0xa8, 0x2b, 0xb8, 0x7f, 0xad, 0x9f, + 0xb0, 0x99, 0xf2, 0x17, 0x10, 0x1f, 0xbb, 0xdd, 0xbc, 0x01, 0xb5, 0x55, + 0xa6, 0xce, 0xb9, 0xf5, 0x96, 0xac, 0xdd, 0xe4, 0xd9, 0xd2, 0x41, 0xcc, + 0x4d, 0xe1, 0x8f, 0xb2, 0x23, 0xcc, 0x61, 0x7c, 0x67, 0x3c, 0x38, 0x19, + 0xcf, 0x22, 0x66, 0x65, 0x0e, 0x4f, 0x60, 0x6c, 0x78, 0x35, 0x96, 0x96, + 0x7b, 0x05, 0x39, 0x0a, 0xe4, 0x39, 0x00, 0x7e, 0xe2, 0x32, 0x51, 0xc7, + 0x9d, 0x6f, 0xf9, 0xb3, 0x2d, 0x98, 0xc2, 0x6d, 0x18, 0xd7, 0xf7, 0x4d, + 0xd4, 0x7f, 0xec, 0xd0, 0x1f, 0xfc, 0xad, 0xb6, 0x97, 0x78, 0x43, 0xde, + 0x97, 0x31, 0x9e, 0x28, 0x4f, 0x1a, 0x87, 0xca, 0xdc, 0xa3, 0x5e, 0xea, + 0x11, 0x2b, 0x9e, 0x55, 0xc8, 0x51, 0xc7, 0x3a, 0x71, 0xe6, 0x29, 0xe8, + 0x46, 0xc1, 0x98, 0x1a, 0xea, 0x92, 0x7c, 0xb2, 0x07, 0x34, 0x3f, 0x82, + 0x1e, 0xb1, 0xc3, 0xfa, 0x35, 0xcc, 0x43, 0x8f, 0x92, 0xb4, 0x8f, 0x56, + 0x5d, 0x57, 0x4e, 0xeb, 0xb8, 0x35, 0xe0, 0xe9, 0xd6, 0x3f, 0x99, 0xae, + 0x2e, 0x3d, 0x8d, 0xf1, 0x2e, 0xcc, 0xff, 0x26, 0x7a, 0xc4, 0xac, 0x31, + 0x7f, 0x9e, 0x36, 0x38, 0x8e, 0xf9, 0xcf, 0x01, 0xc7, 0x9f, 0xe0, 0xfb, + 0x7e, 0x7c, 0xff, 0xd1, 0xb6, 0xbd, 0xdf, 0xe0, 0xd9, 0x98, 0xcf, 0x6e, + 0x9b, 0xf7, 0xfd, 0xb7, 0x8e, 0x93, 0xd2, 0xbd, 0x06, 0xc6, 0xd7, 0x22, + 0xb2, 0xfb, 0x7c, 0x9b, 0xa8, 0xaa, 0xeb, 0xc3, 0x55, 0xd5, 0x94, 0x9e, + 0xf3, 0xf4, 0xdf, 0x3f, 0xc2, 0x1e, 0x4b, 0xd4, 0x1a, 0x2e, 0x8d, 0x77, + 0xab, 0x6d, 0xf4, 0x99, 0xe3, 0x7d, 0x4b, 0xec, 0x0b, 0xc7, 0x47, 0x6b, + 0x84, 0xe1, 0xf7, 0x89, 0xe3, 0x7d, 0xb5, 0x9f, 0x00, 0x16, 0x72, 0x29, + 0xfb, 0xf8, 0x09, 0xff, 0xda, 0xb6, 0x33, 0xb5, 0x6c, 0x71, 0x26, 0xed, + 0xfe, 0x99, 0xe3, 0xd9, 0x0a, 0xf3, 0x83, 0x44, 0x4c, 0x74, 0x1e, 0x5e, + 0x38, 0x3e, 0x53, 0x0a, 0x4b, 0x48, 0xd3, 0xe2, 0xaf, 0x73, 0x8d, 0xf7, + 0xb0, 0x13, 0x6d, 0xa4, 0xab, 0x11, 0x0f, 0xe3, 0x0c, 0xf1, 0x9c, 0x00, + 0x9e, 0x24, 0xf0, 0x30, 0xde, 0xb8, 0xf4, 0xc6, 0x97, 0x76, 0xa2, 0x8d, + 0xb8, 0x78, 0x96, 0x8f, 0xaf, 0x47, 0xd4, 0xf9, 0xb7, 0x49, 0xaf, 0xc9, + 0x9c, 0xd6, 0xf5, 0x35, 0x4d, 0x92, 0x3f, 0x8b, 0xdc, 0xc6, 0x1e, 0xf3, + 0xc6, 0x77, 0x9b, 0xac, 0xb7, 0xe3, 0x8a, 0xf3, 0xec, 0xb1, 0x96, 0x8a, + 0x63, 0x0e, 0xe3, 0x65, 0x1f, 0x56, 0x79, 0xb0, 0x1d, 0x0d, 0x7c, 0x37, + 0x79, 0xb2, 0xe6, 0x99, 0x7e, 0xdd, 0xd9, 0x48, 0x0b, 0x40, 0x71, 0x0f, + 0xdd, 0x5b, 0xf7, 0xe0, 0xf3, 0x89, 0x85, 0x35, 0xd2, 0x96, 0x04, 0xaf, + 0x3e, 0x6d, 0x9f, 0xf6, 0xfe, 0xb8, 0x37, 0x89, 0x3f, 0xff, 0x3c, 0x5f, + 0x06, 0xa4, 0x8b, 0x3d, 0x74, 0xf9, 0x13, 0x75, 0x73, 0x12, 0x76, 0xc7, + 0x37, 0x10, 0xc7, 0x59, 0xb5, 0x29, 0xfb, 0x16, 0xdc, 0xbb, 0xf6, 0xb1, + 0xa8, 0x21, 0x14, 0x73, 0xb9, 0x38, 0xeb, 0xd5, 0xa3, 0xb2, 0x09, 0x5c, + 0x19, 0xd4, 0x94, 0x6e, 0x5d, 0x34, 0x0d, 0xff, 0xb8, 0x0e, 0xfd, 0xbc, + 0x6a, 0xf1, 0x2d, 0x26, 0xcc, 0x78, 0x27, 0xc5, 0xda, 0xcf, 0x01, 0xc3, + 0x3c, 0xea, 0xf6, 0x3b, 0xcb, 0x12, 0x60, 0x96, 0xb1, 0x76, 0xca, 0xf5, + 0xcb, 0xf4, 0xed, 0xc8, 0xa9, 0x50, 0xc3, 0x58, 0xff, 0xe3, 0xe4, 0xa3, + 0x8d, 0xb0, 0x3b, 0xbd, 0x83, 0x20, 0xe6, 0x2c, 0x26, 0xe6, 0x97, 0xe0, + 0xc3, 0x2b, 0x96, 0xda, 0xad, 0xb4, 0x46, 0x26, 0x2a, 0xf0, 0x49, 0xa8, + 0x78, 0x13, 0xf1, 0x25, 0x79, 0x5f, 0xdf, 0x43, 0x93, 0x35, 0x6c, 0xf6, + 0xa8, 0xaf, 0x52, 0xaf, 0x34, 0xe5, 0xa1, 0x33, 0x88, 0xcb, 0x23, 0x4f, + 0x20, 0xe6, 0x40, 0x5e, 0x67, 0x0a, 0xa8, 0xe2, 0xa9, 0x23, 0x3f, 0xf8, + 0x83, 0x19, 0xcb, 0xcd, 0xff, 0x75, 0x3c, 0x13, 0x97, 0xc7, 0xd0, 0x99, + 0x76, 0xed, 0x67, 0xf2, 0xda, 0xdf, 0xf4, 0x9b, 0x53, 0xaa, 0x0d, 0x39, + 0x06, 0x12, 0x4f, 0x64, 0x38, 0xe6, 0xa0, 0x48, 0x1f, 0xf3, 0x4e, 0xf8, + 0xe1, 0xbe, 0x35, 0x78, 0xb7, 0x33, 0x84, 0x57, 0x12, 0x3e, 0x13, 0x92, + 0xa6, 0x33, 0x7c, 0x0b, 0x91, 0x3d, 0xa8, 0xc3, 0x88, 0xb3, 0x2f, 0x8c, + 0x7e, 0x02, 0x7f, 0xfb, 0x90, 0x5f, 0x99, 0xc8, 0x8d, 0x77, 0x80, 0x07, + 0x2c, 0xf7, 0xec, 0x04, 0xdf, 0xd5, 0x2d, 0x6d, 0x11, 0xec, 0x21, 0x3c, + 0xf2, 0x43, 0x6b, 0x0f, 0xe8, 0x71, 0xcf, 0x27, 0x8e, 0xf0, 0x19, 0x91, + 0xfe, 0x05, 0xe9, 0x51, 0x7a, 0x4f, 0x58, 0x66, 0x52, 0x5c, 0x6b, 0x07, + 0x3c, 0xf7, 0x61, 0x4d, 0xef, 0x73, 0xdf, 0x94, 0xf2, 0xb7, 0xe9, 0xc6, + 0x9c, 0x81, 0x6f, 0xe4, 0x53, 0x29, 0x53, 0xfa, 0xab, 0x2e, 0x6c, 0xdf, + 0xda, 0x53, 0xdd, 0x7c, 0x97, 0x52, 0x96, 0x4b, 0x9b, 0x42, 0xee, 0x9b, + 0x87, 0x54, 0xc3, 0x83, 0x7c, 0x9b, 0x21, 0x0c, 0xeb, 0xd9, 0x2e, 0x0d, + 0x63, 0x0e, 0x52, 0x7e, 0xee, 0x9c, 0x52, 0xff, 0xd7, 0x9b, 0x4b, 0x63, + 0x4e, 0xa1, 0x6d, 0x05, 0xfb, 0xbf, 0xa9, 0x6d, 0x45, 0x54, 0xdc, 0xb3, + 0x15, 0x8c, 0x97, 0x39, 0xf6, 0x63, 0xf1, 0xf1, 0x7b, 0x5c, 0x7f, 0xef, + 0xc8, 0xac, 0xcd, 0xf7, 0x0b, 0x47, 0xae, 0xda, 0x05, 0xe3, 0xc0, 0x1d, + 0x79, 0x66, 0x52, 0xc7, 0xe7, 0x19, 0xc8, 0x7e, 0xb3, 0xa6, 0x6b, 0x35, + 0xb9, 0x56, 0x8b, 0xc8, 0x3b, 0x2b, 0x6d, 0xb2, 0xb9, 0xe4, 0xea, 0xfc, + 0xe6, 0x12, 0xf5, 0xdc, 0x94, 0x9f, 0xad, 0x58, 0x58, 0x4b, 0xe2, 0xaf, + 0x47, 0x6e, 0xac, 0xdc, 0x99, 0x77, 0x5e, 0xae, 0x3f, 0x0a, 0x5a, 0x7a, + 0x24, 0x64, 0x39, 0xba, 0xee, 0xca, 0x21, 0xf6, 0x15, 0x64, 0x42, 0xf2, + 0xe5, 0x7e, 0xd4, 0x7e, 0x08, 0xce, 0x61, 0xc6, 0x20, 0xdc, 0x7f, 0xf9, + 0xf3, 0xc8, 0x4d, 0x12, 0x30, 0x9e, 0x7e, 0xfd, 0xa6, 0xf8, 0xc5, 0x70, + 0x8f, 0x34, 0x5b, 0xdf, 0xec, 0x76, 0x63, 0x95, 0xe9, 0xd6, 0xa7, 0x96, + 0x1f, 0xaf, 0xdf, 0x04, 0xee, 0x11, 0xe8, 0x29, 0x75, 0xd3, 0x86, 0xce, + 0x9a, 0xb2, 0x3a, 0x94, 0xa8, 0x14, 0x84, 0xfe, 0x21, 0xc5, 0x7c, 0x11, + 0xfb, 0x92, 0x90, 0x47, 0xab, 0xce, 0x85, 0x32, 0x0a, 0x77, 0xbb, 0x30, + 0x27, 0xf9, 0xfa, 0xef, 0x63, 0x3e, 0x23, 0xd3, 0xf5, 0x71, 0x9c, 0x75, + 0x1a, 0x7a, 0xfb, 0x60, 0x8f, 0xb4, 0xf1, 0x9c, 0x14, 0x68, 0x7c, 0x44, + 0x66, 0xce, 0xce, 0xc9, 0x91, 0x32, 0xe9, 0xe4, 0x1b, 0x63, 0x22, 0x99, + 0x93, 0xe1, 0xf8, 0x0a, 0x72, 0x27, 0xd7, 0x1e, 0xd3, 0x32, 0x73, 0x0e, + 0x38, 0xca, 0xac, 0xff, 0xfb, 0xa1, 0x37, 0xc3, 0xba, 0x7e, 0x99, 0xd6, + 0x7e, 0x87, 0xf3, 0x6f, 0xe3, 0x9e, 0xfa, 0x0b, 0xfb, 0x00, 0x97, 0x47, + 0xad, 0x33, 0x85, 0x7c, 0x79, 0xb9, 0x8c, 0x3a, 0xcf, 0x0e, 0x31, 0xf7, + 0x52, 0xea, 0xa1, 0x5e, 0xa9, 0x96, 0x87, 0x4d, 0xa5, 0x98, 0x53, 0xf1, + 0x2e, 0xb8, 0x46, 0xfb, 0x8e, 0xa9, 0xb0, 0xd5, 0x2b, 0x2b, 0xe5, 0x02, + 0xea, 0x65, 0xe5, 0xbd, 0x67, 0x14, 0xc4, 0xb4, 0x5c, 0xbf, 0xa7, 0x6b, + 0x1b, 0xe6, 0x9f, 0xf5, 0x2f, 0x80, 0xc6, 0x0c, 0x2e, 0xf3, 0x24, 0xe8, + 0xc3, 0xf7, 0x32, 0x74, 0x7c, 0x81, 0x39, 0x5c, 0x06, 0x6b, 0x69, 0x39, + 0x76, 0x61, 0x0a, 0x34, 0x74, 0x4a, 0xff, 0x9f, 0xd1, 0xc6, 0x9e, 0xc4, + 0x1c, 0xc7, 0x09, 0xe8, 0xeb, 0xd7, 0xf1, 0x4d, 0xd8, 0x18, 0x7a, 0xca, + 0xa1, 0x17, 0xbd, 0x09, 0x5a, 0x58, 0x07, 0x43, 0xfe, 0x87, 0xe3, 0x52, + 0x3d, 0xfb, 0xb0, 0x4c, 0x2f, 0x3f, 0x0c, 0xfc, 0xff, 0x8a, 0xba, 0x00, + 0xf1, 0x6d, 0x99, 0x67, 0x31, 0xff, 0xe3, 0x39, 0x10, 0x10, 0x6d, 0x63, + 0x81, 0xf3, 0xec, 0x0f, 0x62, 0x3f, 0x6a, 0x8c, 0x72, 0x46, 0x66, 0xca, + 0x3c, 0x0b, 0x77, 0x87, 0x7c, 0x2a, 0x7f, 0x76, 0xca, 0xbb, 0xe3, 0x1e, + 0xc9, 0x45, 0x0b, 0xac, 0x2f, 0x10, 0x27, 0x96, 0x46, 0xb3, 0xa5, 0x84, + 0x99, 0x55, 0xc4, 0x95, 0x14, 0xc6, 0x06, 0x77, 0x2e, 0x22, 0xd6, 0x02, + 0x6a, 0xda, 0x34, 0xd7, 0x4e, 0x7a, 0x6f, 0x06, 0xc4, 0xf5, 0x63, 0x99, + 0x80, 0x8e, 0xf5, 0x2f, 0x8c, 0x20, 0x17, 0xfe, 0x29, 0x72, 0xc9, 0xb8, + 0x27, 0x83, 0x71, 0x4f, 0x37, 0xda, 0x1a, 0x74, 0x02, 0xf7, 0x5c, 0xc6, + 0xdd, 0x97, 0xa1, 0x07, 0xf0, 0xd5, 0xaf, 0x6e, 0xe9, 0xc7, 0x78, 0x43, + 0x8e, 0xd9, 0x21, 0xff, 0x50, 0x49, 0x24, 0xd7, 0xa1, 0x3f, 0x37, 0x50, + 0x0b, 0xac, 0xa3, 0x3e, 0xdc, 0xb4, 0x23, 0xa8, 0x4b, 0x0e, 0x83, 0x7e, + 0xe6, 0x94, 0x1c, 0xc7, 0x74, 0xae, 0xd3, 0x62, 0x3d, 0x7f, 0x8f, 0x7e, + 0xd7, 0x95, 0xaf, 0xf6, 0xb0, 0xa6, 0x64, 0x3d, 0xce, 0x37, 0xe9, 0x77, + 0x70, 0x8f, 0xeb, 0x26, 0xd7, 0xfd, 0x7d, 0xac, 0x05, 0x7c, 0xfd, 0x21, + 0x2d, 0xd4, 0x1f, 0xee, 0x21, 0x4c, 0x8f, 0xb6, 0x93, 0xbc, 0xc6, 0x47, + 0x9d, 0xfd, 0x9b, 0x6e, 0xd7, 0xce, 0x74, 0x9e, 0x65, 0x5e, 0x13, 0x5f, + 0x7f, 0x3f, 0x74, 0x58, 0xd7, 0x65, 0x87, 0xe0, 0xbb, 0xeb, 0x8e, 0xbc, + 0x60, 0xdf, 0x69, 0x77, 0xfb, 0xcb, 0xbe, 0x9c, 0x28, 0xc7, 0xc3, 0x72, + 0xaa, 0x9e, 0x80, 0x4d, 0x50, 0x86, 0x56, 0x83, 0x0c, 0x45, 0xfe, 0xaa, + 0x2c, 0xf2, 0x4a, 0x99, 0x6b, 0x5a, 0x86, 0xb1, 0x6c, 0xa8, 0x8d, 0xef, + 0xea, 0xd0, 0xcb, 0xb7, 0xe5, 0xc8, 0xa2, 0xc8, 0x05, 0xac, 0xaf, 0x96, + 0x69, 0xab, 0x23, 0xc8, 0x5f, 0x77, 0x49, 0x75, 0x09, 0x35, 0x59, 0x59, + 0xa6, 0xb3, 0x9f, 0x63, 0xbc, 0x89, 0xc8, 0xa6, 0x7e, 0x8f, 0x15, 0x19, + 0xbc, 0x18, 0x96, 0xf0, 0x45, 0x14, 0x7f, 0x90, 0xfd, 0xa5, 0x21, 0xff, + 0x7d, 0xd6, 0xb5, 0xf9, 0x62, 0x09, 0x7b, 0xcb, 0xfd, 0xda, 0x4f, 0x16, + 0x6b, 0x33, 0x92, 0xaf, 0xf0, 0x2c, 0xf4, 0x4b, 0x71, 0xac, 0xa5, 0x64, + 0xf6, 0xec, 0x88, 0x3c, 0x8b, 0x33, 0x50, 0xff, 0xe1, 0x8c, 0x09, 0x29, + 0x5c, 0xc0, 0x7c, 0xed, 0xba, 0x2c, 0xad, 0xcc, 0x48, 0xb5, 0x72, 0xb9, + 0xe1, 0xdd, 0x1d, 0xe3, 0xa5, 0xc6, 0x5a, 0xf6, 0x30, 0xeb, 0x19, 0xd4, + 0xaa, 0x16, 0xc6, 0x90, 0x59, 0x6d, 0x76, 0xfa, 0xce, 0xf7, 0xe2, 0xc6, + 0x1a, 0x76, 0x52, 0xe6, 0xcb, 0x29, 0x29, 0x9e, 0x1d, 0xd1, 0x6f, 0x0a, + 0x2d, 0xe9, 0xca, 0xd3, 0x37, 0x11, 0x2b, 0x26, 0xf5, 0x7b, 0xf1, 0x2d, + 0x79, 0xcc, 0x9e, 0x97, 0xa3, 0xd6, 0x41, 0x39, 0x85, 0xfc, 0xfa, 0x4b, + 0x76, 0xab, 0xc4, 0xbb, 0x79, 0x8f, 0xa0, 0xd7, 0x62, 0x0d, 0xea, 0xc8, + 0x84, 0xfd, 0xa0, 0xf9, 0x3c, 0x24, 0xfb, 0x4e, 0x8d, 0x71, 0xf2, 0xbf, + 0x9d, 0x0c, 0xe2, 0xde, 0x4d, 0xd4, 0x8e, 0x19, 0x0d, 0x67, 0xb8, 0x70, + 0x15, 0xc2, 0x0d, 0x9b, 0x2f, 0x10, 0x6e, 0xc9, 0xf0, 0xe0, 0x0c, 0xc0, + 0x85, 0x64, 0xc3, 0x0e, 0x43, 0x47, 0x26, 0xc1, 0x27, 0x7c, 0xfc, 0x68, + 0x87, 0x97, 0x07, 0xb7, 0x22, 0xb6, 0xde, 0xde, 0xff, 0x86, 0xb7, 0xff, + 0x59, 0x6f, 0xff, 0xd5, 0xad, 0xfd, 0x7e, 0x7c, 0xfd, 0x85, 0x23, 0x0d, + 0x74, 0xbd, 0x51, 0x72, 0xe1, 0xe7, 0x3d, 0xba, 0xae, 0x6e, 0xd1, 0xe5, + 0xc3, 0x43, 0x9e, 0x9a, 0x67, 0xfa, 0x66, 0xfa, 0xe8, 0x7e, 0xc8, 0xd1, + 0x91, 0x9c, 0x0d, 0xdb, 0x28, 0x27, 0xc6, 0x0b, 0xfa, 0x2d, 0x4d, 0xc9, + 0x7a, 0x74, 0x5e, 0x26, 0xad, 0xc4, 0xf8, 0xac, 0x84, 0xa0, 0xcb, 0xf4, + 0x2d, 0x21, 0xa9, 0xd2, 0xe7, 0xa0, 0xcf, 0xdb, 0x3b, 0xd3, 0xfa, 0x4e, + 0x03, 0xad, 0xa1, 0x97, 0x49, 0xa3, 0x4b, 0x6b, 0x64, 0xe0, 0x36, 0xad, + 0x2e, 0xbc, 0x4b, 0xeb, 0x3b, 0xa5, 0x06, 0xf8, 0x8b, 0x61, 0x0f, 0x3e, + 0xdc, 0x00, 0x4f, 0x7d, 0x66, 0x5e, 0x41, 0x7d, 0x26, 0x6d, 0x9f, 0x85, + 0x6d, 0x48, 0xa4, 0x35, 0x5d, 0x39, 0xfe, 0xc0, 0x80, 0x23, 0x11, 0xe4, + 0x1b, 0xcd, 0x58, 0xdb, 0xac, 0x30, 0x17, 0x51, 0x7d, 0xcd, 0x32, 0x08, + 0x9d, 0xe5, 0xdd, 0xb9, 0x6f, 0x82, 0x8f, 0xe9, 0x9c, 0xc0, 0x91, 0xa3, + 0x36, 0x69, 0x79, 0xdf, 0x79, 0x25, 0x3a, 0x68, 0x17, 0x65, 0xc8, 0x6c, + 0xc6, 0xf9, 0xd5, 0xba, 0xc6, 0x99, 0x24, 0x2d, 0xe7, 0x87, 0xfa, 0xcd, + 0xbf, 0x07, 0x9f, 0x13, 0x15, 0x43, 0xaa, 0x56, 0x22, 0x76, 0x09, 0x38, + 0xf6, 0xe1, 0x6e, 0xaa, 0x23, 0xa4, 0x47, 0xe4, 0x08, 0xf4, 0xbb, 0xaa, + 0xe3, 0x22, 0xf5, 0x38, 0x31, 0x59, 0x40, 0xae, 0xf3, 0xd7, 0x3a, 0xb6, + 0x39, 0xce, 0x4d, 0xc4, 0xb7, 0xc9, 0x6d, 0xba, 0xa7, 0x2e, 0xba, 0xba, + 0xa7, 0x2e, 0xa2, 0x06, 0x3e, 0x1d, 0x91, 0x96, 0x55, 0xd8, 0xcf, 0xcb, + 0x7b, 0xdc, 0x7c, 0xee, 0x65, 0xfe, 0xe6, 0x04, 0x7f, 0x77, 0x3a, 0x2c, + 0xd6, 0x69, 0x1d, 0x0f, 0x20, 0xef, 0x09, 0x99, 0x3d, 0x47, 0x9f, 0x6a, + 0xc9, 0xc0, 0x69, 0xde, 0x07, 0xf3, 0x9a, 0xa5, 0xd1, 0x19, 0xd8, 0xc8, + 0x1c, 0xfc, 0x82, 0x5a, 0x7d, 0x57, 0x66, 0x2c, 0xca, 0xa1, 0x53, 0xda, + 0x56, 0x51, 0x8f, 0xaf, 0xc2, 0x37, 0xac, 0xc6, 0xa4, 0x09, 0xb6, 0xa5, + 0x2e, 0x46, 0x8d, 0xe2, 0xe2, 0x07, 0xb0, 0x07, 0xfe, 0x7e, 0x83, 0xdc, + 0xf2, 0x62, 0xcc, 0xa0, 0x6d, 0xa9, 0x8b, 0xd4, 0x73, 0xa4, 0x53, 0x17, + 0xa9, 0xe7, 0xa4, 0xc3, 0xb7, 0x17, 0x7c, 0x5f, 0x1c, 0xd1, 0xef, 0xd3, + 0x37, 0x6d, 0xf2, 0xf2, 0x8f, 0x92, 0xad, 0x30, 0x47, 0x24, 0x3f, 0xd2, + 0x8d, 0x5c, 0xa6, 0x2b, 0x6b, 0x0f, 0x8c, 0x6f, 0xca, 0xa7, 0xe5, 0xeb, + 0xee, 0x4f, 0xc1, 0x17, 0xf9, 0x68, 0xe4, 0x8b, 0x3c, 0x75, 0x4a, 0x93, + 0xe6, 0xcb, 0xe7, 0x07, 0x82, 0x06, 0x3f, 0x7d, 0xa7, 0x63, 0xc0, 0xff, + 0x75, 0xf8, 0x80, 0x5e, 0xf4, 0x4f, 0xa2, 0x47, 0x48, 0xbb, 0x48, 0xde, + 0xc9, 0xeb, 0x0d, 0xe4, 0x8d, 0x3e, 0x9f, 0xd3, 0xf8, 0x7e, 0x5d, 0x66, + 0x17, 0x9d, 0x93, 0x88, 0xab, 0x7c, 0x3b, 0xef, 0x71, 0xdf, 0x81, 0xb7, + 0xf3, 0xfe, 0xba, 0xb8, 0xf2, 0x49, 0x98, 0x55, 0xc1, 0xf7, 0xca, 0x76, + 0x59, 0x34, 0xfa, 0x8e, 0x98, 0xce, 0xc3, 0x8f, 0xd4, 0xe8, 0x27, 0x28, + 0xa3, 0x1b, 0x92, 0x5d, 0xe4, 0xfb, 0x97, 0x8b, 0x6f, 0xba, 0xe6, 0xfb, + 0x8d, 0xc6, 0x3d, 0x36, 0xe0, 0x7a, 0x01, 0x47, 0xba, 0xd6, 0x29, 0x3f, + 0xf8, 0x9c, 0xbd, 0x0d, 0xbe, 0xa6, 0x71, 0xdf, 0xb8, 0x3c, 0x87, 0x3c, + 0xe0, 0x0d, 0xfb, 0x0e, 0xb9, 0x4e, 0x33, 0x17, 0xaa, 0xd6, 0xa6, 0x60, + 0x93, 0x4d, 0xf0, 0x65, 0xa6, 0x6c, 0x96, 0x9a, 0xa5, 0x8a, 0x7c, 0x67, + 0x79, 0x85, 0xbe, 0x90, 0xb4, 0xb7, 0x61, 0xde, 0xf5, 0x5f, 0xf4, 0xb5, + 0x9b, 0x25, 0xc4, 0x59, 0xd8, 0xf6, 0x66, 0x29, 0x8a, 0xbe, 0x17, 0xbd, + 0x85, 0x3e, 0x8e, 0x3e, 0x89, 0x7e, 0x04, 0xfd, 0x08, 0x7a, 0x0b, 0x7b, + 0x63, 0xe8, 0xfd, 0x9a, 0x81, 0xb8, 0x6e, 0xf3, 0x5d, 0xd4, 0xe7, 0x21, + 0x57, 0xb4, 0x18, 0xd3, 0xc2, 0x76, 0x0e, 0x75, 0x44, 0x76, 0x84, 0xb9, + 0x1e, 0x73, 0xbe, 0x8f, 0x1d, 0xd3, 0x62, 0x5d, 0x5e, 0x30, 0xf6, 0x0d, + 0x31, 0x2e, 0x54, 0x10, 0x17, 0x3e, 0xd8, 0x8d, 0xfa, 0xd1, 0xdc, 0xaf, + 0xdf, 0x8e, 0x16, 0x31, 0xe6, 0x37, 0x6a, 0xde, 0xe8, 0x1c, 0xe2, 0x14, + 0xfd, 0xa7, 0x83, 0x3d, 0x79, 0xf8, 0xf1, 0x2e, 0xd8, 0x5f, 0x06, 0x7e, + 0x1b, 0xdf, 0x4b, 0x6f, 0xec, 0x76, 0x63, 0x2a, 0xf2, 0x77, 0xb5, 0xfd, + 0xbd, 0xc6, 0xc6, 0x9e, 0x9d, 0x6a, 0x83, 0x0e, 0xe0, 0x48, 0x54, 0x96, + 0x60, 0x83, 0x3f, 0xb4, 0x4f, 0xea, 0xdc, 0x8e, 0x77, 0xf1, 0x2c, 0x72, + 0xd4, 0xdc, 0x02, 0x73, 0x98, 0x13, 0xa8, 0x4b, 0x50, 0x9f, 0x45, 0x59, + 0x93, 0x33, 0x16, 0xe8, 0x5c, 0x34, 0x2a, 0x6d, 0x8c, 0x03, 0x37, 0x70, + 0x1e, 0xf8, 0x5a, 0x76, 0x20, 0xb3, 0x03, 0xc8, 0x09, 0x1d, 0x27, 0x6c, + 0xed, 0x93, 0xf8, 0x21, 0xfa, 0x1c, 0xc1, 0x7e, 0x53, 0xdc, 0xf7, 0x74, + 0xf8, 0xdd, 0x29, 0xfd, 0x5b, 0x31, 0x94, 0xeb, 0xb3, 0xd8, 0x7b, 0x17, + 0x70, 0x71, 0x9e, 0x6f, 0xd9, 0x22, 0xfb, 0x16, 0xdc, 0x9c, 0x56, 0x59, + 0x8d, 0xf8, 0x7e, 0xd5, 0xc3, 0xc7, 0x75, 0xe5, 0xfd, 0xa6, 0xb1, 0xc7, + 0x7d, 0x1b, 0xc6, 0x1d, 0x9f, 0x42, 0xfe, 0xbc, 0x81, 0x7b, 0x79, 0x03, + 0x77, 0x72, 0xa5, 0x44, 0x5d, 0x1f, 0x86, 0xde, 0x43, 0x86, 0x53, 0xc4, + 0x35, 0xa2, 0xcf, 0xde, 0x28, 0xc1, 0x77, 0xd2, 0xff, 0x29, 0x64, 0x77, + 0x6d, 0x6e, 0x4c, 0x77, 0xf1, 0xf4, 0xba, 0x70, 0xe2, 0xaf, 0xed, 0xd6, + 0xf4, 0x54, 0xf5, 0x3b, 0x18, 0xe5, 0x04, 0x1d, 0xe4, 0x6f, 0x03, 0x1a, + 0xe6, 0x6b, 0x51, 0xfd, 0xfe, 0xae, 0x38, 0x47, 0x3e, 0x46, 0x24, 0xbb, + 0xe0, 0xef, 0xeb, 0xc6, 0xbe, 0xd6, 0x06, 0x5c, 0x77, 0x6f, 0xe3, 0x41, + 0x79, 0x3c, 0x70, 0xfd, 0x93, 0x6f, 0xc3, 0x85, 0xad, 0xb7, 0x61, 0xc6, + 0x5f, 0xde, 0x4d, 0x0a, 0xfb, 0xfd, 0xfb, 0xe9, 0xf5, 0x6a, 0x81, 0xc4, + 0x7c, 0x41, 0x98, 0xab, 0xf0, 0x8e, 0xc6, 0x61, 0xd7, 0x5d, 0xc0, 0x6f, + 0x4b, 0xa5, 0xd4, 0x22, 0xaa, 0x87, 0xb5, 0x31, 0x73, 0xe5, 0xc6, 0x33, + 0x7f, 0xdb, 0x3b, 0x13, 0xf5, 0xf4, 0x19, 0xe6, 0xcd, 0x3a, 0xce, 0x00, + 0xa6, 0x7d, 0x1b, 0x6d, 0xbf, 0xee, 0xc1, 0x71, 0x3d, 0x29, 0x05, 0xe4, + 0xa1, 0xb9, 0x05, 0x64, 0xf4, 0xf0, 0xdf, 0x2a, 0xcd, 0xdf, 0xb3, 0xf8, + 0x86, 0x37, 0x1c, 0x9f, 0x05, 0x8d, 0x05, 0x33, 0xc3, 0x77, 0x33, 0xe0, + 0xd8, 0xbb, 0x0d, 0xc7, 0x84, 0x87, 0x63, 0x42, 0x8a, 0xe7, 0x26, 0x61, + 0x6b, 0x19, 0xc4, 0xf7, 0x7e, 0xf3, 0x80, 0x7c, 0x1e, 0xc5, 0x35, 0xe6, + 0x2e, 0x8c, 0xe0, 0x9e, 0x1c, 0x67, 0x9f, 0x7d, 0x18, 0x74, 0xbf, 0x86, + 0xd8, 0xea, 0xe7, 0x3c, 0xc5, 0x58, 0x08, 0x31, 0xec, 0x98, 0xfe, 0x0d, + 0xb6, 0x60, 0x9a, 0xd0, 0x57, 0x65, 0x0c, 0x27, 0x51, 0xde, 0x23, 0xbe, + 0xcd, 0x23, 0x56, 0x91, 0xcf, 0x0e, 0x29, 0x9a, 0xc6, 0xa3, 0x21, 0xe4, + 0x35, 0xd9, 0x05, 0xda, 0x91, 0x0c, 0x84, 0xd2, 0xcd, 0xc8, 0x49, 0x1d, + 0xf9, 0x99, 0xcd, 0x7f, 0xa3, 0x30, 0x2f, 0x1b, 0x35, 0x13, 0xfd, 0x3a, + 0xee, 0xe1, 0xdb, 0xf8, 0xbe, 0xde, 0x83, 0xbc, 0x0f, 0x2b, 0x19, 0xe8, + 0x6e, 0x52, 0xe7, 0x33, 0xcc, 0x23, 0xaa, 0x88, 0xb7, 0x0a, 0xb1, 0x06, + 0x79, 0xd5, 0x38, 0x73, 0xd7, 0xe7, 0x96, 0xaf, 0xcb, 0x95, 0x45, 0xfe, + 0x06, 0xca, 0xb8, 0x7c, 0x90, 0xfe, 0xc0, 0x9c, 0x4b, 0x61, 0x6e, 0x85, + 0xbe, 0x0c, 0xe3, 0x3a, 0x0c, 0xa8, 0x07, 0x39, 0x02, 0x72, 0xed, 0x4d, + 0x2b, 0x09, 0x3e, 0xaf, 0xcb, 0xc6, 0x62, 0x58, 0x96, 0x2d, 0xe6, 0x45, + 0x12, 0xcf, 0x02, 0x76, 0x63, 0xe5, 0x9a, 0xab, 0x13, 0x84, 0x47, 0xcd, + 0x53, 0x40, 0x5e, 0x77, 0x40, 0xef, 0xfd, 0x65, 0xf7, 0x4c, 0x9a, 0x1a, + 0xeb, 0xbc, 0x19, 0xd9, 0xa0, 0x3d, 0xd9, 0x7c, 0x93, 0x62, 0x6e, 0x70, + 0x02, 0x3a, 0xcb, 0xdc, 0x9d, 0xf5, 0x00, 0xbe, 0x6b, 0x5c, 0x27, 0xef, + 0xe8, 0x97, 0xfa, 0x21, 0x1b, 0xda, 0x3d, 0xdf, 0xc4, 0x10, 0x47, 0x15, + 0x6d, 0xbd, 0xa8, 0x7d, 0x41, 0xb1, 0x3c, 0x83, 0x98, 0x02, 0x1f, 0xc0, + 0xdf, 0x70, 0xa6, 0xa6, 0x70, 0x97, 0xe3, 0x80, 0xdb, 0x16, 0x4b, 0xd6, + 0x8a, 0x3a, 0x2f, 0x53, 0xe7, 0x6f, 0xbf, 0xdf, 0xe4, 0x61, 0x3f, 0x6a, + 0x0d, 0xba, 0x05, 0x1b, 0x52, 0x6b, 0x51, 0xf4, 0xf0, 0xc7, 0x6b, 0xa8, + 0x2f, 0x4a, 0x7c, 0x1f, 0x42, 0x6d, 0x50, 0xe2, 0xdb, 0x49, 0x12, 0xfd, + 0x08, 0xdf, 0x8b, 0x3c, 0xbf, 0x46, 0xfc, 0xa4, 0xc3, 0xf7, 0x2f, 0xcc, + 0x25, 0xe9, 0x5f, 0xfc, 0x7c, 0xd2, 0xd5, 0x85, 0x53, 0x65, 0xfa, 0x10, + 0xea, 0x75, 0x3f, 0xfc, 0x16, 0x75, 0xc1, 0xcd, 0x25, 0x57, 0x2a, 0xae, + 0xcc, 0x66, 0xeb, 0x97, 0x75, 0x8c, 0xd8, 0x2f, 0x16, 0x74, 0x8c, 0xb2, + 0xc3, 0x9a, 0x8e, 0x01, 0x97, 0x24, 0xa3, 0x7b, 0xca, 0xec, 0x75, 0xc9, + 0xac, 0x8c, 0xc8, 0x0b, 0xda, 0x6f, 0xf9, 0x3e, 0x8b, 0x39, 0x64, 0x0c, + 0xf2, 0x4b, 0xca, 0xf3, 0x67, 0xaf, 0x4b, 0xf6, 0x45, 0xfa, 0xad, 0xe1, + 0x58, 0xab, 0x41, 0x5f, 0xe5, 0x48, 0x0d, 0xb1, 0xe9, 0x80, 0xcd, 0x7f, + 0x07, 0x10, 0x42, 0x4d, 0xe7, 0x48, 0xf3, 0x68, 0xc2, 0x8e, 0x1b, 0xfd, + 0x4f, 0xb6, 0x1a, 0x8c, 0x8d, 0xc3, 0xe6, 0x53, 0xe2, 0xbf, 0x47, 0xb5, + 0xc8, 0x53, 0xfa, 0xad, 0x02, 0x66, 0xbb, 0xf0, 0x91, 0xfe, 0x1d, 0xe5, + 0x66, 0x8a, 0xb2, 0xc6, 0x78, 0x8d, 0xf3, 0x85, 0xc8, 0xcd, 0x54, 0x93, + 0x14, 0xef, 0x72, 0x9c, 0xa3, 0xa3, 0xa9, 0xdd, 0xee, 0xbf, 0x15, 0xf9, + 0xc6, 0x5d, 0xae, 0x2f, 0x38, 0xea, 0x8d, 0x5f, 0x41, 0x4f, 0xdd, 0x66, + 0xbc, 0x65, 0x7c, 0xe4, 0xbd, 0xa1, 0x5f, 0xe1, 0x37, 0x63, 0xef, 0x3c, + 0x62, 0x2f, 0xe3, 0x65, 0x97, 0xe4, 0x0e, 0x6b, 0x9f, 0xc1, 0xf9, 0x82, + 0x9b, 0x4b, 0x7b, 0x70, 0x95, 0x69, 0x99, 0xad, 0x30, 0x87, 0xda, 0x40, + 0x2c, 0x1b, 0x82, 0xae, 0x32, 0xa6, 0x9d, 0x44, 0x3c, 0xe7, 0xef, 0xd2, + 0x58, 0x5b, 0xe2, 0xbe, 0x44, 0x32, 0xae, 0xc0, 0xf3, 0x96, 0x4e, 0xdd, + 0x8c, 0xf2, 0x3d, 0xea, 0xd2, 0x10, 0xee, 0xfd, 0x4f, 0x59, 0x5b, 0x0c, + 0x68, 0x1d, 0xc9, 0xbe, 0x4c, 0xd9, 0xbb, 0xbf, 0x5b, 0x4b, 0xb7, 0x6b, + 0x03, 0xcc, 0x03, 0x1e, 0x87, 0x5c, 0xf6, 0xdb, 0xd7, 0x19, 0xbb, 0xff, + 0x5d, 0x59, 0xc3, 0xc9, 0xa7, 0x0c, 0xda, 0x36, 0xc6, 0x2b, 0x21, 0x59, + 0x8a, 0x92, 0x7f, 0xc8, 0xcb, 0xa0, 0xed, 0xec, 0x24, 0x87, 0xed, 0x32, + 0xf8, 0x4b, 0xc8, 0x80, 0xb2, 0xf4, 0x65, 0xc0, 0xef, 0x49, 0xdc, 0x17, + 0x6b, 0x86, 0x7e, 0x5d, 0x47, 0x16, 0xeb, 0xee, 0xd9, 0xc5, 0x72, 0x23, + 0xcd, 0xa4, 0x97, 0x77, 0x7a, 0x49, 0x72, 0xfa, 0x7e, 0xe7, 0x25, 0x57, + 0xb9, 0x24, 0xfb, 0x2a, 0xf3, 0xf2, 0x98, 0xf5, 0x28, 0xf8, 0xbd, 0xe6, + 0xcc, 0x58, 0xba, 0x56, 0x19, 0xcf, 0xff, 0x6f, 0xe7, 0x56, 0x1b, 0xdb, + 0x56, 0x75, 0x86, 0x5f, 0x5f, 0xdb, 0x69, 0x1a, 0x9a, 0x70, 0xeb, 0x3a, + 0x89, 0x9b, 0x66, 0xad, 0x1d, 0xdf, 0x7e, 0x88, 0xa4, 0xe8, 0x36, 0x64, + 0x34, 0xea, 0x82, 0x62, 0x9c, 0x50, 0xc2, 0xe8, 0x44, 0xda, 0x75, 0x55, + 0xb5, 0x31, 0x64, 0x39, 0xe9, 0x07, 0xd3, 0x06, 0xa3, 0xb0, 0x82, 0x18, + 0x52, 0x8d, 0xdb, 0x6a, 0x9d, 0x96, 0xc6, 0xe9, 0x07, 0x6b, 0x37, 0x69, + 0x9a, 0xe5, 0xa4, 0x2d, 0x48, 0x11, 0x2e, 0x88, 0x6e, 0xfb, 0xb1, 0x8d, + 0x2a, 0x65, 0xec, 0xff, 0xf6, 0x67, 0xda, 0xd0, 0x16, 0x15, 0x18, 0xfc, + 0xd8, 0xa4, 0xfe, 0xe0, 0x47, 0x25, 0xe8, 0xbc, 0xe7, 0x79, 0xcf, 0xbd, + 0x8e, 0x6d, 0x82, 0x26, 0x2d, 0x52, 0xe4, 0x7b, 0xce, 0x3d, 0xf7, 0x9c, + 0x73, 0xcf, 0xfb, 0xfd, 0xbe, 0xcf, 0xc5, 0xda, 0x13, 0x7d, 0x6b, 0xe5, + 0x63, 0xf8, 0x1d, 0x27, 0x67, 0x6d, 0xc9, 0xd8, 0x83, 0xf2, 0x63, 0xcd, + 0xe5, 0x33, 0x3e, 0x09, 0xc0, 0x27, 0x35, 0xb8, 0x02, 0x69, 0x77, 0x62, + 0x37, 0x85, 0x3e, 0x65, 0x18, 0xb4, 0x8e, 0x1b, 0xbf, 0xd9, 0x36, 0xf7, + 0x37, 0x9d, 0x81, 0xef, 0xee, 0x0e, 0xb4, 0xfb, 0x39, 0x5f, 0xe3, 0xdf, + 0xfe, 0xc5, 0xab, 0xa1, 0x0d, 0xca, 0x0c, 0xf6, 0xf3, 0x96, 0xea, 0x59, + 0x07, 0xbc, 0xc4, 0xdc, 0x74, 0x4c, 0xf3, 0x0f, 0xe1, 0x69, 0xea, 0xa8, + 0xab, 0xd0, 0x51, 0x43, 0xd4, 0x5d, 0xc3, 0xb3, 0x2e, 0xf3, 0x03, 0x51, + 0xf9, 0xf3, 0x14, 0xf5, 0x70, 0x5c, 0xfe, 0x34, 0xf5, 0x02, 0xf6, 0x93, + 0x28, 0x32, 0x47, 0x79, 0x63, 0x26, 0x47, 0x3f, 0x49, 0xfd, 0xf9, 0xb4, + 0xfb, 0xac, 0xda, 0x81, 0xb8, 0x95, 0x5f, 0x13, 0x56, 0x7d, 0xf3, 0xb4, + 0xd6, 0x74, 0xe3, 0x56, 0xb7, 0xdc, 0x38, 0x6f, 0x74, 0x6c, 0x78, 0x3a, + 0x1a, 0x18, 0x99, 0xa3, 0x5d, 0x4a, 0xc6, 0xb2, 0xd6, 0x0a, 0x39, 0x10, + 0x65, 0xee, 0x39, 0x45, 0xfd, 0x0c, 0x5b, 0xd8, 0x6b, 0x67, 0xad, 0x66, + 0xcf, 0xfe, 0xc4, 0x1a, 0xf4, 0xec, 0xd3, 0x9e, 0x9e, 0xe5, 0xbd, 0x14, + 0x68, 0x4a, 0x5b, 0x94, 0x98, 0x19, 0xb5, 0x92, 0xb0, 0x79, 0xb8, 0x9e, + 0xe7, 0xfc, 0x71, 0x39, 0x32, 0x7f, 0x18, 0xfe, 0x77, 0xaf, 0xbd, 0x87, + 0x76, 0xd5, 0x1e, 0x22, 0x16, 0x07, 0xeb, 0x7f, 0xa9, 0x61, 0xae, 0xc7, + 0xbd, 0xb9, 0x78, 0x1f, 0x72, 0x3e, 0xed, 0xc8, 0x04, 0x6c, 0xc9, 0x88, + 0x6d, 0xf6, 0x5a, 0x3f, 0x76, 0x77, 0x75, 0xdd, 0x13, 0x05, 0xc7, 0xc3, + 0x85, 0xe1, 0x17, 0xbe, 0xd0, 0xd7, 0x23, 0x5c, 0x93, 0xeb, 0xb5, 0x49, + 0x7a, 0x1f, 0xf4, 0xcb, 0x34, 0xff, 0x73, 0x5e, 0xed, 0x0a, 0xf1, 0x4a, + 0xb4, 0x6b, 0x19, 0xdb, 0xf4, 0x80, 0x37, 0xdf, 0xb6, 0x0e, 0x69, 0x89, + 0xd6, 0x8c, 0x67, 0x6e, 0x85, 0xed, 0xb8, 0xe4, 0xe6, 0xf9, 0x5b, 0xa9, + 0x44, 0x9c, 0x26, 0xd9, 0x63, 0xaf, 0x6b, 0x98, 0x63, 0x2b, 0xfa, 0x8c, + 0x4f, 0x10, 0x9c, 0x0e, 0x78, 0xbe, 0xc5, 0x06, 0xfa, 0x4d, 0xde, 0x75, + 0xb3, 0xe6, 0x64, 0xe2, 0x56, 0x57, 0xc3, 0x7b, 0x6c, 0xa8, 0xda, 0xe1, + 0xb8, 0x45, 0xdd, 0xd9, 0x14, 0x95, 0x36, 0xf2, 0x50, 0x45, 0xfd, 0xf8, + 0x90, 0x63, 0xb0, 0x16, 0x51, 0xe7, 0x60, 0x07, 0x73, 0xf6, 0x6f, 0xeb, + 0xb9, 0xb5, 0xd2, 0x27, 0xc0, 0x35, 0xf8, 0xe4, 0x73, 0xf9, 0x5e, 0xe6, + 0x7a, 0x31, 0x7f, 0x0b, 0xe7, 0x77, 0xbd, 0x73, 0x4e, 0xb8, 0x39, 0xeb, + 0x7e, 0xc9, 0x9e, 0x37, 0xfc, 0x97, 0x76, 0xc0, 0x7b, 0x6d, 0x68, 0xcf, + 0xd1, 0x26, 0x7c, 0xd1, 0x3c, 0xbe, 0x6d, 0xd8, 0xa2, 0xb6, 0xe1, 0x78, + 0x81, 0xfc, 0x49, 0xbe, 0xf4, 0xf9, 0xd1, 0xd7, 0x79, 0xe4, 0x51, 0xea, + 0xd9, 0x41, 0x39, 0x53, 0xe0, 0xd9, 0xa4, 0xb4, 0xa6, 0xb5, 0xf1, 0xec, + 0x84, 0xe2, 0xb1, 0x7a, 0xa6, 0x13, 0x17, 0x73, 0x32, 0x2c, 0x57, 0x5d, + 0x9e, 0x59, 0xa2, 0x98, 0x09, 0xb6, 0xd6, 0xbc, 0xff, 0x3e, 0x3d, 0xb3, + 0xb0, 0xfa, 0x8c, 0x31, 0x8c, 0x7d, 0xc9, 0xa3, 0x77, 0x9b, 0x9e, 0x6d, + 0xa6, 0x8e, 0x3e, 0x8f, 0xea, 0x39, 0x85, 0xa1, 0x13, 0x59, 0xc7, 0x0f, + 0x47, 0xf8, 0x0c, 0xd7, 0xa5, 0xcf, 0xc7, 0xb5, 0xc8, 0x7b, 0x3d, 0xb0, + 0xd8, 0xfd, 0x12, 0xdc, 0x01, 0xd1, 0xdf, 0xc1, 0x3a, 0x72, 0x00, 0xb2, + 0xba, 0xd1, 0x60, 0x5f, 0xc6, 0x8d, 0xaf, 0x91, 0xb1, 0xde, 0xc2, 0x39, + 0x22, 0x56, 0x81, 0x1f, 0x7d, 0xfc, 0xa7, 0x77, 0x30, 0x5f, 0xc6, 0xf3, + 0xd7, 0x07, 0x30, 0x3f, 0xcf, 0x82, 0x32, 0x36, 0xb5, 0x8d, 0xbc, 0x3a, + 0xaa, 0xf5, 0x41, 0x3e, 0x43, 0x39, 0xe6, 0x99, 0x91, 0x2e, 0x7f, 0xc3, + 0xf3, 0x6c, 0x6f, 0x6d, 0xa0, 0x63, 0xd2, 0xdb, 0x9f, 0x7f, 0x3f, 0x2c, + 0xe1, 0x0e, 0xea, 0xb8, 0xa8, 0x24, 0xa7, 0x19, 0xb3, 0xc0, 0x76, 0x8d, + 0x73, 0xae, 0xff, 0xad, 0x8b, 0x33, 0xff, 0xa7, 0x2e, 0xce, 0x58, 0x1f, + 0x29, 0xef, 0x84, 0x35, 0x8f, 0xf5, 0xc5, 0x74, 0x2d, 0xd6, 0xd1, 0xd5, + 0xaf, 0xdd, 0x47, 0xab, 0x74, 0xfc, 0x51, 0x81, 0xf6, 0x2a, 0xa5, 0x39, + 0xe5, 0x7f, 0x4e, 0xf1, 0x6c, 0xb9, 0xc7, 0xab, 0xdc, 0xe3, 0xf0, 0x82, + 0x62, 0x20, 0xbf, 0xa6, 0x32, 0x7c, 0xb2, 0x40, 0x1d, 0xd3, 0x2a, 0xb3, + 0x33, 0xbe, 0x9e, 0x19, 0xf3, 0x7c, 0xdc, 0xfc, 0x9a, 0x26, 0xd5, 0x33, + 0xf0, 0x6e, 0x9c, 0x11, 0xcf, 0xbe, 0x74, 0x4b, 0xe9, 0x3c, 0xed, 0x6e, + 0x12, 0x7d, 0xd1, 0x40, 0x69, 0x8e, 0xb5, 0x49, 0x62, 0x50, 0x86, 0x85, + 0x75, 0xff, 0x11, 0xfb, 0x38, 0xe4, 0x2d, 0x26, 0xef, 0x4f, 0xd1, 0xa7, + 0x6f, 0x82, 0x6f, 0xdc, 0xd6, 0x70, 0xbe, 0xdb, 0xab, 0x3e, 0x61, 0x3d, + 0xdd, 0x37, 0x74, 0x4a, 0x0b, 0xf9, 0xdc, 0xb1, 0x6f, 0x08, 0x7d, 0x30, + 0x5e, 0x67, 0x11, 0x0b, 0x30, 0xf6, 0x88, 0x6b, 0xec, 0x51, 0x2a, 0xb2, + 0xaf, 0xd5, 0xcb, 0x2b, 0xb5, 0x2a, 0xaf, 0x90, 0xdf, 0x32, 0xea, 0x7f, + 0x0f, 0xa9, 0xce, 0xca, 0x4f, 0xf5, 0x1a, 0xfc, 0x8a, 0x1d, 0x53, 0xde, + 0x93, 0x3a, 0xde, 0x8b, 0x79, 0x6b, 0x3f, 0xdc, 0x69, 0x7c, 0x2b, 0x5b, + 0xf5, 0x4d, 0x58, 0xc7, 0xd1, 0xae, 0x70, 0x7e, 0xf2, 0x06, 0x79, 0x84, + 0x3a, 0xcf, 0x1f, 0xe7, 0xd3, 0xc3, 0x6f, 0x73, 0x3c, 0xf9, 0xbf, 0x16, + 0x8b, 0xe0, 0xcb, 0xaa, 0xdf, 0xe7, 0xcb, 0x1d, 0xef, 0xd5, 0xda, 0x04, + 0xca, 0x5d, 0x6d, 0x7d, 0xd2, 0x96, 0xc8, 0xf4, 0x12, 0x5d, 0xd2, 0xfd, + 0xdc, 0xff, 0x4b, 0xcc, 0xed, 0x42, 0xde, 0x96, 0xa3, 0xcd, 0x51, 0xa5, + 0x4d, 0x06, 0xb4, 0x89, 0x28, 0x6d, 0x18, 0xef, 0x3d, 0xe3, 0xf1, 0x5b, + 0x2b, 0xce, 0x8b, 0xb9, 0x5a, 0xe8, 0xba, 0xbd, 0xd4, 0xf9, 0xcf, 0x77, + 0x6a, 0x7d, 0xd0, 0xa1, 0xee, 0x5b, 0x05, 0x7d, 0xc6, 0xf6, 0x66, 0xf5, + 0x47, 0x4c, 0xbc, 0x15, 0xd7, 0x3c, 0x68, 0x10, 0xfa, 0xb9, 0x34, 0x05, + 0x5f, 0x8d, 0x78, 0xb7, 0x3a, 0x5a, 0x7d, 0xc7, 0x3b, 0xaf, 0x92, 0xd2, + 0x86, 0x32, 0x40, 0xbd, 0xb9, 0x1a, 0xf3, 0xed, 0x8e, 0xf6, 0x81, 0xbf, + 0x7e, 0x81, 0xfe, 0x8d, 0x1a, 0x4f, 0x04, 0x21, 0xf3, 0x37, 0xa7, 0x3a, + 0xbc, 0x18, 0xce, 0x41, 0x1b, 0x71, 0xeb, 0x54, 0x84, 0x31, 0x05, 0xda, + 0x5b, 0xa4, 0x69, 0x1a, 0xf1, 0x2b, 0xf4, 0xf8, 0x82, 0xda, 0xa3, 0x3e, + 0xdc, 0xbf, 0x8b, 0x18, 0x3f, 0x5c, 0x1f, 0xc6, 0x73, 0xbd, 0x06, 0x8b, + 0x10, 0xdd, 0xa4, 0x67, 0x5a, 0x9a, 0x4a, 0xc4, 0x0e, 0x8a, 0xd7, 0x37, + 0xee, 0xaa, 0x3e, 0x58, 0xda, 0xd7, 0x43, 0xb2, 0xbb, 0x6a, 0x2f, 0x18, + 0x47, 0xc3, 0x87, 0x9f, 0x31, 0xf6, 0x20, 0x5f, 0xec, 0x53, 0x5c, 0x54, + 0x70, 0x68, 0x1e, 0x67, 0x49, 0x9f, 0x74, 0x11, 0x7e, 0xb8, 0x8b, 0x33, + 0xa4, 0xdf, 0x5d, 0x39, 0x76, 0xc2, 0x4d, 0xb1, 0x3e, 0x06, 0x7d, 0x70, + 0x4c, 0x46, 0x10, 0x17, 0x8c, 0x04, 0xdb, 0x98, 0x57, 0x86, 0x6f, 0x98, + 0xf3, 0x72, 0x8f, 0x7d, 0xcc, 0x99, 0xca, 0xd9, 0x39, 0xee, 0x9d, 0xb2, + 0x6d, 0x62, 0xef, 0xd2, 0x14, 0xf7, 0x6b, 0xf2, 0x10, 0x6c, 0x5b, 0xd3, + 0x2e, 0x7e, 0x79, 0x16, 0x03, 0xf8, 0x1d, 0x84, 0x3c, 0x70, 0x2c, 0x7e, + 0xe7, 0x16, 0xe5, 0xdd, 0xf3, 0xbe, 0x6d, 0x0f, 0xc8, 0x3b, 0x4e, 0xe5, + 0xd8, 0x71, 0x77, 0x0d, 0xcf, 0xc0, 0xcd, 0xb1, 0x66, 0xed, 0x38, 0x6e, + 0x5e, 0x2a, 0x95, 0x05, 0x77, 0x61, 0x8d, 0xa5, 0xb4, 0xa4, 0xfc, 0xff, + 0x03, 0x67, 0x78, 0xfd, 0x3e, 0x4b, 0x0c, 0xfd, 0x48, 0x9b, 0xcf, 0xd7, + 0xfe, 0x6a, 0x6d, 0x81, 0xaf, 0xff, 0xc8, 0x8f, 0xe4, 0xcb, 0x45, 0xd9, + 0xa9, 0xfa, 0x7f, 0xb9, 0xe7, 0x6a, 0x75, 0xbf, 0xef, 0xdf, 0x52, 0xbf, + 0x93, 0x17, 0x63, 0x1a, 0x1f, 0x6c, 0x9a, 0x6e, 0xd4, 0x09, 0x4f, 0x78, + 0x75, 0x85, 0xe5, 0x78, 0x6f, 0xbf, 0xa7, 0x17, 0x52, 0xea, 0x3b, 0xa7, + 0x6c, 0xea, 0x07, 0xee, 0xa7, 0x45, 0x26, 0x2e, 0xdc, 0x01, 0x4d, 0x7c, + 0x1d, 0xcc, 0xb8, 0xcf, 0xd7, 0x1d, 0x6d, 0x9e, 0x2f, 0x6c, 0x49, 0xcf, + 0x59, 0xfa, 0x4e, 0x0e, 0xf4, 0x68, 0xbb, 0x64, 0xc6, 0x83, 0x92, 0x3c, + 0x1b, 0x8b, 0x19, 0x5f, 0x97, 0xfc, 0x07, 0x79, 0xd3, 0x3e, 0xad, 0x45, + 0xa1, 0xff, 0x6e, 0xe1, 0xda, 0x86, 0x9f, 0x21, 0xcf, 0x7b, 0xfd, 0x7b, + 0x76, 0x03, 0x8f, 0xee, 0xf0, 0x78, 0x94, 0xf7, 0x2d, 0x53, 0xff, 0xc0, + 0xd8, 0x9e, 0xb3, 0xdc, 0xa3, 0x79, 0xae, 0xe7, 0xac, 0x89, 0xd7, 0xeb, + 0x9f, 0xeb, 0xab, 0x3e, 0x87, 0xfb, 0xf0, 0x7d, 0xcd, 0xdc, 0x3b, 0x07, + 0xe1, 0xd3, 0xf5, 0xd1, 0xe6, 0xd0, 0x7e, 0x6f, 0x74, 0x77, 0x0a, 0xf9, + 0x3d, 0xe1, 0xf1, 0x1c, 0xf5, 0x4d, 0xc4, 0xd3, 0x37, 0x4b, 0xf6, 0x65, + 0xc4, 0xe0, 0x4f, 0x98, 0x13, 0xa9, 0xb1, 0x2f, 0x4f, 0x98, 0x77, 0xab, + 0xb3, 0x2f, 0x77, 0x7b, 0xf3, 0xf8, 0xf7, 0x7c, 0xbd, 0xe2, 0xb7, 0x7d, + 0xbd, 0xd2, 0xe8, 0xd3, 0xfa, 0xb4, 0xaf, 0xed, 0xaf, 0x8f, 0xf9, 0xf2, + 0xcb, 0xe6, 0x5d, 0xb2, 0x88, 0xd9, 0xe8, 0x53, 0x26, 0x72, 0x06, 0x2f, + 0x6d, 0x9d, 0xb1, 0x88, 0xfb, 0x70, 0x7e, 0x22, 0xe9, 0xc8, 0x1d, 0x8d, + 0xad, 0x4f, 0x5e, 0x18, 0xd3, 0x3c, 0x4f, 0xc9, 0xf5, 0xf4, 0x4e, 0x74, + 0x17, 0xe4, 0xea, 0x4a, 0x64, 0x09, 0x53, 0x34, 0x73, 0x34, 0x0d, 0x3b, + 0x94, 0xd2, 0x7a, 0xd9, 0xf7, 0xb0, 0xdf, 0x41, 0xc5, 0x73, 0xad, 0x74, + 0x5e, 0x94, 0x47, 0xec, 0x8a, 0xd6, 0x6e, 0x9a, 0x87, 0x8a, 0x47, 0x9b, + 0x4f, 0xfb, 0x7c, 0x4f, 0x7e, 0x9a, 0x39, 0x3a, 0x31, 0x53, 0x19, 0x0e, + 0x6d, 0xeb, 0xb5, 0xf3, 0x42, 0xbc, 0xfe, 0xb0, 0x1c, 0x52, 0xdc, 0xf0, + 0xab, 0xb8, 0xbf, 0x97, 0xf1, 0x65, 0x22, 0xa4, 0x78, 0xe0, 0x44, 0x6c, + 0x12, 0xb2, 0x98, 0x75, 0x89, 0xef, 0x5f, 0xa5, 0x38, 0xff, 0x92, 0xd0, + 0xcf, 0x22, 0xa6, 0xe0, 0x05, 0x39, 0xe8, 0x6e, 0x74, 0x17, 0xc4, 0xf8, + 0xbf, 0x59, 0xad, 0x09, 0xad, 0x90, 0x49, 0x37, 0xd4, 0x9c, 0x2e, 0x1b, + 0x19, 0x18, 0x0d, 0xa6, 0x56, 0x9e, 0x70, 0xa2, 0xcd, 0x3b, 0xcb, 0x90, + 0xf1, 0x32, 0xf4, 0x7f, 0x39, 0x16, 0x18, 0x51, 0x6c, 0xda, 0x57, 0x24, + 0xdd, 0x41, 0x3f, 0x9f, 0xfa, 0xe4, 0x01, 0xb9, 0x69, 0x6f, 0x96, 0x9b, + 0x5b, 0x88, 0xc3, 0xec, 0x47, 0x9b, 0xba, 0x64, 0x10, 0x7d, 0x49, 0xf4, + 0x35, 0x2b, 0x3f, 0x6a, 0x7c, 0x06, 0x9d, 0x75, 0xd3, 0xa6, 0xae, 0x5a, + 0xcf, 0x5f, 0xbc, 0xeb, 0x22, 0x68, 0x42, 0x6c, 0xc7, 0x56, 0xb4, 0xa9, + 0xe3, 0xec, 0x86, 0xfe, 0x2e, 0xb4, 0xef, 0xc3, 0x1c, 0x4d, 0xfa, 0x7e, + 0x96, 0xb3, 0xcd, 0xd4, 0x39, 0xeb, 0xc6, 0xac, 0x6e, 0x68, 0xff, 0xb1, + 0xdd, 0xe0, 0x13, 0x3e, 0x25, 0xbd, 0x73, 0x29, 0xd9, 0xd5, 0x59, 0xdf, + 0xfe, 0x77, 0x43, 0xbb, 0x4d, 0x56, 0xb6, 0x93, 0x0c, 0x4f, 0x75, 0xd4, + 0xf7, 0xfb, 0xfc, 0xe4, 0xb7, 0x3b, 0xf1, 0xbe, 0x09, 0x18, 0xbc, 0xa4, + 0xc6, 0x52, 0x37, 0xa3, 0x5c, 0xeb, 0x83, 0x86, 0x67, 0x78, 0xcd, 0x67, + 0xf8, 0x2c, 0xf3, 0x7a, 0x9f, 0xb1, 0x1f, 0xcf, 0x30, 0x27, 0xc0, 0xbc, + 0x06, 0x79, 0x76, 0xb9, 0x38, 0x8b, 0x63, 0x3e, 0x9f, 0x6f, 0xc8, 0x54, + 0x79, 0xcf, 0xd7, 0x2b, 0xb1, 0x2a, 0x56, 0x6d, 0x67, 0xc1, 0xcf, 0x09, + 0x93, 0x76, 0x5a, 0x93, 0x8a, 0xdd, 0x00, 0x9d, 0x0f, 0x80, 0xce, 0x0f, + 0x05, 0x19, 0x17, 0xb6, 0x78, 0xb4, 0x76, 0x64, 0xa4, 0xfc, 0x5b, 0xc8, + 0x38, 0x79, 0x14, 0x3e, 0x45, 0xd9, 0xf2, 0xf0, 0x19, 0x03, 0xb0, 0x69, + 0xae, 0x04, 0x35, 0xef, 0x80, 0xf8, 0x7e, 0xf6, 0xba, 0x8c, 0x4c, 0x31, + 0x27, 0x40, 0x7e, 0x66, 0x5c, 0x9f, 0xc2, 0xbd, 0x5b, 0x18, 0xeb, 0x42, + 0x86, 0xc7, 0xc0, 0xaf, 0x21, 0x71, 0xa6, 0xb7, 0x4a, 0x6e, 0x7c, 0x4c, + 0x7d, 0x80, 0x1e, 0xd8, 0xa8, 0xe3, 0xee, 0xa8, 0x9c, 0xb8, 0xb2, 0x01, + 0xb2, 0xca, 0xb8, 0x5f, 0x73, 0x1a, 0x95, 0xb0, 0xfa, 0xe6, 0xf4, 0x39, + 0x98, 0x87, 0x33, 0x35, 0x66, 0x23, 0xb7, 0x93, 0x31, 0x69, 0x1b, 0x95, + 0x99, 0x0b, 0xb6, 0xe2, 0x5d, 0x52, 0x72, 0xa7, 0x42, 0xda, 0x65, 0xf7, + 0xc6, 0xa1, 0xab, 0xe8, 0xcb, 0x9f, 0x8c, 0x98, 0xb3, 0x7c, 0x74, 0x2d, + 0x63, 0xe2, 0xe4, 0x74, 0xed, 0x1c, 0x8a, 0x91, 0xc1, 0xbd, 0xd7, 0xda, + 0x8d, 0xcc, 0x30, 0x3e, 0xfe, 0xa0, 0x92, 0x8a, 0x72, 0x4d, 0x8e, 0x65, + 0xed, 0x96, 0x3c, 0xc2, 0xbd, 0x7d, 0xea, 0xf1, 0xf2, 0xcf, 0x30, 0x5f, + 0x5c, 0x7a, 0x5e, 0x1f, 0xd3, 0xb8, 0xfe, 0x78, 0x5d, 0x0c, 0x6b, 0xf2, + 0x05, 0x26, 0x8e, 0xbd, 0x2e, 0x93, 0xf3, 0xa4, 0x0f, 0x6d, 0x7c, 0x40, + 0x5e, 0x73, 0x7a, 0xed, 0x27, 0xb5, 0xd6, 0x98, 0x48, 0xb1, 0x3e, 0xd3, + 0xe2, 0x24, 0xed, 0x59, 0x09, 0x0d, 0x7e, 0x15, 0xd7, 0x8c, 0x6b, 0xf3, + 0x6e, 0xaf, 0xfb, 0xa4, 0xf8, 0x38, 0x90, 0x8d, 0xa9, 0x15, 0x81, 0xdb, + 0x95, 0xeb, 0x7b, 0x39, 0xc6, 0xe0, 0x40, 0x24, 0x40, 0x5a, 0xbd, 0xb7, + 0x9e, 0xf8, 0x99, 0xfa, 0xfc, 0xdf, 0x83, 0x4f, 0xef, 0x19, 0x48, 0x9c, + 0x62, 0x0c, 0x1b, 0x76, 0xbe, 0xb5, 0xd6, 0xbc, 0x6b, 0x2e, 0xb7, 0x5a, + 0xb4, 0x7e, 0x76, 0xe4, 0x23, 0x87, 0x78, 0x88, 0x44, 0x6c, 0x85, 0xc5, + 0x3c, 0x38, 0x75, 0x1c, 0x6b, 0x2a, 0xcc, 0xb9, 0x11, 0xc7, 0xdf, 0x2c, + 0x97, 0xfb, 0x2c, 0x79, 0x30, 0x94, 0x8a, 0x5b, 0xb2, 0x29, 0x7e, 0x56, + 0xb0, 0x26, 0xeb, 0x2b, 0xf3, 0x89, 0x1c, 0xc7, 0x87, 0xa6, 0x39, 0x5f, + 0x5c, 0xe3, 0x95, 0xe4, 0xa6, 0x4a, 0xe5, 0x19, 0x57, 0x02, 0xc9, 0x7b, + 0x3f, 0xac, 0xb0, 0x16, 0x6e, 0xbd, 0xfe, 0x45, 0x38, 0x05, 0xea, 0x8a, + 0x55, 0x93, 0x06, 0x73, 0x78, 0xe2, 0x48, 0xcf, 0x3c, 0xdb, 0xdf, 0x7d, + 0xc4, 0xb4, 0x4f, 0xa1, 0xdd, 0xe4, 0x61, 0x9d, 0xa6, 0x8e, 0xf4, 0x14, + 0x9f, 0x5a, 0x6b, 0xe2, 0xef, 0x45, 0xc5, 0x7f, 0xbd, 0x5d, 0x17, 0xd3, + 0xa4, 0x02, 0xe3, 0x85, 0xb1, 0xc0, 0x58, 0xc1, 0xea, 0x6b, 0x06, 0xad, + 0xe6, 0x5c, 0xe6, 0x6a, 0xfc, 0x9c, 0x15, 0xf3, 0xfd, 0x22, 0xdf, 0x57, + 0x8c, 0x14, 0x6b, 0x8a, 0x96, 0xfa, 0x42, 0x07, 0xe6, 0x98, 0xe3, 0x8f, + 0xa8, 0x3e, 0x38, 0x38, 0xdf, 0x26, 0x79, 0x7b, 0x8d, 0xe4, 0x55, 0xc6, + 0xa3, 0xaa, 0x03, 0x2c, 0xe7, 0x5e, 0xf4, 0x71, 0xdf, 0x4f, 0x28, 0x2e, + 0xe2, 0xcd, 0x42, 0x17, 0xda, 0xcc, 0x35, 0x6f, 0x6f, 0xe8, 0xaf, 0xad, + 0xcb, 0x26, 0x6c, 0xcb, 0x6a, 0xac, 0xc9, 0xb2, 0xaf, 0xb1, 0x16, 0x7b, + 0x52, 0xae, 0x93, 0x6f, 0xca, 0x7e, 0xce, 0xdd, 0xf5, 0x72, 0xee, 0xdf, + 0xee, 0x32, 0x18, 0x61, 0xc9, 0x84, 0x86, 0x9a, 0xfb, 0x8e, 0x4f, 0x05, + 0x6f, 0x2d, 0xe5, 0x4f, 0xd1, 0x9e, 0xaf, 0xd6, 0xca, 0x71, 0xef, 0x39, + 0x62, 0xc5, 0xe1, 0x57, 0xe4, 0xbc, 0xef, 0x0e, 0x78, 0xbf, 0xfa, 0xfc, + 0xff, 0xd8, 0x53, 0x8b, 0xd6, 0xd9, 0xad, 0xba, 0x3a, 0xfb, 0xe3, 0x78, + 0x96, 0x35, 0xf6, 0x5c, 0xa5, 0x09, 0xbc, 0xdb, 0x44, 0x9c, 0x48, 0x75, + 0x3c, 0x75, 0xbc, 0xea, 0x72, 0x9d, 0x6b, 0xa7, 0x37, 0x57, 0x10, 0x7a, + 0x7e, 0x62, 0xca, 0x1f, 0x73, 0x4c, 0x56, 0xf4, 0x27, 0x62, 0x41, 0x8b, + 0x63, 0x8c, 0xbe, 0x4f, 0xbb, 0xc7, 0xa0, 0xc7, 0xa9, 0xf3, 0xf9, 0xde, + 0x0e, 0x7c, 0x3d, 0xea, 0x02, 0xea, 0x73, 0xb5, 0x01, 0xf1, 0x3c, 0x74, + 0xfd, 0x48, 0x59, 0x73, 0xf9, 0xb1, 0x87, 0x83, 0x89, 0x99, 0xac, 0xea, + 0x06, 0xf8, 0x7b, 0xe5, 0x6b, 0xcc, 0x07, 0x9d, 0x92, 0x40, 0x6d, 0x9d, + 0x86, 0xb1, 0x19, 0x6b, 0x1a, 0xad, 0xd0, 0x0d, 0x22, 0x57, 0xc1, 0x1b, + 0x6f, 0xcc, 0x91, 0x5f, 0x83, 0x1d, 0x26, 0xbe, 0x5a, 0xd8, 0x6e, 0x49, + 0x87, 0xd6, 0x3e, 0xf3, 0x4e, 0x84, 0xfe, 0xc9, 0x70, 0xb2, 0x1f, 0x7e, + 0xb6, 0x62, 0x0f, 0x98, 0xaf, 0x9c, 0x40, 0x3c, 0x56, 0x9b, 0x63, 0x81, + 0x7c, 0x8d, 0xb3, 0x3f, 0x0b, 0xbf, 0x72, 0xa9, 0xee, 0x91, 0x2f, 0x9e, + 0xd0, 0xdc, 0x66, 0x69, 0xae, 0x55, 0x75, 0x6c, 0xa9, 0xf8, 0x30, 0xce, + 0x45, 0x36, 0x5b, 0x43, 0x79, 0xaf, 0x3f, 0x2c, 0xc5, 0x22, 0xdb, 0xd2, + 0xdd, 0xa4, 0xe7, 0xee, 0xd7, 0x76, 0x6c, 0x99, 0x85, 0xaf, 0x58, 0x9c, + 0x77, 0xf0, 0xbf, 0x05, 0xff, 0x7d, 0xf8, 0xdf, 0x25, 0xe9, 0x69, 0xfa, + 0xaf, 0xac, 0xe5, 0xb4, 0x36, 0xac, 0x1f, 0xf6, 0x70, 0xe0, 0xf4, 0x6b, + 0x4d, 0x9c, 0x93, 0x2f, 0x36, 0xca, 0x09, 0xf3, 0xa4, 0xbe, 0x8e, 0x60, + 0xbe, 0xd4, 0xaf, 0xf5, 0xd5, 0xd6, 0xb0, 0x2c, 0xaf, 0xee, 0x45, 0x9e, + 0x6e, 0x91, 0x83, 0x45, 0xbf, 0x76, 0x15, 0x93, 0x43, 0xd5, 0xda, 0x95, + 0x64, 0x82, 0x43, 0xb7, 0x1f, 0xcb, 0x4e, 0x29, 0x9e, 0xc0, 0xb2, 0x86, + 0xae, 0x3f, 0x36, 0x39, 0xff, 0xce, 0x63, 0x4b, 0x98, 0x70, 0xdc, 0x9b, + 0x5f, 0x0e, 0x33, 0x44, 0x2c, 0x1d, 0xbf, 0x93, 0x53, 0xdf, 0x0d, 0xfb, + 0xf6, 0x63, 0x1e, 0xe2, 0xec, 0xe2, 0xf6, 0x12, 0x7e, 0xd9, 0x8f, 0x47, + 0x89, 0x23, 0xe5, 0x73, 0xb5, 0xd8, 0x8f, 0x10, 0xce, 0x5f, 0x02, 0x96, + 0x93, 0xc3, 0x3e, 0x2e, 0x76, 0x19, 0x3f, 0x90, 0x38, 0xd3, 0x44, 0x0d, + 0xf6, 0xc8, 0xc7, 0x9a, 0x5e, 0xc4, 0x5c, 0x19, 0xf9, 0x7d, 0xf9, 0x71, + 0xf9, 0x75, 0x79, 0x0c, 0xf2, 0x3d, 0x89, 0x39, 0xf7, 0xcb, 0xaf, 0xca, + 0x7b, 0xe5, 0x5a, 0x79, 0x5c, 0xde, 0x2a, 0xef, 0x42, 0x4c, 0x35, 0x4a, + 0xac, 0xa7, 0x87, 0x95, 0x1e, 0x96, 0x89, 0x73, 0x8a, 0x01, 0xbc, 0x45, + 0xbf, 0xe7, 0x88, 0xfa, 0xd9, 0x01, 0xf2, 0xf4, 0x6f, 0x18, 0xcf, 0x13, + 0x9b, 0x59, 0x2c, 0xfb, 0x18, 0x8e, 0x43, 0xdd, 0x58, 0xdb, 0xe6, 0x37, + 0x29, 0x23, 0xe7, 0x22, 0x81, 0xd1, 0x73, 0xa1, 0xc0, 0x43, 0xfa, 0x7d, + 0x0b, 0xeb, 0x9d, 0x15, 0x39, 0xe1, 0x3a, 0xe4, 0xcd, 0xc1, 0x11, 0xc8, + 0xc2, 0x28, 0x54, 0xfd, 0x23, 0xce, 0x1a, 0x01, 0x49, 0x53, 0x1f, 0xc3, + 0xcf, 0x4c, 0x9e, 0x76, 0x25, 0x5b, 0x98, 0x0d, 0x18, 0x3c, 0x9a, 0x8d, + 0x76, 0x1f, 0xda, 0xbf, 0xf4, 0xda, 0x3b, 0x24, 0x7b, 0x41, 0x52, 0xef, + 0xab, 0x3f, 0xfc, 0x73, 0xaf, 0x6f, 0x10, 0x7d, 0xe0, 0xcc, 0x57, 0xd8, + 0xf7, 0x8a, 0xd7, 0xc7, 0x33, 0x61, 0xad, 0x3e, 0xae, 0x7c, 0x95, 0xb5, + 0xc7, 0x85, 0xdf, 0x2f, 0x18, 0x4c, 0xe8, 0xfb, 0x5d, 0x46, 0xb7, 0x11, + 0x13, 0xf8, 0xaf, 0x2e, 0xc6, 0x60, 0x45, 0xc8, 0xd7, 0x7a, 0xe8, 0xc4, + 0xbf, 0x6f, 0x5e, 0x6a, 0x5b, 0x43, 0x9f, 0xd4, 0x60, 0xb4, 0x3f, 0x91, + 0x9e, 0xf9, 0xdb, 0x1e, 0x9e, 0xf7, 0x30, 0xde, 0x0d, 0x67, 0x55, 0x20, + 0x6e, 0x3c, 0x0e, 0xd9, 0x6e, 0x95, 0x35, 0x67, 0x48, 0xaf, 0x5e, 0xe8, + 0xea, 0x14, 0xe4, 0xd6, 0x95, 0xb9, 0x72, 0x28, 0x30, 0x52, 0x48, 0x89, + 0xc1, 0x53, 0x5b, 0x92, 0x89, 0xa6, 0xe4, 0xe4, 0x40, 0x62, 0x0b, 0xf3, + 0x90, 0xd9, 0x7e, 0x57, 0x2e, 0x95, 0x69, 0x8f, 0x73, 0x72, 0x79, 0x20, + 0xe1, 0x16, 0x85, 0xb8, 0x18, 0x57, 0x2e, 0x43, 0x36, 0xff, 0x70, 0x6e, + 0x97, 0x1c, 0x2a, 0xa8, 0x1f, 0xdc, 0x1b, 0x96, 0x97, 0xe5, 0xd2, 0xc0, + 0xcb, 0xb7, 0x2e, 0xb9, 0x93, 0x38, 0x53, 0xf2, 0xe1, 0x81, 0x6e, 0xb3, + 0x6f, 0xc5, 0x21, 0x09, 0xf3, 0x21, 0x5a, 0x53, 0x73, 0x56, 0x48, 0x7a, + 0x5f, 0xc4, 0x8b, 0xcb, 0xe1, 0x73, 0x07, 0xee, 0x33, 0xf5, 0x94, 0x80, + 0xbf, 0xcf, 0x30, 0xfc, 0x18, 0x3e, 0xe7, 0xd3, 0xc6, 0x9f, 0xa7, 0x2b, + 0x90, 0xbe, 0xd0, 0x26, 0xa1, 0x57, 0xbe, 0x0c, 0xba, 0x86, 0xe4, 0x40, + 0x7f, 0xa5, 0xf2, 0x0d, 0x37, 0x14, 0x9f, 0x44, 0x8c, 0x82, 0xfd, 0xcb, + 0xea, 0xd3, 0xed, 0xa0, 0x49, 0xb3, 0x44, 0x4f, 0xfb, 0xeb, 0xad, 0xf0, + 0xb0, 0x0c, 0xe7, 0x57, 0x1b, 0x5b, 0xe6, 0x63, 0x1b, 0xfc, 0xf9, 0x0c, + 0xa6, 0xac, 0xc7, 0xea, 0x0f, 0x78, 0xdf, 0x49, 0x78, 0xed, 0x7b, 0x03, + 0x0f, 0x86, 0x3a, 0x24, 0xe4, 0xfc, 0x70, 0x1d, 0xb1, 0x91, 0x0b, 0x05, + 0xbf, 0x1f, 0x7e, 0x62, 0xc8, 0xf7, 0x87, 0x65, 0xdb, 0xd2, 0x59, 0xcb, + 0xb6, 0x9e, 0xf9, 0x6f, 0x7a, 0x73, 0xa6, 0xbc, 0xb1, 0x88, 0x39, 0x62, + 0xab, 0xd4, 0x3e, 0x99, 0xb1, 0x9f, 0xc9, 0xb3, 0xfd, 0x89, 0x57, 0x15, + 0x27, 0x5b, 0x7d, 0x86, 0xf7, 0x11, 0x43, 0x96, 0xf5, 0x99, 0xd8, 0x6e, + 0xd0, 0x37, 0x13, 0xbb, 0xc7, 0x9e, 0xb5, 0x82, 0x01, 0xe3, 0x8f, 0x34, + 0xc9, 0x0f, 0xa2, 0xb0, 0xdb, 0x88, 0xf1, 0xb2, 0xcc, 0x7f, 0xb9, 0x77, + 0x3c, 0x3f, 0x85, 0x7d, 0x89, 0x53, 0x49, 0x6b, 0x02, 0xfb, 0xe3, 0x19, + 0x10, 0x03, 0x6a, 0x81, 0x4e, 0x5d, 0x78, 0x3f, 0xc4, 0x4f, 0xfd, 0xfe, + 0xfb, 0xaf, 0x86, 0x0e, 0xe3, 0xfe, 0x0d, 0x2e, 0x4c, 0x2c, 0xe6, 0x42, + 0x86, 0x3d, 0x0c, 0x6c, 0xad, 0xdc, 0xfa, 0xd8, 0x58, 0x1f, 0x4f, 0x47, + 0x8c, 0x52, 0x0c, 0x7e, 0x20, 0x65, 0x82, 0xbc, 0xd9, 0x89, 0xfe, 0x95, + 0xb7, 0x53, 0xfa, 0xea, 0x7e, 0xdf, 0x87, 0x55, 0x6c, 0xf7, 0x64, 0x61, + 0xaf, 0xc1, 0xe6, 0x59, 0x8b, 0x92, 0xea, 0x4e, 0xda, 0x27, 0xb0, 0xdf, + 0x74, 0x28, 0x51, 0xcc, 0x49, 0x4c, 0x66, 0xa1, 0x2f, 0xde, 0x80, 0xec, + 0x5f, 0x2b, 0xc7, 0x03, 0x69, 0xec, 0xe9, 0x60, 0x61, 0x48, 0x26, 0x2f, + 0xe8, 0x37, 0x5f, 0xd0, 0xfb, 0x43, 0x52, 0x2a, 0x24, 0xb6, 0xcc, 0x82, + 0xff, 0x66, 0x0b, 0xc4, 0x17, 0xf5, 0xc6, 0x47, 0x31, 0xe3, 0x42, 0x61, + 0x23, 0xec, 0x83, 0xa4, 0x2e, 0xc1, 0xff, 0xb9, 0x54, 0xde, 0x02, 0x3e, + 0xc3, 0xfd, 0xb2, 0x83, 0x5f, 0xe8, 0xcc, 0xf2, 0x00, 0xe4, 0x9c, 0x7b, + 0xb1, 0x65, 0x6e, 0x33, 0xce, 0x8e, 0x38, 0x22, 0xc5, 0x8f, 0xff, 0x07, + 0xe7, 0xeb, 0xbf, 0xf7, 0x76, 0xb5, 0xd3, 0xb3, 0xba, 0x2f, 0xd8, 0x65, + 0xc4, 0x00, 0xd9, 0x7e, 0x63, 0xb7, 0xd3, 0x91, 0x76, 0x49, 0xdf, 0x43, + 0x3b, 0xde, 0xa1, 0x31, 0xa2, 0xf2, 0x62, 0x84, 0xf7, 0xdf, 0x59, 0x67, + 0xe8, 0x17, 0x6e, 0x68, 0xbf, 0x8d, 0xdf, 0x36, 0xe9, 0x74, 0xf8, 0x6b, + 0xe3, 0xf7, 0xc6, 0x3a, 0xd6, 0x77, 0x3b, 0x9d, 0x24, 0xd6, 0xfa, 0x9d, + 0x97, 0x2f, 0xc0, 0xf5, 0x2c, 0x9f, 0x59, 0xeb, 0xad, 0xcb, 0x79, 0xdb, + 0x30, 0x4f, 0xab, 0xb7, 0x56, 0x9b, 0xe6, 0x27, 0xcd, 0x5a, 0x88, 0x71, + 0x0b, 0xef, 0xad, 0xd3, 0xef, 0x8c, 0x61, 0x2f, 0xea, 0xdb, 0x7f, 0x5d, + 0x47, 0xdc, 0x5c, 0xa7, 0xd3, 0xa6, 0x18, 0xcf, 0x9b, 0x1d, 0x1d, 0xb8, + 0xe6, 0x9a, 0x1c, 0x63, 0xf2, 0xe1, 0xa5, 0x32, 0xe7, 0x67, 0x3b, 0x25, + 0x47, 0x35, 0x9f, 0x61, 0xb0, 0x7c, 0xa5, 0xc2, 0xfd, 0x32, 0x79, 0x4e, + 0xf1, 0x75, 0x33, 0x79, 0x8b, 0xdf, 0xbd, 0xf0, 0x3b, 0x39, 0xfa, 0x12, + 0x63, 0x32, 0x81, 0xf3, 0xbb, 0x0c, 0x9f, 0x6a, 0xc1, 0x7c, 0x13, 0x8b, + 0xbf, 0xfd, 0x38, 0x97, 0x10, 0x64, 0x8c, 0x32, 0x4a, 0x99, 0xc2, 0xf9, + 0x8d, 0xdb, 0xf2, 0xee, 0x00, 0xe5, 0x79, 0x40, 0xae, 0x54, 0xe5, 0x39, + 0x07, 0x79, 0xa6, 0x2c, 0xe7, 0x20, 0xd3, 0x86, 0xaf, 0xf7, 0xf1, 0x1b, + 0x6b, 0x84, 0xeb, 0x25, 0xf5, 0x21, 0x2e, 0x82, 0xaf, 0x6d, 0x13, 0x97, + 0x2b, 0x2e, 0xfe, 0x30, 0xf4, 0x5a, 0x93, 0xf7, 0x1d, 0x00, 0xae, 0xaf, + 0xbc, 0x28, 0xe9, 0x0b, 0x2d, 0xd8, 0x77, 0xbc, 0x9b, 0x67, 0x96, 0xbd, + 0xc2, 0x7f, 0x9f, 0x17, 0x89, 0x37, 0xa5, 0x3f, 0xcb, 0x6b, 0xc6, 0x79, + 0xeb, 0x31, 0x66, 0x10, 0x74, 0x6e, 0xc1, 0xfc, 0xdc, 0xe3, 0x72, 0xe3, + 0x78, 0x3f, 0x54, 0x83, 0x4f, 0xf5, 0xe9, 0xbd, 0x4a, 0xd7, 0xcc, 0xea, + 0x37, 0x5a, 0x46, 0x06, 0x27, 0x0a, 0xe4, 0xfb, 0x18, 0xf8, 0x96, 0x3e, + 0x31, 0xf9, 0x25, 0xa5, 0xe7, 0x50, 0x2a, 0x90, 0x7f, 0x43, 0x9a, 0xc3, + 0xc8, 0xc2, 0xb6, 0xec, 0xd1, 0xf1, 0xb1, 0x25, 0xf9, 0xee, 0x0e, 0x68, + 0xdc, 0x9d, 0x2d, 0xac, 0x94, 0x1e, 0xd5, 0x41, 0xdd, 0x1e, 0x6f, 0xc3, + 0x5e, 0x28, 0x96, 0x7b, 0xbf, 0x1c, 0x29, 0x0f, 0x82, 0x0e, 0x31, 0x79, + 0x06, 0x7e, 0xf3, 0x73, 0xe5, 0xbb, 0x64, 0x31, 0x82, 0x7d, 0x55, 0x65, + 0x6c, 0x58, 0x9e, 0x9f, 0x8d, 0x7b, 0xd7, 0x09, 0x77, 0xd1, 0xda, 0x8e, + 0x3d, 0x50, 0x9e, 0x28, 0x57, 0x1c, 0x17, 0x44, 0x2c, 0xc2, 0x79, 0x8f, + 0x18, 0xdd, 0x86, 0x79, 0x8b, 0x11, 0xca, 0x2f, 0xf7, 0x16, 0xf2, 0x64, + 0x96, 0x71, 0x15, 0xdf, 0xd9, 0xd8, 0xa4, 0x4c, 0xdd, 0x59, 0x24, 0x14, + 0x07, 0xba, 0x74, 0x06, 0xfe, 0x3c, 0xbe, 0x5c, 0xfa, 0xdf, 0x51, 0x50, + 0x8f, 0xc2, 0x56, 0x16, 0x60, 0x2b, 0x0b, 0xb0, 0x91, 0x90, 0x85, 0x6b, + 0x05, 0xd8, 0xc8, 0x02, 0x6c, 0x24, 0xf4, 0xd9, 0x9b, 0x88, 0xed, 0xde, + 0x00, 0x0f, 0x19, 0x5f, 0xfb, 0x30, 0x7d, 0x6d, 0xfc, 0xfd, 0x17, 0xea, + 0x52, 0x61, 0x78, 0xd0, 0x71, 0x00, 0x00, 0x00 }; static const u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 }; static const u32 bnx2_RXP_b06FwRodata[(0x24/4) + 1] = { - 0x08004590, 0x08004590, 0x08004508, 0x08004540, 0x08004574, 0x08004598, - 0x08004598, 0x08004598, 0x08004478, 0x00000000 }; + 0x0800458c, 0x0800458c, 0x08004504, 0x0800453c, 0x08004570, 0x08004594, + 0x08004594, 0x08004594, 0x08004474, 0x00000000 }; static struct fw_info bnx2_rxp_fw_06 = { - /* Firmware version: 4.1.1 */ + /* Firmware version: 4.4.2 */ .ver_major = 0x4, - .ver_minor = 0x1, - .ver_fix = 0x1, + .ver_minor = 0x4, + .ver_fix = 0x2, .start_addr = 0x080031d0, .text_addr = 0x08000000, - .text_len = 0x71d0, + .text_len = 0x71cc, .text_index = 0x0, .gz_text = bnx2_RXP_b06FwText, .gz_text_len = sizeof(bnx2_RXP_b06FwText), @@ -2973,7 +2974,7 @@ static struct fw_info bnx2_rxp_fw_06 = { .bss_len = 0x44c, .bss_index = 0x0, - .rodata_addr = 0x080071d0, + .rodata_addr = 0x080071cc, .rodata_len = 0x24, .rodata_index = 0x0, .rodata = bnx2_RXP_b06FwRodata, @@ -2996,687 +2997,639 @@ static const struct cpu_reg cpu_reg_rxp = { }; static u8 bnx2_rv2p_proc1[] = { - /* Date: 12/07/2007 15:02 */ - 0xd5, 0x56, 0x41, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xdd, 0x6c, 0xbb, 0xdb, - 0x64, 0xb3, 0x59, 0xaa, 0xd6, 0x50, 0x53, 0x93, 0x06, 0x2f, 0xad, 0x29, - 0x6d, 0xaa, 0x82, 0x42, 0xa1, 0x92, 0x4b, 0xc1, 0xf6, 0x20, 0xf5, 0x22, - 0x22, 0xd8, 0x46, 0xd1, 0x5f, 0x21, 0x06, 0xdb, 0xd4, 0x73, 0x05, 0x0b, - 0xf5, 0xa0, 0x3d, 0x59, 0x11, 0xc1, 0x04, 0x14, 0x44, 0x04, 0x41, 0x45, - 0x04, 0x3d, 0x78, 0xa8, 0x60, 0x2f, 0xad, 0x22, 0x56, 0x3c, 0x78, 0xd4, - 0x93, 0x26, 0xbe, 0x37, 0x33, 0xaf, 0xdd, 0xdd, 0x66, 0x9b, 0x2a, 0x82, - 0x18, 0x68, 0x3f, 0xde, 0xec, 0xbc, 0x37, 0x33, 0xdf, 0xcc, 0x9b, 0x79, - 0x2e, 0x00, 0xe8, 0x50, 0xaa, 0xa6, 0x05, 0x82, 0xa5, 0x69, 0x96, 0x00, - 0x0d, 0xe0, 0xae, 0x8d, 0x58, 0xea, 0x77, 0x05, 0xda, 0xda, 0x70, 0x46, - 0x62, 0x04, 0x86, 0xbb, 0x25, 0xee, 0x87, 0x27, 0x99, 0xa4, 0xc0, 0x9f, - 0x75, 0x28, 0xc9, 0xf5, 0xee, 0xca, 0xc3, 0x6a, 0x0c, 0xcf, 0x59, 0xed, - 0x07, 0xfc, 0xbd, 0x8b, 0x10, 0x1e, 0xce, 0x59, 0x88, 0x25, 0x46, 0xe8, - 0x73, 0x11, 0x96, 0x66, 0x2d, 0x34, 0x57, 0xea, 0xb3, 0x70, 0x1f, 0xe8, - 0x24, 0x5f, 0x99, 0x4d, 0x88, 0xff, 0x29, 0x78, 0x5f, 0x90, 0x6b, 0x2b, - 0x3a, 0x8d, 0x7a, 0x15, 0xde, 0x2f, 0xfe, 0x50, 0xff, 0xb8, 0xd8, 0x07, - 0xfc, 0x53, 0xfb, 0x5c, 0x3c, 0xa7, 0x98, 0x93, 0x7e, 0xb5, 0x0b, 0x83, - 0xca, 0x1f, 0x9b, 0xe2, 0x4b, 0x93, 0xb6, 0x89, 0xdf, 0xd7, 0x84, 0xdf, - 0xca, 0x6e, 0x33, 0x7b, 0x41, 0x7f, 0x83, 0x76, 0xe5, 0x79, 0x86, 0xb0, - 0xe7, 0xb7, 0x03, 0x20, 0xe5, 0xcb, 0xf5, 0x75, 0x79, 0x8f, 0xff, 0xfb, - 0x6a, 0xaf, 0x3c, 0xaf, 0x05, 0xa0, 0x57, 0xea, 0x2d, 0xb1, 0x3f, 0x83, - 0xb0, 0x4f, 0x4f, 0xe2, 0x77, 0x03, 0xf7, 0xef, 0x11, 0xe7, 0x4a, 0xec, - 0x62, 0xec, 0x66, 0x1c, 0x67, 0xbc, 0xca, 0xb8, 0x8b, 0x71, 0x27, 0xe3, - 0x0e, 0xc6, 0x76, 0xc6, 0x97, 0x8c, 0x2e, 0x63, 0x82, 0xd1, 0x61, 0x7c, - 0xce, 0x68, 0x33, 0xc6, 0x18, 0x5f, 0x30, 0xbe, 0x62, 0xb4, 0x18, 0x6f, - 0x30, 0x7e, 0x61, 0xfc, 0xaa, 0xfc, 0xd0, 0x08, 0x1f, 0xf1, 0xfa, 0x10, - 0xaf, 0x8f, 0x30, 0x02, 0xf3, 0xa4, 0x05, 0x78, 0xba, 0xcf, 0x75, 0x24, - 0x79, 0xe6, 0xef, 0x3d, 0x4a, 0x8f, 0xf3, 0x84, 0x3c, 0xdd, 0x63, 0xbd, - 0xf6, 0xca, 0x42, 0xa0, 0xde, 0x32, 0x5b, 0xd6, 0x59, 0xaa, 0x41, 0xde, - 0x12, 0x18, 0xcf, 0xc4, 0x48, 0x02, 0xed, 0x38, 0xad, 0x24, 0x57, 0x6e, - 0x9d, 0x4c, 0x10, 0x9e, 0x8b, 0x12, 0x7e, 0x62, 0x3c, 0x1f, 0x23, 0x9c, - 0x8c, 0x2b, 0x9e, 0xd5, 0x39, 0xca, 0x9f, 0x66, 0x7e, 0x84, 0xd9, 0x53, - 0x7e, 0x35, 0xb3, 0x4b, 0x58, 0xd4, 0xfd, 0xf1, 0x5f, 0x1f, 0x20, 0x34, - 0xf2, 0x44, 0xea, 0x9c, 0xdd, 0x26, 0xa0, 0x5e, 0x9f, 0xb7, 0x0d, 0xb9, - 0x3e, 0x38, 0xff, 0x1a, 0xef, 0xc7, 0xe0, 0x5c, 0x95, 0xfd, 0x4b, 0x28, - 0x9e, 0xe9, 0xde, 0x64, 0x81, 0xd6, 0xe3, 0xc8, 0xbb, 0xa8, 0xb0, 0x1e, - 0xee, 0x03, 0x59, 0x7f, 0xbe, 0xa8, 0x6e, 0x23, 0x9c, 0x8f, 0x8b, 0x9c, - 0x8f, 0xae, 0x90, 0x7c, 0x84, 0xdd, 0xa3, 0xcd, 0xf7, 0xf7, 0x4c, 0x26, - 0xc8, 0x5b, 0xd8, 0x7d, 0x53, 0x7c, 0x93, 0xf4, 0x77, 0x79, 0xbc, 0xc0, - 0x3c, 0x16, 0x89, 0xc7, 0xe4, 0xe7, 0x86, 0x3c, 0x65, 0x3c, 0x3c, 0xc9, - 0x38, 0xf7, 0x86, 0xe4, 0x39, 0x2c, 0xbe, 0xdc, 0x1f, 0xe7, 0x39, 0xe0, - 0x1f, 0x9c, 0xc5, 0xfe, 0xe4, 0x42, 0x71, 0x44, 0xf9, 0xeb, 0xe7, 0xb9, - 0x93, 0xf2, 0x0d, 0xd3, 0x79, 0x29, 0xaf, 0x03, 0x3c, 0xd5, 0x71, 0x6d, - 0x14, 0x34, 0x09, 0x56, 0x31, 0x4f, 0xfb, 0x1d, 0x5d, 0xe7, 0xf5, 0x76, - 0xeb, 0x42, 0xe5, 0x5d, 0x62, 0x2b, 0x14, 0x26, 0x39, 0xce, 0x2c, 0xd9, - 0xa3, 0x3a, 0x30, 0xb8, 0x0e, 0x86, 0xb8, 0x7f, 0x05, 0xf9, 0xb0, 0x2a, - 0x0b, 0xb3, 0xde, 0x7b, 0x9d, 0x84, 0x62, 0x9e, 0xea, 0x6a, 0x73, 0x5e, - 0xd5, 0xdc, 0x51, 0x7d, 0x09, 0xc5, 0x95, 0x52, 0xc4, 0x17, 0xef, 0x51, - 0xc8, 0x79, 0x79, 0xd6, 0x1a, 0xd4, 0x47, 0x33, 0x3b, 0xbe, 0xf3, 0x1c, - 0xc8, 0x35, 0xea, 0x37, 0x26, 0xc7, 0xd5, 0xcd, 0xf5, 0xdd, 0xb1, 0xa9, - 0xbe, 0xd5, 0x7c, 0xfb, 0x7b, 0x75, 0xce, 0xf1, 0x9b, 0xa8, 0x97, 0x5a, - 0x79, 0xe0, 0x9d, 0x67, 0x51, 0xcf, 0x3c, 0xa3, 0x6d, 0xa6, 0xf2, 0x3b, - 0xed, 0x9d, 0x43, 0xb1, 0x90, 0x3c, 0x78, 0xe7, 0x57, 0x30, 0x5e, 0x7f, - 0x3d, 0x52, 0x5e, 0xa3, 0x1c, 0xbf, 0xd6, 0xa4, 0x2f, 0xb7, 0xb1, 0xde, - 0x8f, 0x5a, 0xb8, 0x1e, 0x9d, 0x5b, 0xe8, 0xf1, 0xf6, 0xf1, 0xef, 0x35, - 0x9a, 0x07, 0xdf, 0x6a, 0x8a, 0xdf, 0xc7, 0x21, 0xfc, 0x0e, 0xfd, 0x53, - 0x7e, 0x21, 0xc0, 0xef, 0x6a, 0x6d, 0x7b, 0xfc, 0x02, 0xc7, 0x0f, 0x21, - 0xfc, 0xb6, 0x32, 0x0f, 0x6f, 0xb7, 0xe0, 0x4d, 0xea, 0xc5, 0x58, 0xef, - 0x8d, 0x47, 0x0f, 0xfd, 0x1e, 0xa2, 0x7b, 0x65, 0x16, 0xd7, 0x02, 0xbc, - 0xe5, 0x73, 0xf2, 0x7e, 0x5f, 0x82, 0x2a, 0xc7, 0xbf, 0xec, 0xe3, 0x21, - 0x2e, 0xfc, 0x73, 0xd1, 0xfe, 0xed, 0xaa, 0xe2, 0x8b, 0x3e, 0x67, 0x72, - 0x84, 0x8b, 0xa8, 0xef, 0x7a, 0x78, 0xf3, 0xbe, 0xaf, 0x5c, 0xb8, 0x55, - 0x55, 0xfd, 0x4c, 0xf6, 0x15, 0x13, 0x06, 0x78, 0x4e, 0x4e, 0x70, 0xff, - 0xfa, 0x10, 0xa5, 0x3e, 0x59, 0x1c, 0xc5, 0x3e, 0x03, 0x1d, 0xeb, 0xfd, - 0x8c, 0xd6, 0x9d, 0x71, 0x7a, 0x47, 0x0e, 0x98, 0x36, 0xea, 0x75, 0xc6, - 0x09, 0x3b, 0x62, 0x72, 0x5f, 0x12, 0x3e, 0x8e, 0xa1, 0x7a, 0x6e, 0xa3, - 0x3f, 0x05, 0xfb, 0x12, 0xc7, 0x79, 0x40, 0xca, 0x3b, 0x02, 0xfd, 0x48, - 0xe8, 0xf4, 0x92, 0x7f, 0x37, 0x81, 0xe3, 0x52, 0xfb, 0xd2, 0x92, 0xc7, - 0xc5, 0x9a, 0xea, 0xe3, 0xd9, 0x11, 0xe9, 0x4f, 0x02, 0x1c, 0x93, 0xf2, - 0x48, 0x28, 0xf4, 0x74, 0x53, 0x6e, 0x4b, 0x95, 0x75, 0x5a, 0x97, 0x2f, - 0xe3, 0x31, 0x63, 0x65, 0x25, 0x2f, 0x60, 0x61, 0x8e, 0xdf, 0x79, 0x86, - 0x72, 0xa7, 0x1a, 0x21, 0xb9, 0x39, 0xaa, 0xf8, 0x48, 0x60, 0x7c, 0x73, - 0xc4, 0xc7, 0xe9, 0x6b, 0x84, 0xa7, 0xe0, 0x18, 0x62, 0x74, 0x63, 0x2e, - 0x5b, 0x88, 0x10, 0xf7, 0xf6, 0xdf, 0x16, 0xe1, 0x1e, 0xf6, 0x4d, 0x4f, - 0x7e, 0x82, 0x73, 0xb5, 0x59, 0x9e, 0xbc, 0x73, 0x5d, 0xe6, 0xa9, 0xd1, - 0xfc, 0x8e, 0x73, 0x5d, 0x95, 0x9b, 0xd4, 0x9f, 0xea, 0x83, 0x25, 0xae, - 0xfb, 0x46, 0xef, 0x1a, 0x89, 0x4e, 0xc8, 0xfc, 0x4f, 0xad, 0xfb, 0x95, - 0x0e, 0x7d, 0x77, 0x91, 0xfe, 0xf6, 0xde, 0x5b, 0x6e, 0xc8, 0x1c, 0xfe, - 0x1f, 0xde, 0x55, 0x5b, 0xbd, 0xa7, 0x1c, 0xe6, 0xf9, 0x04, 0xf3, 0x6c, - 0x40, 0x4b, 0x04, 0x89, 0xb1, 0x8d, 0x29, 0x3c, 0x57, 0x2f, 0xd3, 0x58, - 0xb7, 0x5b, 0x66, 0x70, 0xae, 0x3b, 0xf6, 0x0c, 0xe9, 0x19, 0x24, 0x4f, - 0x2a, 0xbc, 0x32, 0x45, 0xef, 0x6c, 0x1d, 0x7e, 0x01, 0x50, 0xb6, 0x82, - 0xa7, 0xd8, 0x0d, 0x00, 0x00, 0x00 }; + /* Date: 05/13/2008 13:50 */ + 0xa5, 0x56, 0x4f, 0x48, 0x14, 0x61, 0x14, 0x7f, 0x3b, 0xfb, 0x67, 0xd6, + 0xdd, 0xd9, 0x9d, 0x25, 0xff, 0x6d, 0x66, 0xb8, 0x49, 0x97, 0xd5, 0x15, + 0xb5, 0x22, 0x3a, 0x18, 0x86, 0x17, 0x21, 0x3b, 0x84, 0x20, 0x45, 0x04, + 0xd9, 0x12, 0xde, 0x82, 0x0e, 0xd1, 0x29, 0x68, 0xd1, 0x34, 0x8a, 0x0a, + 0x16, 0x52, 0x30, 0xa2, 0xa4, 0x43, 0x85, 0x04, 0xed, 0x74, 0x0a, 0x12, + 0x82, 0x8a, 0x88, 0xea, 0x12, 0x78, 0xa8, 0x4b, 0x16, 0x61, 0xd0, 0xa1, + 0x83, 0x9d, 0xba, 0xe4, 0xf4, 0xbd, 0xef, 0xbd, 0xcf, 0x9d, 0xf9, 0x9c, + 0x55, 0x21, 0x41, 0x7f, 0xbc, 0x6f, 0xde, 0x7b, 0xdf, 0x9b, 0xdf, 0x7b, + 0xef, 0x37, 0x66, 0x00, 0xc0, 0x80, 0x92, 0xd3, 0x26, 0x10, 0x52, 0x46, + 0x28, 0x2e, 0x20, 0x04, 0xf0, 0x18, 0xe8, 0x27, 0x6a, 0x49, 0xbb, 0xd4, + 0xcd, 0x76, 0x27, 0x41, 0xa9, 0x33, 0x23, 0xfe, 0x9e, 0x85, 0xfe, 0x1c, + 0x62, 0x18, 0xfa, 0x77, 0x21, 0x1e, 0x84, 0x17, 0xb9, 0xac, 0xc0, 0xbf, + 0x2e, 0x94, 0xd0, 0x6e, 0xa8, 0x3c, 0x73, 0x92, 0x32, 0xff, 0x12, 0xc7, + 0x7f, 0x0a, 0x13, 0x1e, 0x28, 0xc4, 0x29, 0x0f, 0x23, 0x74, 0x65, 0x24, + 0x2c, 0x96, 0xd1, 0x1e, 0x19, 0x81, 0x18, 0xe6, 0x99, 0x12, 0x0e, 0x68, + 0xb7, 0x86, 0x4a, 0x5d, 0x5c, 0x97, 0x41, 0x7e, 0x5f, 0xca, 0x36, 0x9e, + 0xc3, 0xd7, 0x01, 0xb4, 0xb7, 0x27, 0x2e, 0x97, 0x11, 0xb3, 0x30, 0x16, + 0xb7, 0xe8, 0x7d, 0xda, 0x28, 0xed, 0x52, 0x07, 0xc6, 0x09, 0xdf, 0x0e, + 0xce, 0x1b, 0xc5, 0xbc, 0x3f, 0x5d, 0xca, 0x8b, 0xf9, 0xbc, 0x79, 0x5a, + 0x45, 0x1e, 0x3c, 0x8f, 0x71, 0x5d, 0x31, 0xad, 0xae, 0x98, 0xa8, 0x83, + 0x79, 0x00, 0x55, 0x07, 0x62, 0xa3, 0xb8, 0x17, 0xf3, 0xae, 0xf0, 0x7b, + 0x03, 0x9c, 0xca, 0x71, 0x7e, 0x07, 0xb1, 0xc2, 0xf9, 0xc4, 0x2f, 0xbf, + 0xc7, 0xfa, 0x3c, 0x8a, 0x27, 0x7f, 0xfd, 0x66, 0x41, 0x3d, 0x57, 0xfd, + 0xc0, 0x7b, 0x3e, 0x8a, 0x7b, 0xbc, 0xfe, 0xb0, 0x89, 0xff, 0x7b, 0xe1, + 0xef, 0xcf, 0x4b, 0xe7, 0x6f, 0xab, 0xe7, 0xf9, 0x20, 0xde, 0xa2, 0x1a, + 0x6f, 0x2f, 0x99, 0xb7, 0x41, 0xd8, 0x6d, 0x64, 0xa5, 0x5f, 0x04, 0x10, + 0x77, 0x88, 0x02, 0x10, 0x77, 0x32, 0x1e, 0x63, 0xbc, 0xc9, 0x78, 0x83, + 0xb1, 0x91, 0xb1, 0x81, 0xb1, 0x9e, 0x71, 0x1b, 0xe3, 0x3b, 0xc6, 0x0c, + 0xa3, 0xcd, 0x98, 0x66, 0x7c, 0xc3, 0x68, 0x31, 0x26, 0xb5, 0x7c, 0x2d, + 0x8c, 0x71, 0xc6, 0xbb, 0x8c, 0xfb, 0xb5, 0xf8, 0xdf, 0x8c, 0x0b, 0x8c, + 0xcd, 0x21, 0xc2, 0x43, 0x6c, 0x23, 0xa1, 0x3c, 0xf7, 0x3e, 0xbe, 0xee, + 0xaf, 0xf5, 0x77, 0xb1, 0xcc, 0xcf, 0xf3, 0xca, 0x2f, 0x2e, 0xf9, 0x83, + 0x0e, 0xaf, 0xff, 0x9d, 0x0d, 0xfc, 0xc9, 0x6d, 0x20, 0x1f, 0x14, 0x37, + 0xed, 0x52, 0x1d, 0xb7, 0x38, 0xbe, 0xbe, 0xb2, 0x50, 0x63, 0x8f, 0xfa, + 0x0a, 0xfa, 0x7c, 0x05, 0xed, 0xd1, 0x4e, 0xde, 0xa3, 0xa3, 0xeb, 0xe6, + 0x97, 0xe6, 0xd4, 0xbb, 0x87, 0x32, 0x4f, 0x8d, 0x39, 0x7f, 0x1a, 0x2a, + 0x16, 0xb2, 0x34, 0x17, 0xa5, 0x8d, 0xee, 0xc5, 0x78, 0x9e, 0xcb, 0xbc, + 0x9a, 0x4f, 0xff, 0x5c, 0xd2, 0x7c, 0xc5, 0xb4, 0xf9, 0xba, 0xb0, 0x09, + 0xbf, 0x49, 0x8d, 0xa7, 0x73, 0xae, 0xea, 0x97, 0xc1, 0xc7, 0xe3, 0xb1, + 0x8c, 0xcc, 0x7b, 0xcd, 0x91, 0x66, 0x83, 0x35, 0x85, 0x76, 0x04, 0xae, + 0x3b, 0x2a, 0x8e, 0xf7, 0xb2, 0x43, 0xdd, 0x43, 0xf1, 0x29, 0x20, 0x9e, + 0xe7, 0x34, 0x9e, 0x73, 0x5b, 0xd2, 0xa9, 0x15, 0xb7, 0xaa, 0x53, 0xf4, + 0xbc, 0x0d, 0xbc, 0x3a, 0x15, 0x87, 0xd1, 0x41, 0x5b, 0xde, 0x9b, 0x8e, + 0x51, 0x9a, 0xe3, 0x36, 0xe1, 0x99, 0x04, 0xe1, 0x72, 0xa2, 0x4e, 0xfc, + 0x75, 0xdd, 0xb1, 0x24, 0xd9, 0xa7, 0x53, 0x6a, 0x3f, 0x54, 0xbc, 0xaa, + 0x6b, 0xa3, 0x7a, 0xf0, 0x7e, 0x75, 0x8f, 0xaa, 0x43, 0xdd, 0xe7, 0xe7, + 0xbf, 0xf6, 0xbd, 0x84, 0x45, 0xc3, 0xcf, 0xc3, 0xed, 0x1e, 0xc2, 0x48, + 0xaf, 0x84, 0xec, 0x8c, 0x45, 0x71, 0xb3, 0x56, 0x04, 0xed, 0x7d, 0xb3, + 0x1f, 0x30, 0xbf, 0xb1, 0x67, 0xc6, 0xe1, 0xfa, 0x6c, 0xd5, 0x3f, 0x79, + 0x0e, 0xed, 0x40, 0xf6, 0x30, 0xcf, 0xc3, 0xb0, 0x9c, 0x7b, 0xb1, 0xd7, + 0x06, 0x62, 0x0b, 0x94, 0xa4, 0xae, 0x1b, 0x89, 0xd7, 0x32, 0x3e, 0xcc, + 0xe7, 0xa2, 0x4f, 0xed, 0xfe, 0x7d, 0x59, 0xa2, 0xfe, 0xc7, 0xfd, 0x73, + 0xd3, 0xed, 0x06, 0xcf, 0x63, 0xa2, 0x32, 0x57, 0x0e, 0xea, 0xd7, 0x73, + 0xd6, 0xbd, 0x2c, 0x14, 0x7b, 0x6b, 0xe9, 0xb1, 0xfa, 0x0e, 0x2a, 0x3d, + 0x92, 0xc7, 0x95, 0x52, 0xd8, 0xc7, 0xcb, 0x21, 0x28, 0x04, 0xe5, 0x7f, + 0xa2, 0xbe, 0x2f, 0x01, 0x7b, 0xb4, 0xd9, 0xbd, 0xbe, 0xfc, 0x69, 0x28, + 0x04, 0xed, 0x81, 0xa9, 0xed, 0x8d, 0xcd, 0x7b, 0xd3, 0xbc, 0x6e, 0x7e, + 0x95, 0x4e, 0xe4, 0x36, 0xd4, 0x89, 0xff, 0xd5, 0x05, 0x03, 0x48, 0x17, + 0x50, 0x8f, 0xfd, 0xf7, 0x9b, 0xaa, 0x7e, 0x6d, 0xff, 0xa9, 0xee, 0x3f, + 0xab, 0x5b, 0xd3, 0x11, 0xef, 0xfb, 0x07, 0xe9, 0x48, 0x42, 0xd3, 0x85, + 0x5f, 0xab, 0x55, 0x1d, 0xc1, 0xe7, 0xf3, 0xf3, 0xd4, 0x97, 0x8b, 0xee, + 0x9a, 0xae, 0xfb, 0xf8, 0xac, 0x63, 0x3e, 0x85, 0x9f, 0x8c, 0x5f, 0xd6, + 0xe2, 0x55, 0x5f, 0xcf, 0x33, 0xcf, 0x46, 0x1f, 0xcd, 0x95, 0x59, 0xfc, + 0xa1, 0xf1, 0xdd, 0x5b, 0xc0, 0xbd, 0xb8, 0x04, 0x0e, 0xf3, 0xf6, 0xd9, + 0xc7, 0x5f, 0x8a, 0xf5, 0xc1, 0x84, 0x47, 0x8e, 0xe2, 0x59, 0xf5, 0x87, + 0xf0, 0xa1, 0xf4, 0xcf, 0x6c, 0xc2, 0x77, 0x06, 0x1e, 0x38, 0x6a, 0xbf, + 0x6d, 0x99, 0xaf, 0x87, 0xf5, 0x64, 0x94, 0xf7, 0xfa, 0x5b, 0x82, 0x74, + 0xa3, 0x38, 0x24, 0xf7, 0x14, 0x9a, 0x78, 0xbf, 0x8b, 0x29, 0xb2, 0x5b, + 0x52, 0xf4, 0x7f, 0x5b, 0x8f, 0x69, 0x49, 0xbf, 0x96, 0x14, 0x61, 0x53, + 0x12, 0xe3, 0xb2, 0xf0, 0xfd, 0x88, 0x74, 0x2f, 0x54, 0xf7, 0x5b, 0xdf, + 0x6b, 0x7e, 0xdf, 0xbd, 0x78, 0xde, 0x24, 0xf6, 0xd4, 0xdb, 0x0f, 0x6b, + 0x4d, 0x5f, 0xef, 0x71, 0xf5, 0x39, 0xdb, 0xcb, 0xb7, 0x9a, 0xdb, 0x67, + 0x35, 0xfa, 0x34, 0xe8, 0x2a, 0xdd, 0x6b, 0x1f, 0xc4, 0x7a, 0x6d, 0x48, + 0x9b, 0x34, 0x1f, 0x84, 0x22, 0x8f, 0x61, 0x62, 0x58, 0xeb, 0x24, 0xeb, + 0xc4, 0xe4, 0xb8, 0x4c, 0x73, 0x64, 0x52, 0x9d, 0x0f, 0xc8, 0xc1, 0x1f, + 0x9e, 0x7f, 0x25, 0xcf, 0xd3, 0x4e, 0x98, 0xce, 0xcd, 0x21, 0xc5, 0x97, + 0x2d, 0xdf, 0x7f, 0x86, 0xf8, 0x3a, 0x39, 0x4d, 0x78, 0x02, 0x0e, 0x4b, + 0x4c, 0x54, 0xf5, 0x2d, 0x2e, 0x11, 0x52, 0x5e, 0x7d, 0x8b, 0x8a, 0xf2, + 0xd0, 0xae, 0xf3, 0xf4, 0x51, 0xff, 0x6e, 0x6c, 0xb5, 0x9f, 0x5e, 0x9d, + 0xc4, 0x7e, 0xea, 0x7a, 0x27, 0xe7, 0x46, 0x9b, 0xcf, 0x72, 0x8d, 0xf9, + 0xcc, 0xd5, 0x98, 0x6f, 0x5d, 0x2f, 0xae, 0xf2, 0xde, 0x45, 0x20, 0x1a, + 0x96, 0x1f, 0x24, 0x2b, 0x32, 0x21, 0xfb, 0x6b, 0x4c, 0xd2, 0x87, 0xd4, + 0x8a, 0x4e, 0x85, 0x24, 0x6f, 0xd6, 0x14, 0xf9, 0x45, 0xe8, 0x3c, 0xab, + 0xf0, 0xca, 0x84, 0xfa, 0xee, 0xfe, 0x03, 0x65, 0x6c, 0x9a, 0x59, 0x40, + 0x0c, 0x00, 0x00, 0x00 }; static u8 bnx2_rv2p_proc2[] = { - /* Date: 12/07/2007 15:02 */ - 0xed, 0x59, 0x5d, 0x6c, 0x54, 0xc7, 0x15, 0x9e, 0xbd, 0xbb, 0x7b, 0xf7, - 0x7a, 0x7d, 0xf7, 0xae, 0x71, 0xa8, 0xff, 0xf9, 0xb3, 0x09, 0xd8, 0xa9, - 0x21, 0xce, 0x9a, 0x98, 0x02, 0x55, 0x63, 0x39, 0x95, 0x81, 0xa6, 0x55, - 0x0c, 0x49, 0x9b, 0xbe, 0x35, 0x76, 0x02, 0xb6, 0xa9, 0x4d, 0x2d, 0x43, - 0x83, 0x4a, 0x1b, 0x65, 0x85, 0xd7, 0xf6, 0xcb, 0x26, 0xea, 0x22, 0xc0, - 0x24, 0xaa, 0xa8, 0x1b, 0xa4, 0x28, 0xea, 0xdb, 0x56, 0x6a, 0x6d, 0xda, - 0x97, 0xfe, 0x10, 0xb7, 0x4a, 0xa4, 0x42, 0xa5, 0xf6, 0xa1, 0x52, 0x85, - 0x44, 0xda, 0x62, 0x99, 0xc4, 0x20, 0x63, 0xba, 0x79, 0x21, 0x75, 0x67, - 0xce, 0x77, 0xe6, 0xee, 0xbd, 0xeb, 0xb5, 0x21, 0x2d, 0x8f, 0xdd, 0x07, - 0x1f, 0x66, 0xee, 0x99, 0x33, 0xe7, 0xe7, 0x9b, 0x33, 0x67, 0x0e, 0x65, - 0x42, 0x08, 0x43, 0x24, 0xb3, 0x1b, 0x24, 0x15, 0x56, 0x20, 0x20, 0xf0, - 0x7b, 0xac, 0x8c, 0xc8, 0x9f, 0xb3, 0x96, 0xfc, 0x1b, 0x16, 0xcf, 0x1b, - 0x55, 0x34, 0x0e, 0x09, 0x45, 0x1d, 0x21, 0x92, 0x5e, 0x5a, 0xce, 0xf4, - 0x67, 0x4c, 0x77, 0x1b, 0xa0, 0x3d, 0x4c, 0xeb, 0x98, 0x9e, 0x64, 0xba, - 0x91, 0xe9, 0x56, 0xa6, 0x27, 0x98, 0x7e, 0x8f, 0xe9, 0x07, 0x4c, 0x77, - 0xb2, 0x3c, 0xf9, 0x4b, 0xda, 0xf2, 0x4f, 0x40, 0x24, 0x9b, 0xb4, 0x7e, - 0x36, 0xa6, 0x9b, 0xa0, 0xe7, 0x73, 0x1b, 0x15, 0xdf, 0xcd, 0xa5, 0x3c, - 0x1f, 0xe6, 0xaf, 0x65, 0x40, 0x37, 0x60, 0xd5, 0x4f, 0x93, 0x8f, 0xeb, - 0xf5, 0x20, 0xdd, 0x31, 0xd0, 0x9e, 0x20, 0x68, 0x7b, 0x33, 0x91, 0xf4, - 0x4b, 0x06, 0xc6, 0x9d, 0x5b, 0x2c, 0xb2, 0x2f, 0x64, 0x28, 0x39, 0xeb, - 0x2d, 0xf3, 0x12, 0xe6, 0xbf, 0x19, 0x07, 0x7d, 0x39, 0x0a, 0xfa, 0x4f, - 0xa6, 0x87, 0x4b, 0x59, 0xbe, 0xcd, 0x6a, 0x97, 0x62, 0xfd, 0x8c, 0xad, - 0x68, 0x50, 0x24, 0x79, 0x9d, 0x10, 0xd0, 0xeb, 0xc7, 0x02, 0xdf, 0xd7, - 0x6c, 0xc5, 0xec, 0x0f, 0x0f, 0x63, 0x5c, 0x7b, 0xb1, 0x8c, 0xf8, 0xcf, - 0x67, 0xb5, 0xfe, 0x16, 0x79, 0x3f, 0x19, 0x87, 0x1c, 0x51, 0x6f, 0xd1, - 0x26, 0xc9, 0x66, 0x50, 0xb1, 0x4d, 0xcb, 0xc3, 0xef, 0xdc, 0xa3, 0xda, - 0x3f, 0x18, 0xaf, 0x4d, 0x80, 0x9e, 0x65, 0x5a, 0xd1, 0x4a, 0x64, 0xfb, - 0xdf, 0x9f, 0xb0, 0x48, 0x97, 0xe4, 0x36, 0xaf, 0x1f, 0x7f, 0x23, 0xfd, - 0xc8, 0x82, 0x1a, 0x40, 0x6e, 0x3c, 0xaa, 0xf8, 0xa4, 0x71, 0xf5, 0x90, - 0x7b, 0xb0, 0xbf, 0x98, 0xff, 0x7f, 0xf9, 0x19, 0xfc, 0xaf, 0xe4, 0xb5, - 0xb3, 0xfe, 0x1b, 0xa5, 0xfe, 0x8a, 0xd6, 0x05, 0x92, 0xdb, 0xfc, 0xfe, - 0xb9, 0x96, 0x89, 0xd3, 0xbf, 0x6f, 0x76, 0x94, 0x91, 0xfd, 0xcf, 0x62, - 0xfe, 0x74, 0xe7, 0x14, 0xfc, 0xb4, 0x9f, 0xe2, 0x22, 0xa2, 0xa9, 0x9f, - 0x63, 0x55, 0x77, 0x4c, 0x8d, 0x5f, 0xd8, 0x71, 0x23, 0x8b, 0xef, 0xe1, - 0x11, 0x35, 0x36, 0xe4, 0x3a, 0xfc, 0xf6, 0x07, 0x09, 0xe0, 0x69, 0x73, - 0x84, 0x86, 0xf6, 0x0c, 0x7d, 0xb7, 0xc5, 0x78, 0x16, 0xdf, 0x8f, 0x96, - 0xaa, 0xf1, 0xb3, 0xcd, 0x73, 0x18, 0x37, 0xf7, 0x8f, 0xf1, 0x42, 0xa3, - 0x44, 0xfe, 0x59, 0x5a, 0xba, 0x69, 0x40, 0x1e, 0x87, 0x37, 0x1a, 0x32, - 0xe2, 0x64, 0xaf, 0xdd, 0x09, 0x3a, 0x4a, 0xdf, 0xef, 0x05, 0xd2, 0x64, - 0x77, 0xa7, 0x13, 0x9a, 0x02, 0x23, 0xe3, 0xca, 0xc5, 0x8d, 0xc6, 0xdd, - 0x83, 0xe2, 0x67, 0xcc, 0xc5, 0x0f, 0xfb, 0xbf, 0x69, 0x25, 0xfc, 0x80, - 0x76, 0x6e, 0x01, 0x35, 0x1b, 0x14, 0x5f, 0xb8, 0x08, 0x8e, 0xfc, 0x7e, - 0xe6, 0xf8, 0x14, 0xe2, 0x44, 0xe2, 0x03, 0x63, 0xc6, 0x8b, 0xc4, 0x95, - 0xe2, 0xaf, 0x96, 0xfe, 0xd2, 0xf1, 0x57, 0x82, 0x22, 0xe2, 0xdb, 0x2c, - 0xaf, 0x9f, 0xed, 0x1a, 0x60, 0x7b, 0xe6, 0xa3, 0xda, 0xaf, 0xda, 0x1e, - 0xd0, 0x71, 0x9f, 0x3d, 0x01, 0x89, 0x27, 0x8d, 0x23, 0x9f, 0x3e, 0xe9, - 0xf7, 0xea, 0xf1, 0x8f, 0x5a, 0xc6, 0xa1, 0x6b, 0xe7, 0x16, 0xc5, 0x67, - 0x26, 0x26, 0xb2, 0x7e, 0x1c, 0x6e, 0x10, 0x5a, 0x8e, 0x96, 0xaf, 0x70, - 0x99, 0x93, 0xb8, 0x44, 0xdc, 0xce, 0x67, 0xbd, 0xe7, 0xa8, 0xa6, 0xc8, - 0x39, 0xf2, 0x9f, 0x07, 0xed, 0x97, 0xa3, 0x31, 0x4a, 0x10, 0x3b, 0xae, - 0xcc, 0xfa, 0xf7, 0x03, 0xbe, 0x23, 0x2e, 0x7e, 0xd6, 0xb6, 0xb1, 0xff, - 0x98, 0x56, 0xec, 0x54, 0xf2, 0xba, 0x58, 0x7e, 0x0b, 0xcb, 0xb7, 0x0b, - 0xce, 0xdb, 0x73, 0xee, 0x79, 0xd3, 0x71, 0xcb, 0x9f, 0x3b, 0xed, 0x3f, - 0xda, 0xbf, 0xf9, 0xca, 0xac, 0x5a, 0x5f, 0x7b, 0x9f, 0x73, 0xb8, 0xbf, - 0xc8, 0x39, 0x84, 0x9c, 0xbf, 0x3c, 0xee, 0xb7, 0x6b, 0x88, 0xf3, 0x5c, - 0x0f, 0xe2, 0x66, 0xbd, 0xf4, 0x2b, 0xfe, 0xf0, 0x18, 0xe1, 0x5d, 0xbc, - 0x18, 0x41, 0x7c, 0x1d, 0xd2, 0x5f, 0xb0, 0x1d, 0x2f, 0x7b, 0xce, 0x6b, - 0x09, 0xf9, 0xb5, 0xc3, 0xc4, 0x7e, 0x1d, 0xdd, 0x58, 0xde, 0xce, 0x78, - 0xc8, 0xf1, 0x79, 0x99, 0xb5, 0x49, 0xff, 0xe8, 0x9d, 0x53, 0x98, 0x1f, - 0xdd, 0x43, 0x24, 0x7d, 0xd5, 0xd0, 0xf6, 0x86, 0xd4, 0xdf, 0xc9, 0x41, - 0x7c, 0x9f, 0x0c, 0xf1, 0xf9, 0x7c, 0xaf, 0x9e, 0xd6, 0x5b, 0xf3, 0x19, - 0xac, 0xcf, 0xb1, 0x7e, 0x27, 0x82, 0xc4, 0x1f, 0x1d, 0x63, 0xbe, 0xf1, - 0x11, 0xbf, 0x9d, 0x3f, 0x40, 0x3e, 0xb7, 0xbf, 0x3f, 0x42, 0xe7, 0xdd, - 0x31, 0x5d, 0x3e, 0xa2, 0xce, 0xe8, 0x29, 0xc5, 0x5f, 0x29, 0xc6, 0xb2, - 0x4a, 0xd1, 0x2a, 0xd1, 0xbd, 0x17, 0xeb, 0xde, 0x30, 0x91, 0x6f, 0x7a, - 0xf7, 0x82, 0x7e, 0x88, 0xf9, 0xf5, 0xce, 0xb8, 0xe2, 0x5f, 0x53, 0xe3, - 0x4c, 0x29, 0x1a, 0x97, 0xf6, 0x28, 0xfb, 0xa5, 0xed, 0x8c, 0xcf, 0xc1, - 0x46, 0xf0, 0xf7, 0x1d, 0xa2, 0x8d, 0xcf, 0x0c, 0xe4, 0x28, 0x5f, 0x4d, - 0x0e, 0x5f, 0x52, 0x7e, 0xa9, 0x16, 0xb3, 0xc7, 0x14, 0x0d, 0x89, 0x8e, - 0x4d, 0xec, 0x97, 0x3d, 0xfe, 0xfc, 0x3c, 0xbf, 0x53, 0x8d, 0x6b, 0x24, - 0x9f, 0x17, 0xbf, 0x16, 0xc7, 0x39, 0xe4, 0xfa, 0xf5, 0x13, 0x03, 0x76, - 0xa7, 0x48, 0xff, 0x3d, 0xd1, 0x14, 0x9d, 0xeb, 0x98, 0xe8, 0x25, 0x3c, - 0x85, 0xac, 0xc1, 0x4b, 0xf8, 0x3e, 0xff, 0x0b, 0x2d, 0x57, 0xe1, 0x61, - 0x17, 0xdf, 0x9f, 0xc2, 0x95, 0x13, 0xda, 0xc9, 0x71, 0xd0, 0xfb, 0xb6, - 0xe2, 0xbe, 0xe9, 0x08, 0xa8, 0xf1, 0x3a, 0x39, 0xb6, 0x29, 0x6e, 0x1d, - 0xdd, 0x6a, 0xbd, 0x4c, 0x02, 0x74, 0x7e, 0x1c, 0x29, 0x5f, 0xcd, 0x47, - 0xa4, 0x1d, 0xfe, 0x7d, 0x06, 0x11, 0x0f, 0xfb, 0x28, 0xf9, 0xe7, 0xf3, - 0xf6, 0xad, 0x8c, 0xb6, 0x07, 0xf3, 0xb7, 0x5d, 0x7d, 0x6c, 0xb2, 0xab, - 0x63, 0x13, 0xf6, 0x9b, 0x75, 0x78, 0x9f, 0x4d, 0xbc, 0xef, 0x31, 0xb5, - 0x5f, 0x83, 0x47, 0x5f, 0xc5, 0x67, 0x45, 0x6f, 0x91, 0xdc, 0x75, 0xd6, - 0x77, 0x2e, 0x91, 0x7f, 0xad, 0xa3, 0x53, 0xd8, 0xff, 0xf6, 0xd4, 0x6a, - 0x7a, 0xd7, 0xb0, 0x9c, 0x75, 0xec, 0xd7, 0xd8, 0x43, 0x8c, 0xdb, 0xea, - 0x71, 0xca, 0xfb, 0x57, 0xfb, 0x87, 0xe4, 0xdb, 0x0b, 0xd3, 0xab, 0xe9, - 0x2b, 0x6d, 0x4a, 0x82, 0x3f, 0x65, 0xd0, 0xc1, 0xa8, 0x82, 0x5f, 0xf2, - 0x71, 0xd3, 0xfa, 0xce, 0x1f, 0xc2, 0x7d, 0x34, 0xe8, 0xe6, 0x0b, 0x25, - 0xb7, 0x9d, 0xf1, 0x20, 0xe5, 0x05, 0xe0, 0x9f, 0x85, 0x69, 0x9c, 0x9b, - 0x13, 0x74, 0x3e, 0xbe, 0x68, 0x87, 0x68, 0xff, 0xa8, 0x75, 0x83, 0xef, - 0xa5, 0xfc, 0xfd, 0x03, 0x79, 0x7d, 0x36, 0x68, 0x2f, 0xe7, 0xe9, 0x1b, - 0x4c, 0x53, 0xb6, 0x5a, 0x57, 0x2a, 0xf3, 0xad, 0x45, 0xf2, 0x91, 0x57, - 0x4b, 0x5c, 0x7d, 0x8f, 0xb0, 0x9c, 0x8f, 0x98, 0x0a, 0x96, 0x33, 0xc0, - 0xeb, 0xe7, 0x7c, 0x72, 0x0c, 0x8f, 0x1c, 0x7f, 0x3e, 0x1a, 0xe3, 0x7b, - 0xef, 0xbc, 0xb9, 0x52, 0xbd, 0xa4, 0x68, 0xb9, 0x5c, 0x8f, 0x59, 0x7d, - 0x2f, 0xa4, 0x1a, 0x89, 0xb4, 0x85, 0x0c, 0xb2, 0x77, 0x32, 0x35, 0x02, - 0x3f, 0x8d, 0xb3, 0x9f, 0x22, 0xf0, 0x53, 0x4d, 0xfe, 0x9e, 0xe4, 0x8d, - 0xf8, 0xfc, 0xcd, 0x6c, 0xf6, 0x9f, 0xc7, 0xf3, 0xa6, 0x8e, 0x2f, 0x91, - 0x34, 0xf2, 0x90, 0xbe, 0x3f, 0xf5, 0xbd, 0x72, 0x4b, 0xe7, 0x6d, 0xb9, - 0x6f, 0x81, 0x3e, 0x41, 0x8a, 0x73, 0x74, 0x9c, 0xf3, 0xd1, 0xd5, 0xa0, - 0x8e, 0x27, 0xf4, 0x1b, 0xff, 0x8c, 0xfa, 0xe5, 0xef, 0xe5, 0xb0, 0x22, - 0xcd, 0xb3, 0xc7, 0x88, 0xb6, 0xf4, 0x1d, 0xc7, 0x7c, 0x65, 0xab, 0xd2, - 0xe7, 0x27, 0x01, 0x9c, 0xd3, 0xb0, 0x98, 0xc9, 0xe0, 0x9e, 0x13, 0x11, - 0xd2, 0xa3, 0xee, 0x32, 0xe1, 0xc2, 0x8c, 0xa6, 0x32, 0x3e, 0x7f, 0x79, - 0xec, 0x2e, 0x66, 0xef, 0x84, 0xc4, 0x93, 0xfa, 0x6e, 0xf2, 0x79, 0x95, - 0x78, 0xb5, 0xf9, 0xbc, 0x3c, 0x4d, 0x7c, 0xf6, 0x22, 0xd9, 0xf9, 0x0d, - 0x6b, 0x9c, 0xeb, 0xb4, 0x8f, 0x3b, 0xd5, 0xf8, 0x79, 0xfb, 0x75, 0x9c, - 0x77, 0xfb, 0x75, 0xe4, 0x5b, 0x2b, 0x7c, 0x11, 0x79, 0xb8, 0xf3, 0xa2, - 0x6f, 0xff, 0x74, 0xc8, 0xd0, 0xe7, 0xe7, 0x7f, 0xf2, 0x9b, 0xfd, 0x5d, - 0xf6, 0xdb, 0xdd, 0xd5, 0xe3, 0x9a, 0x36, 0xf9, 0x1c, 0xf6, 0xdd, 0x2d, - 0xb4, 0x57, 0xf9, 0xef, 0x43, 0xf7, 0x1e, 0x0e, 0xed, 0x62, 0x7d, 0x76, - 0x71, 0x1e, 0xe0, 0xfa, 0x67, 0x7d, 0x50, 0xdf, 0x8b, 0x1a, 0x0f, 0x7c, - 0x3f, 0x02, 0xa7, 0xd6, 0x28, 0xec, 0x15, 0xaf, 0xf2, 0x39, 0xf8, 0x37, - 0xd3, 0xd7, 0x18, 0xff, 0x27, 0xb9, 0x3e, 0xd2, 0xf5, 0xdd, 0x3d, 0xcc, - 0x3b, 0x13, 0x6e, 0x3d, 0xa4, 0xef, 0x1f, 0x35, 0x0e, 0x08, 0x27, 0x52, - 0x4a, 0xfb, 0x25, 0x7f, 0x07, 0x80, 0x8d, 0x3f, 0x0d, 0x3f, 0xce, 0xb6, - 0x82, 0xef, 0x0d, 0xf8, 0xc7, 0xd1, 0xfa, 0x2d, 0x36, 0xfa, 0xde, 0x01, - 0x6d, 0xf0, 0xaf, 0xe9, 0xfa, 0x57, 0xe3, 0x73, 0x89, 0x69, 0xed, 0x66, - 0xb6, 0xf3, 0xbf, 0xf3, 0xbb, 0xa7, 0x1e, 0x5b, 0xc9, 0xef, 0xb4, 0xbe, - 0xad, 0xef, 0x2e, 0xe6, 0xcb, 0x76, 0x83, 0x66, 0x76, 0xd3, 0xfc, 0x66, - 0xe4, 0xdb, 0x70, 0xdb, 0xe9, 0xfb, 0xd4, 0xa7, 0xfa, 0x5d, 0x53, 0xf9, - 0x25, 0xd0, 0x33, 0x4c, 0x3f, 0xf7, 0x14, 0xe8, 0xb9, 0xa7, 0xfc, 0x79, - 0xc4, 0x8c, 0xfb, 0xe2, 0xdb, 0x86, 0xf8, 0xbe, 0xe3, 0xc6, 0x77, 0x3d, - 0xea, 0x03, 0x19, 0xaf, 0x55, 0xe3, 0xe9, 0xc6, 0xe9, 0x7e, 0xf1, 0x7c, - 0xd8, 0x71, 0x4c, 0xed, 0xc2, 0x3d, 0x37, 0xcc, 0xef, 0xcd, 0x45, 0xf7, - 0x9e, 0x2a, 0x16, 0xdf, 0xc8, 0xff, 0xe3, 0x4b, 0xf1, 0x3d, 0xb2, 0xa4, - 0xf3, 0x1f, 0xee, 0x79, 0x5d, 0xd7, 0x0f, 0x79, 0xea, 0x7a, 0xff, 0xbe, - 0xdf, 0xa2, 0x7a, 0x79, 0x34, 0xe0, 0xe2, 0x82, 0xf8, 0xa7, 0x79, 0x5d, - 0x19, 0xaf, 0xdb, 0xb7, 0x6c, 0xdd, 0xb5, 0x8c, 0x5a, 0xf7, 0xb7, 0x4f, - 0x97, 0xf7, 0x25, 0x7c, 0x7a, 0x26, 0x45, 0x1c, 0xf1, 0xc1, 0x7d, 0x61, - 0x16, 0xe9, 0x63, 0xf8, 0x71, 0xb7, 0x37, 0x8e, 0x7c, 0xa8, 0xdf, 0x79, - 0xfe, 0xba, 0xfe, 0x8f, 0x9f, 0xae, 0x5c, 0xd7, 0x6b, 0x79, 0x88, 0x5f, - 0xb7, 0x11, 0x23, 0xbe, 0xeb, 0x43, 0x6a, 0x5d, 0xbf, 0x6b, 0x5f, 0x3b, - 0xd9, 0x75, 0x99, 0xed, 0xab, 0x63, 0xfb, 0xe4, 0xe7, 0x6d, 0x74, 0x9f, - 0x58, 0xd7, 0x87, 0xbc, 0xf6, 0xfd, 0x7a, 0x95, 0xfd, 0x1e, 0xf4, 0x1d, - 0xc1, 0xfb, 0xc6, 0xf5, 0xfe, 0x4a, 0x5e, 0x2d, 0xd7, 0x63, 0x8e, 0xe0, - 0xe7, 0x54, 0x91, 0xba, 0x46, 0xed, 0xff, 0x7b, 0xe9, 0x00, 0xbe, 0xc7, - 0xe8, 0x1d, 0x11, 0xb4, 0x2e, 0x67, 0x8a, 0xf9, 0xe5, 0x6b, 0x01, 0xf0, - 0x15, 0x8b, 0x9b, 0xfa, 0x1e, 0x66, 0x39, 0xc5, 0xec, 0x66, 0x3d, 0x5d, - 0x3c, 0xf0, 0x3a, 0xe2, 0xeb, 0x63, 0xbe, 0x50, 0x91, 0xbe, 0x04, 0x46, - 0xb9, 0xad, 0x54, 0x2f, 0x5e, 0x38, 0x39, 0xad, 0xf8, 0x62, 0xee, 0xbb, - 0xcc, 0xaf, 0xdf, 0xc4, 0x43, 0xf0, 0x23, 0xbd, 0x3f, 0x44, 0xaf, 0xb3, - 0x92, 0xbf, 0xf0, 0x7e, 0x5a, 0x98, 0xd6, 0xfe, 0xb6, 0xc9, 0x4e, 0xd4, - 0xd3, 0x17, 0x0a, 0xfc, 0x68, 0x78, 0xfc, 0x08, 0xfe, 0x95, 0x71, 0xef, - 0x7f, 0x97, 0x03, 0x17, 0xaf, 0x16, 0xc1, 0x3d, 0xf5, 0xf7, 0x1e, 0xd8, - 0xce, 0x03, 0xad, 0x5e, 0xbb, 0x1a, 0xc4, 0x4c, 0x16, 0xf8, 0xef, 0x62, - 0x9c, 0xbc, 0xc8, 0x79, 0xf6, 0x7a, 0x54, 0x4d, 0x58, 0xa2, 0xe7, 0x19, - 0xe4, 0xe9, 0x8a, 0x52, 0xd8, 0xdd, 0xf3, 0x55, 0xed, 0x27, 0xcc, 0xd7, - 0xc4, 0x50, 0x57, 0x77, 0x45, 0xf0, 0xbe, 0xa8, 0x89, 0x81, 0x56, 0x70, - 0x9e, 0x9e, 0x71, 0xfb, 0x29, 0xa0, 0xf9, 0xfa, 0x12, 0x7d, 0xa5, 0xdf, - 0x9a, 0xa8, 0xc3, 0x45, 0x13, 0xd7, 0xcf, 0x94, 0xef, 0x82, 0xe2, 0x60, - 0x13, 0x70, 0x22, 0xea, 0xfd, 0x79, 0x8a, 0xf3, 0xec, 0xb2, 0x7a, 0x0d, - 0x7d, 0x99, 0x12, 0x4f, 0x5f, 0x42, 0xef, 0xa7, 0xfd, 0xa8, 0xe5, 0xd2, - 0x70, 0x85, 0xba, 0x72, 0x91, 0xf3, 0xd8, 0x23, 0xe2, 0x0f, 0x59, 0xd8, - 0x35, 0x93, 0x2d, 0xc4, 0x95, 0xde, 0x4f, 0xcb, 0x83, 0xde, 0xda, 0x8e, - 0xbc, 0x7c, 0xec, 0x7f, 0x88, 0xf5, 0xfc, 0x07, 0xf5, 0x33, 0x2b, 0xd8, - 0x1e, 0x25, 0x17, 0xf3, 0xfb, 0xb8, 0x4f, 0x94, 0x74, 0xc7, 0xfe, 0xfe, - 0x4e, 0x17, 0xe9, 0xb5, 0x86, 0x71, 0x54, 0xe1, 0xc1, 0x39, 0xf8, 0xd7, - 0xb6, 0x80, 0x9e, 0x6d, 0xd1, 0x71, 0xd0, 0xf1, 0xd2, 0xf1, 0x41, 0x1c, - 0x2b, 0xd0, 0x4f, 0xda, 0xd1, 0xf3, 0x04, 0xdd, 0x0f, 0x2d, 0x3d, 0x0b, - 0xfa, 0xdc, 0x61, 0xfd, 0x81, 0x66, 0xc5, 0xff, 0x9a, 0xf8, 0x13, 0xf7, - 0x1b, 0xfe, 0xca, 0xb4, 0xb0, 0x6f, 0x82, 0xbe, 0x8b, 0x8c, 0x5b, 0x98, - 0x03, 0xd2, 0xaa, 0xf3, 0xac, 0xf7, 0x9d, 0xa0, 0xcf, 0xdf, 0xd6, 0x65, - 0x78, 0xcd, 0xe7, 0x4b, 0x6d, 0x9f, 0xe2, 0x6f, 0x66, 0x1c, 0xca, 0xf7, - 0xe9, 0x5e, 0xa5, 0x47, 0x5c, 0xde, 0xdb, 0xc8, 0xc7, 0x4e, 0xc4, 0x1b, - 0x27, 0x89, 0x87, 0x92, 0x88, 0x1a, 0xd6, 0x95, 0x97, 0x90, 0x1d, 0xa7, - 0xdf, 0xff, 0x80, 0x3e, 0xbf, 0x3d, 0x51, 0x8a, 0xf9, 0xca, 0x67, 0xe2, - 0xe4, 0x87, 0x73, 0xc0, 0xf1, 0x8f, 0xce, 0x82, 0xbe, 0x25, 0xbe, 0x82, - 0xf5, 0xe5, 0xa7, 0xe8, 0xfe, 0xb7, 0x2a, 0x19, 0x97, 0x55, 0x38, 0xf7, - 0x69, 0xd4, 0x0f, 0x4b, 0x4b, 0x22, 0x86, 0xba, 0x4d, 0xdf, 0x03, 0xc0, - 0x65, 0xc8, 0x13, 0xdf, 0xfb, 0xe1, 0x54, 0x51, 0xbb, 0xf0, 0x9d, 0x64, - 0x15, 0xe2, 0x55, 0xfb, 0xa3, 0xca, 0x28, 0x8a, 0xcf, 0x36, 0x3f, 0x3e, - 0x4d, 0xc6, 0xe7, 0x5d, 0xb7, 0x8e, 0x5a, 0x2e, 0x97, 0xde, 0x89, 0x12, - 0xb7, 0x0f, 0x0b, 0xaf, 0xa0, 0xfb, 0x1a, 0xd4, 0xfe, 0x95, 0xcb, 0xf2, - 0xeb, 0x06, 0x5f, 0x9c, 0x6f, 0xde, 0xd3, 0x7a, 0x9d, 0x32, 0xbd, 0xdf, - 0x5b, 0xdc, 0x7b, 0x66, 0x98, 0xfb, 0xfc, 0x39, 0xf4, 0xa3, 0x12, 0xf3, - 0x69, 0x1a, 0xda, 0xd5, 0xef, 0x52, 0xdf, 0x22, 0x31, 0xcc, 0xf9, 0xf3, - 0xfd, 0xa0, 0xae, 0xb7, 0x30, 0xbe, 0xc2, 0x79, 0xe3, 0x0e, 0xeb, 0x75, - 0x80, 0x61, 0x39, 0xdf, 0x48, 0x79, 0x37, 0xa1, 0xeb, 0xb4, 0x61, 0x7e, - 0x5f, 0xe8, 0x3e, 0xd5, 0x97, 0x83, 0x9c, 0x4f, 0xc9, 0x8f, 0xa1, 0xc4, - 0xed, 0x29, 0xdd, 0x4f, 0xd0, 0xfd, 0x05, 0xd6, 0x07, 0xfd, 0x30, 0x71, - 0x30, 0x02, 0x2a, 0x9a, 0xfc, 0xf1, 0x11, 0xae, 0x9d, 0x18, 0x99, 0x05, - 0xfd, 0x86, 0x08, 0xf7, 0x09, 0x27, 0x58, 0xbf, 0x33, 0xfc, 0xbe, 0x73, - 0xc8, 0x4f, 0x65, 0xd2, 0x7e, 0xea, 0x5b, 0x25, 0x8e, 0x4d, 0xc3, 0xae, - 0x01, 0xf7, 0xfd, 0x06, 0x3e, 0xa6, 0xce, 0x9b, 0xdc, 0x2f, 0xe3, 0xbe, - 0x9a, 0x63, 0x8e, 0xc0, 0x9e, 0x81, 0x1c, 0xc6, 0x8b, 0x78, 0x17, 0x39, - 0xff, 0xe2, 0x3a, 0xef, 0xf8, 0x49, 0xfd, 0x1e, 0x2c, 0xbe, 0x4e, 0xd7, - 0x85, 0x83, 0xf4, 0x2e, 0x79, 0x61, 0x92, 0xfb, 0xea, 0xa2, 0x9f, 0xea, - 0xd1, 0xaf, 0xdb, 0x39, 0x1e, 0xe7, 0xfb, 0x07, 0xfe, 0xbe, 0x81, 0xae, - 0xbf, 0xe7, 0xd0, 0xff, 0x9c, 0xcc, 0xa5, 0x81, 0x97, 0x64, 0x89, 0x17, - 0xe7, 0x25, 0x89, 0x4a, 0x8e, 0xdb, 0xda, 0x27, 0x41, 0xcf, 0x3e, 0x89, - 0x77, 0xf2, 0xc0, 0x2b, 0xec, 0x97, 0x1d, 0x14, 0xa7, 0xed, 0xe8, 0xbf, - 0x78, 0xeb, 0x50, 0x85, 0x9b, 0x4f, 0x5c, 0x3c, 0xcf, 0x91, 0x5e, 0xb5, - 0x93, 0x39, 0xe2, 0xab, 0x11, 0x8f, 0xd0, 0xbd, 0x57, 0xed, 0x2c, 0x40, - 0xcf, 0xc4, 0x04, 0xdb, 0x37, 0xf4, 0x05, 0xd0, 0x57, 0x38, 0xce, 0x3a, - 0x7e, 0x57, 0xdd, 0x3e, 0x1e, 0xf4, 0xd5, 0xf7, 0xf1, 0xf2, 0xf7, 0x3b, - 0xc6, 0xd5, 0xad, 0x48, 0x60, 0x7d, 0xc7, 0x8b, 0xf7, 0xa7, 0xfc, 0x78, - 0x50, 0x78, 0xd1, 0xb8, 0xf4, 0xe2, 0xa8, 0xf0, 0x9c, 0xe5, 0x71, 0xe1, - 0x34, 0x55, 0x91, 0xbf, 0x70, 0x9f, 0x98, 0x89, 0x89, 0xcc, 0xea, 0x7e, - 0x7a, 0x13, 0x7e, 0x4a, 0xb0, 0xde, 0x76, 0xff, 0x08, 0xee, 0xa1, 0x31, - 0x8e, 0xd3, 0x5c, 0x23, 0xd7, 0x11, 0xac, 0xdf, 0xc7, 0xfc, 0xce, 0x40, - 0x3c, 0x23, 0xf6, 0xe1, 0x69, 0x8e, 0x1f, 0xe3, 0xea, 0x08, 0xdb, 0xfd, - 0x11, 0xec, 0xb6, 0xb5, 0xdd, 0xfd, 0xae, 0xdd, 0xba, 0x4e, 0xf1, 0xca, - 0x29, 0x97, 0xb8, 0xa0, 0x7a, 0xc7, 0xbe, 0x4a, 0x79, 0x24, 0xcc, 0x76, - 0x4a, 0xbe, 0x56, 0xfd, 0xff, 0x8e, 0xf0, 0x57, 0xef, 0x76, 0xef, 0xba, - 0x52, 0x5e, 0x17, 0x95, 0xeb, 0x30, 0x8f, 0xf3, 0x67, 0xaf, 0xe0, 0x4f, - 0xe5, 0x37, 0x2d, 0xb7, 0xf0, 0x7c, 0x79, 0xfd, 0x47, 0x95, 0x1d, 0xfd, - 0x90, 0x57, 0x64, 0x9c, 0xe8, 0x1e, 0xb2, 0xdd, 0xbc, 0x72, 0x87, 0xea, - 0xc0, 0xe8, 0x85, 0x41, 0xe4, 0x81, 0x0b, 0x83, 0xef, 0x72, 0x1d, 0xce, - 0x7e, 0xe9, 0xa2, 0xff, 0xaf, 0x92, 0xb1, 0xab, 0xf7, 0xe7, 0x15, 0xbf, - 0x1e, 0xb5, 0x1e, 0x3d, 0xf4, 0xbe, 0xff, 0x01, 0xfe, 0xf0, 0x11, 0xdc, - 0xa0, 0x1d, 0x00, 0x00, 0x00 }; + /* Date: 05/13/2008 13:50 */ + 0xad, 0x58, 0x4d, 0x6c, 0x54, 0x55, 0x14, 0xbe, 0x7d, 0xf3, 0xdb, 0x99, + 0x37, 0x3f, 0xb4, 0xb5, 0xbf, 0x68, 0xa1, 0x95, 0xd2, 0x92, 0x29, 0x94, + 0x69, 0x01, 0x95, 0x44, 0x49, 0x31, 0x05, 0x94, 0x84, 0x52, 0x5d, 0x10, + 0x37, 0xd0, 0x22, 0xa5, 0x83, 0x2d, 0x69, 0x28, 0x61, 0xc1, 0xc6, 0x09, + 0xc5, 0xe2, 0x62, 0x12, 0x2d, 0xb1, 0x14, 0x8c, 0xc1, 0x46, 0x37, 0xc4, + 0xb8, 0x19, 0x83, 0x52, 0xd4, 0xc4, 0x84, 0x60, 0x43, 0x70, 0x01, 0x26, + 0x9a, 0xe0, 0x42, 0x13, 0xa2, 0x50, 0x0b, 0x36, 0x58, 0x7e, 0x46, 0x17, + 0xca, 0x78, 0xef, 0xf9, 0xce, 0x7d, 0x7d, 0x6f, 0x3a, 0xb5, 0x2c, 0xe8, + 0xe6, 0xeb, 0xbd, 0xef, 0xdc, 0x73, 0xcf, 0xcf, 0x77, 0xcf, 0x39, 0x6d, + 0x54, 0x08, 0xe1, 0x16, 0xc9, 0x74, 0xb5, 0x44, 0x11, 0x32, 0x0a, 0xfc, + 0x12, 0xb2, 0x42, 0x78, 0xca, 0xd5, 0x5a, 0x18, 0x82, 0x7f, 0x56, 0x44, + 0x09, 0x7e, 0x48, 0xab, 0xef, 0x3e, 0xf1, 0xaa, 0x81, 0xef, 0x6e, 0xa1, + 0x30, 0x22, 0x44, 0x52, 0x61, 0x94, 0x71, 0x3d, 0x63, 0x86, 0x31, 0x58, + 0x00, 0x6c, 0x66, 0x7c, 0xc0, 0xfb, 0x77, 0x78, 0x7d, 0x93, 0xf1, 0x6f, + 0xde, 0x37, 0x19, 0x6f, 0xf3, 0xfe, 0xf3, 0x06, 0x30, 0xc1, 0xfb, 0x3f, + 0x4b, 0xd4, 0x76, 0xa9, 0xf5, 0x74, 0x56, 0x24, 0xe5, 0x19, 0x21, 0xc5, + 0x1b, 0xf4, 0xbe, 0x49, 0x90, 0x6c, 0x80, 0xdd, 0xaf, 0x2c, 0x51, 0x72, + 0xbf, 0xe7, 0x91, 0x53, 0xfb, 0x37, 0xb2, 0xd0, 0x3b, 0xeb, 0xaf, 0xe1, + 0x51, 0xe7, 0x96, 0xb6, 0x9c, 0x18, 0xc6, 0xf9, 0x9d, 0x4b, 0xb0, 0xff, + 0x54, 0x4c, 0xf9, 0xef, 0x15, 0x49, 0x46, 0xd1, 0xa8, 0xd0, 0x28, 0x48, + 0x36, 0xea, 0x40, 0x41, 0xfe, 0x97, 0x61, 0xac, 0x3a, 0x43, 0xd0, 0x1b, + 0x70, 0xe8, 0x2d, 0x9d, 0xa3, 0xf7, 0x5a, 0xa1, 0x5d, 0xff, 0x67, 0xac, + 0x3f, 0xb0, 0xa0, 0xfe, 0xae, 0x10, 0xb0, 0x38, 0x96, 0xef, 0x9e, 0xc2, + 0x05, 0xec, 0xdf, 0xb7, 0xa0, 0xfe, 0xc3, 0x96, 0xfd, 0x3a, 0x6e, 0xfa, + 0x3b, 0xb0, 0x1a, 0x62, 0x9f, 0x24, 0x57, 0xe9, 0x78, 0x6a, 0xbf, 0xd9, + 0x3e, 0x17, 0x70, 0x43, 0x8c, 0x20, 0xb5, 0x9b, 0x03, 0xdc, 0x56, 0xa7, + 0xee, 0x2d, 0x12, 0x6e, 0x43, 0xe9, 0x59, 0xee, 0xf7, 0x9e, 0xc7, 0xfe, + 0x8e, 0x08, 0xf0, 0x75, 0x76, 0xe4, 0x46, 0x40, 0x05, 0x26, 0x9b, 0xed, + 0x0e, 0xb2, 0x7e, 0xa4, 0x55, 0x24, 0x83, 0x38, 0x3f, 0x61, 0x2a, 0xfb, + 0x2e, 0xcb, 0xfc, 0xa9, 0xb5, 0x4b, 0x24, 0x23, 0x4e, 0x3f, 0x3e, 0x14, + 0x90, 0x5b, 0xb4, 0x1c, 0xbb, 0xef, 0x76, 0x63, 0x5d, 0xf5, 0x71, 0x94, + 0xe4, 0x4f, 0xa6, 0xb5, 0x1f, 0x6a, 0x5f, 0xbe, 0x83, 0x08, 0xf4, 0x88, + 0x1a, 0x3f, 0x5d, 0x86, 0x38, 0xc9, 0x4b, 0x1b, 0xb5, 0x3e, 0xfc, 0x9c, + 0x58, 0xa6, 0xf9, 0x85, 0x75, 0xb7, 0x97, 0xa0, 0xbc, 0x73, 0x48, 0xd9, + 0x1b, 0x11, 0xbb, 0x0c, 0x65, 0x88, 0xc1, 0xfe, 0xb9, 0xfc, 0xe6, 0x17, + 0x90, 0xff, 0xa6, 0xda, 0x24, 0xdb, 0xba, 0x9b, 0x71, 0xae, 0x24, 0x0e, + 0x1c, 0x89, 0x7b, 0x14, 0xc4, 0xba, 0x07, 0x68, 0xb9, 0xf2, 0xd7, 0xd5, + 0x7e, 0x92, 0x4b, 0x36, 0x6a, 0xfe, 0xea, 0xb8, 0x2b, 0x7f, 0xdf, 0xc9, + 0x5a, 0xfc, 0xaf, 0x45, 0x7c, 0x6e, 0x2e, 0x53, 0xf2, 0x32, 0x48, 0x35, + 0xb8, 0xa7, 0x23, 0x91, 0x8f, 0xff, 0x6f, 0xdb, 0xf8, 0xff, 0x68, 0x79, + 0xdc, 0x40, 0xfe, 0x6f, 0xe0, 0x38, 0x2c, 0x61, 0xbe, 0x2c, 0xce, 0xc3, + 0x97, 0x08, 0xfd, 0x7e, 0xab, 0x35, 0x4a, 0x71, 0xdc, 0x86, 0xfd, 0xe3, + 0x6d, 0xe7, 0x10, 0xef, 0x2d, 0x14, 0x07, 0x11, 0x38, 0xfa, 0x39, 0x4e, + 0x75, 0x86, 0xd4, 0xfa, 0xb5, 0x96, 0xee, 0x2f, 0xb1, 0xee, 0x72, 0xa9, + 0xf5, 0x0e, 0x73, 0xf7, 0x38, 0xe4, 0x3d, 0x83, 0x51, 0x8a, 0xdf, 0x36, + 0xbe, 0x65, 0x8b, 0xab, 0x40, 0x41, 0xca, 0x3b, 0x48, 0x4b, 0x73, 0x82, + 0xbe, 0x47, 0xc5, 0xb1, 0x34, 0xbe, 0xef, 0x0f, 0x52, 0x7d, 0x90, 0xfe, + 0x91, 0x5c, 0x49, 0xc2, 0x8b, 0xf3, 0xa9, 0x61, 0x3f, 0xf9, 0x3b, 0x75, + 0x56, 0xad, 0xb7, 0xc6, 0xa6, 0x20, 0x1f, 0x4b, 0x0c, 0xb1, 0x62, 0x03, + 0xf1, 0xbb, 0x65, 0x40, 0x9e, 0xe9, 0x15, 0x70, 0x53, 0xfe, 0x0a, 0x84, + 0xd9, 0x06, 0x7c, 0x8b, 0xbe, 0xff, 0x53, 0x90, 0xa2, 0x78, 0x6d, 0x0c, + 0xbb, 0xcf, 0xe9, 0xf8, 0x30, 0x46, 0xb4, 0x5f, 0xc0, 0x47, 0xe5, 0xef, + 0x90, 0xa9, 0x79, 0xcb, 0x79, 0x6b, 0x98, 0x8f, 0xb7, 0xc0, 0xb6, 0x3a, + 0xa0, 0xb7, 0x56, 0xc9, 0x79, 0xf2, 0xf0, 0xd7, 0x99, 0x17, 0xce, 0xab, + 0x8d, 0x67, 0x04, 0x92, 0x5f, 0x0e, 0xbe, 0x49, 0x3e, 0x53, 0x5d, 0x92, + 0xf1, 0xd4, 0xbc, 0x51, 0x8a, 0x7c, 0xe2, 0x0d, 0xd6, 0x97, 0x60, 0xbf, + 0x7a, 0xd9, 0xaf, 0xe9, 0x80, 0x8e, 0xbb, 0xf6, 0x07, 0x78, 0xcc, 0x04, + 0xbf, 0x3a, 0x12, 0xda, 0x2f, 0x27, 0x7f, 0xd9, 0x9e, 0xd4, 0xb7, 0x35, + 0xf8, 0xa5, 0xaa, 0x16, 0x68, 0xf9, 0x59, 0x47, 0xef, 0x25, 0x5c, 0x36, + 0xae, 0xed, 0x50, 0x79, 0xfd, 0x4b, 0xe6, 0x15, 0xf9, 0x39, 0x99, 0xb6, + 0xbf, 0xd3, 0xca, 0x3c, 0xef, 0xd4, 0xf9, 0x6e, 0xb4, 0xff, 0xfb, 0x43, + 0x54, 0x88, 0x5a, 0xae, 0x4c, 0x3a, 0xdf, 0x05, 0xf8, 0xef, 0xb3, 0x78, + 0x54, 0xb2, 0x96, 0xe3, 0xc4, 0x58, 0xba, 0x4e, 0xe9, 0x6b, 0x67, 0xfd, + 0x4d, 0xac, 0xdf, 0xb4, 0xbd, 0x4b, 0x65, 0xdf, 0x93, 0xd6, 0x7b, 0xd4, + 0xf9, 0x99, 0x7d, 0x97, 0x3a, 0x4e, 0x74, 0x7f, 0xec, 0xca, 0xa4, 0x3a, + 0x5f, 0xb5, 0xc0, 0x3b, 0x2d, 0xb6, 0xf4, 0xfd, 0x68, 0xbd, 0x47, 0xf5, + 0x3d, 0x28, 0x5e, 0xe0, 0xa5, 0xb3, 0xde, 0xfc, 0x29, 0xeb, 0x0d, 0xf9, + 0xe1, 0x37, 0xcf, 0x71, 0x7d, 0x19, 0x50, 0xf7, 0x94, 0xb3, 0xdd, 0xe5, + 0xba, 0xce, 0x4b, 0xbb, 0xb9, 0x0e, 0xed, 0xb4, 0xd7, 0x13, 0x8f, 0xad, + 0x2e, 0xa8, 0xb5, 0x2b, 0x4f, 0x9f, 0x74, 0xc4, 0x33, 0x29, 0x22, 0x98, + 0x03, 0x92, 0x11, 0x25, 0x7f, 0x4f, 0xcc, 0xad, 0x2b, 0xb9, 0xf6, 0x23, + 0x1e, 0x9d, 0x46, 0x88, 0xe4, 0xae, 0xf7, 0xab, 0x73, 0xd7, 0xac, 0x3e, + 0x8e, 0x3a, 0x73, 0x91, 0xed, 0x5d, 0xcc, 0xf6, 0x4a, 0x7d, 0x8d, 0xc4, + 0x53, 0xff, 0xf5, 0x7e, 0xbb, 0xbd, 0x77, 0x1e, 0xce, 0x7f, 0x9f, 0x33, + 0xef, 0xfd, 0xdc, 0x6f, 0xb8, 0x4f, 0xfa, 0x77, 0x7f, 0xa5, 0xed, 0xe1, + 0x7b, 0x23, 0xfa, 0x7e, 0x93, 0xf2, 0x32, 0x39, 0xa0, 0xce, 0x87, 0x05, + 0xd3, 0x44, 0xf4, 0xd5, 0xa3, 0xae, 0x4d, 0xef, 0x81, 0xfd, 0x7d, 0x75, + 0xea, 0xfe, 0x16, 0x81, 0x7e, 0xe3, 0x96, 0x21, 0x45, 0x7d, 0xbf, 0x38, + 0x9c, 0x2f, 0x8f, 0x5f, 0xb3, 0xdc, 0x38, 0xfb, 0x15, 0x65, 0xbf, 0x36, + 0x4b, 0xbf, 0x28, 0xee, 0xfc, 0x3d, 0x9f, 0xdf, 0x6c, 0xa7, 0xd0, 0xfd, + 0x9b, 0xcf, 0x91, 0x5c, 0x0f, 0xcb, 0xb9, 0xe7, 0xed, 0xdb, 0x99, 0xe5, + 0x54, 0x87, 0x4f, 0x1f, 0xa6, 0x7a, 0x1a, 0xb2, 0xf8, 0xe6, 0xb4, 0x6f, + 0xe2, 0x31, 0xc4, 0x51, 0xc9, 0x2d, 0x12, 0x7b, 0xc3, 0xf3, 0xc5, 0xcb, + 0xad, 0xb6, 0xc7, 0x66, 0xc6, 0x75, 0xbc, 0x4d, 0xf2, 0x73, 0x72, 0x80, + 0xe6, 0xc2, 0x9c, 0x38, 0x1a, 0xb6, 0x38, 0x42, 0x1e, 0xf3, 0x4a, 0xbe, + 0xf8, 0xe5, 0xeb, 0x8b, 0x9f, 0x3e, 0xd4, 0x7c, 0x3a, 0xe2, 0xd5, 0xf6, + 0x2b, 0x5c, 0x65, 0xe5, 0xf3, 0x00, 0xcf, 0x23, 0x19, 0x93, 0x7e, 0x89, + 0x4f, 0xa7, 0x68, 0x69, 0x56, 0x9c, 0x51, 0x72, 0x2b, 0xe2, 0x07, 0xd8, + 0xce, 0xcb, 0x2e, 0xf8, 0xd1, 0xb3, 0x07, 0xeb, 0x2b, 0x5c, 0xdf, 0xee, + 0x72, 0x9d, 0xda, 0xee, 0x07, 0x4e, 0xd7, 0x93, 0x7f, 0xf1, 0x03, 0xe7, + 0xb5, 0x7e, 0xd2, 0x6b, 0x66, 0x38, 0x3e, 0x2f, 0xba, 0xd8, 0xee, 0x1a, + 0xca, 0x47, 0xfc, 0x0e, 0xbd, 0x4f, 0xb7, 0x68, 0x5d, 0xaa, 0xb0, 0x42, + 0xc6, 0x81, 0xed, 0x59, 0x0f, 0xec, 0xf0, 0x71, 0x5c, 0x1b, 0x72, 0xf3, + 0x85, 0x6d, 0x6f, 0x0d, 0x9f, 0xef, 0xc4, 0xda, 0xc7, 0xf5, 0x65, 0x94, + 0xed, 0x7a, 0xaf, 0x1e, 0x18, 0x6e, 0x40, 0x7f, 0x9c, 0x34, 0x15, 0x46, + 0xe2, 0x03, 0xe3, 0xf0, 0xa7, 0x77, 0x23, 0xfc, 0xbd, 0xc7, 0x71, 0x60, + 0x0c, 0x9f, 0x1a, 0xa4, 0xbe, 0x19, 0x1e, 0x42, 0x7f, 0x0d, 0x7b, 0x07, + 0xe1, 0x47, 0x6f, 0x06, 0xeb, 0x7b, 0xcf, 0x02, 0x1f, 0x3c, 0x87, 0x73, + 0x07, 0x0f, 0x73, 0x7c, 0x36, 0xe6, 0x3f, 0xd7, 0x73, 0x1f, 0x72, 0x7d, + 0xf5, 0xd4, 0xe7, 0xc7, 0xb8, 0xef, 0x8a, 0x04, 0xf7, 0xf9, 0x0c, 0xaf, + 0xf7, 0x71, 0x1f, 0xb9, 0xcd, 0x7d, 0xb2, 0x37, 0xa7, 0x4f, 0x4e, 0xa1, + 0x6e, 0x8e, 0x65, 0x52, 0x6a, 0x43, 0xd6, 0xaf, 0x42, 0xdd, 0x1f, 0x15, + 0x06, 0xe2, 0x65, 0x9c, 0xaf, 0x92, 0x35, 0xc0, 0x91, 0x35, 0xe8, 0x6b, + 0xbd, 0x87, 0x38, 0x2e, 0x2d, 0x94, 0x9f, 0x95, 0x33, 0xe3, 0x9a, 0x0f, + 0x34, 0x3f, 0x3d, 0xd4, 0xbc, 0x43, 0xfd, 0xca, 0x58, 0xf5, 0x76, 0x8a, + 0xec, 0xab, 0x1a, 0xcb, 0x90, 0x7c, 0xa5, 0x28, 0x26, 0x7e, 0x55, 0x84, + 0x67, 0x60, 0x6f, 0x7c, 0x94, 0xfd, 0xec, 0x7f, 0x06, 0x78, 0x88, 0xf3, + 0xac, 0xf3, 0x77, 0x75, 0x9d, 0x49, 0xe7, 0x26, 0x07, 0x60, 0xb7, 0xe6, + 0x7d, 0xee, 0x9c, 0xa7, 0xf3, 0x5e, 0xd1, 0x4c, 0x6b, 0xd1, 0x73, 0x50, + 0xdd, 0x13, 0x92, 0xf9, 0x52, 0x76, 0xc9, 0x58, 0x70, 0x7f, 0x74, 0xf2, + 0x41, 0xf1, 0x45, 0xf3, 0xd2, 0xce, 0x23, 0x3b, 0x4f, 0x9c, 0xfc, 0x08, + 0x53, 0x3d, 0x97, 0x8f, 0x97, 0xfa, 0xa7, 0x37, 0x3e, 0x3a, 0xfc, 0xff, + 0xf1, 0x3a, 0x85, 0x78, 0xc5, 0xd9, 0x6e, 0x33, 0x41, 0x73, 0xd6, 0x13, + 0x62, 0x88, 0xf3, 0x35, 0x55, 0xcf, 0xef, 0xb5, 0x06, 0xf9, 0xea, 0x7f, + 0x1a, 0xf6, 0xf4, 0xf3, 0x3b, 0xf9, 0x83, 0xfb, 0x39, 0xf2, 0xec, 0x33, + 0xbb, 0xc7, 0x39, 0xaf, 0xcc, 0xb7, 0x7d, 0x1c, 0x87, 0xdb, 0x88, 0x83, + 0xa9, 0xe3, 0x90, 0xb0, 0xe2, 0xa0, 0xeb, 0x83, 0x5d, 0x4f, 0x91, 0xe4, + 0x0b, 0xd5, 0x19, 0xf3, 0x2a, 0xcd, 0x27, 0x1e, 0xf6, 0x5b, 0xca, 0x35, + 0x2b, 0xff, 0xc2, 0xec, 0x5f, 0x48, 0xec, 0x5d, 0x69, 0x3f, 0x17, 0xe4, + 0x73, 0x01, 0x79, 0x0e, 0xfb, 0x78, 0x8f, 0xe6, 0x3c, 0xf1, 0x55, 0x71, + 0xd4, 0x7a, 0x73, 0xdf, 0x9d, 0x3d, 0x9e, 0x54, 0x51, 0xe9, 0x07, 0x75, + 0x46, 0xe6, 0x8d, 0xea, 0x91, 0x69, 0xd5, 0x99, 0xbb, 0x54, 0x7f, 0x03, + 0xa7, 0xfb, 0x50, 0x17, 0x4e, 0xf7, 0x9d, 0xe1, 0xfe, 0xc7, 0x71, 0x69, + 0xa7, 0xb9, 0x58, 0xc6, 0xae, 0xc6, 0x59, 0x67, 0x9c, 0x76, 0x54, 0xd9, + 0xec, 0xd0, 0xf7, 0xce, 0xd7, 0x97, 0x31, 0xaf, 0x6d, 0xa2, 0xbe, 0xec, + 0xb7, 0xe6, 0x49, 0x67, 0xbd, 0xf7, 0x3f, 0x72, 0xbd, 0xdf, 0xde, 0x6c, + 0xd7, 0x5f, 0x2b, 0x26, 0xd2, 0xd0, 0xdf, 0xce, 0xfd, 0x72, 0x17, 0xbf, + 0xdb, 0xeb, 0x81, 0x08, 0xdd, 0xd7, 0xf5, 0x32, 0xf9, 0x27, 0x4a, 0x83, + 0xf0, 0xa7, 0x6b, 0x2b, 0xbe, 0x77, 0x85, 0xb0, 0x5f, 0x19, 0xc2, 0xdf, + 0x5b, 0xed, 0x3e, 0x93, 0xe4, 0x2b, 0x43, 0xc0, 0x52, 0x7e, 0xef, 0x13, + 0xd6, 0x5c, 0x0c, 0x3c, 0xe9, 0xb5, 0xcf, 0x8f, 0x6e, 0x71, 0xc1, 0x8b, + 0xf7, 0x2f, 0x1a, 0x30, 0x07, 0xb6, 0xd6, 0x99, 0xf4, 0xbd, 0xa3, 0x01, + 0xfd, 0x12, 0xf5, 0x75, 0xf6, 0xef, 0x33, 0x9e, 0x2b, 0x2b, 0x67, 0xe7, + 0x67, 0xfb, 0x7c, 0x5d, 0x18, 0x1f, 0xb5, 0xe6, 0x5c, 0x7d, 0x9f, 0xfd, + 0xfd, 0x28, 0xbd, 0xb4, 0x94, 0x73, 0xaa, 0x7d, 0xbe, 0x76, 0xe9, 0x79, + 0x87, 0xe7, 0xd1, 0x62, 0x71, 0x29, 0x0d, 0xbf, 0x26, 0xd2, 0xf9, 0xde, + 0xa1, 0xba, 0x4f, 0xeb, 0x83, 0xdd, 0xda, 0x8f, 0x59, 0xfd, 0xb8, 0x7f, + 0x0f, 0xdb, 0xf9, 0x1b, 0xfd, 0x5d, 0x5c, 0xca, 0xfe, 0x28, 0xbd, 0xd8, + 0xdf, 0xcc, 0xf3, 0x7e, 0xd2, 0x5a, 0x3b, 0xe7, 0xf4, 0x76, 0xb2, 0xab, + 0x88, 0xfb, 0x69, 0xa9, 0xad, 0xdf, 0x43, 0xbe, 0xa4, 0x09, 0x38, 0xd2, + 0xa4, 0xf3, 0xa0, 0xf3, 0xa5, 0xf3, 0x83, 0x3c, 0x96, 0xae, 0x26, 0xb1, + 0x96, 0xae, 0xd5, 0xf4, 0x60, 0x9b, 0xba, 0x66, 0x9c, 0xff, 0x3f, 0xd8, + 0x1e, 0x53, 0xf2, 0x6f, 0x8a, 0xef, 0x63, 0x68, 0x80, 0x3f, 0x31, 0xce, + 0xce, 0xc5, 0x9c, 0x00, 0x6b, 0x1e, 0xc1, 0x7d, 0x17, 0x3c, 0xbc, 0xdd, + 0xac, 0xe7, 0x46, 0x67, 0xff, 0xfe, 0x90, 0xea, 0xf2, 0xd9, 0x7f, 0x73, + 0xe7, 0xce, 0xd9, 0xf9, 0x51, 0xfb, 0xa9, 0xe4, 0x1b, 0x99, 0x8f, 0x7e, + 0xd1, 0xba, 0x09, 0x7f, 0x6f, 0x87, 0x7d, 0xe0, 0x7d, 0xd8, 0x67, 0xcf, + 0x97, 0xe4, 0x45, 0x21, 0x3d, 0xf0, 0xc5, 0x45, 0x85, 0xe4, 0xcf, 0xf1, + 0xcb, 0xdf, 0xd1, 0xe7, 0x8f, 0x46, 0x83, 0xd8, 0x2f, 0x6b, 0x85, 0x7a, + 0x37, 0xf1, 0xd6, 0x25, 0x8e, 0x82, 0xd7, 0x1f, 0x8c, 0x00, 0xdf, 0x17, + 0x2f, 0x41, 0x4f, 0xd1, 0x11, 0xea, 0x73, 0xfe, 0x32, 0x84, 0x35, 0x35, + 0xca, 0x7c, 0x2d, 0x37, 0xe8, 0xff, 0x65, 0x59, 0x11, 0xe2, 0xff, 0xab, + 0xf0, 0xbb, 0x03, 0x4f, 0xdd, 0xb6, 0x7c, 0x2f, 0xc4, 0x5b, 0xaa, 0x1f, + 0x92, 0x97, 0x38, 0xce, 0xfc, 0xf5, 0xe7, 0xf2, 0x57, 0xc7, 0xa5, 0xdc, + 0xc8, 0xcb, 0xd7, 0xb5, 0x4e, 0xbe, 0x7a, 0x99, 0xaf, 0xf7, 0xad, 0xfe, + 0x36, 0x57, 0x2f, 0xfe, 0xae, 0xb8, 0xf4, 0xd8, 0xf8, 0x0b, 0xdc, 0x5c, + 0xab, 0xee, 0x2f, 0x9b, 0x33, 0x77, 0x56, 0x0b, 0x7b, 0x3d, 0x3a, 0x24, + 0xf3, 0xfd, 0x1f, 0xfe, 0xac, 0x5e, 0x92, 0x80, 0x14, 0x00, 0x00, 0x00 }; static u8 bnx2_TPAT_b06FwText[] = { - 0xbd, 0x59, 0x6f, 0x70, 0x5c, 0xd5, 0x7d, 0x3d, 0x6f, 0xf7, 0xed, 0xee, - 0x93, 0xb4, 0x92, 0x9e, 0x90, 0x0c, 0xab, 0x56, 0x8d, 0xf6, 0x59, 0x6f, - 0xa5, 0xc5, 0xab, 0xd8, 0x6f, 0x2d, 0xb9, 0xac, 0x87, 0x37, 0xcd, 0xb3, - 0x2c, 0x29, 0x8b, 0xec, 0xd8, 0xeb, 0x42, 0x66, 0xe4, 0x09, 0x1d, 0x0b, - 0x59, 0xd8, 0xc2, 0x18, 0xa2, 0x12, 0x3e, 0xa8, 0x13, 0x4f, 0xbd, 0xe8, - 0x9f, 0x85, 0xbd, 0xd2, 0x23, 0x02, 0x2c, 0x3b, 0x93, 0x0e, 0x1e, 0xf9, - 0x8f, 0x18, 0x58, 0x6b, 0xa1, 0xfd, 0x92, 0x69, 0xc3, 0x44, 0x13, 0x1b, - 0xec, 0x90, 0x38, 0x4e, 0xa7, 0x5f, 0xcc, 0xb4, 0x9d, 0xaa, 0x80, 0x29, - 0x50, 0x70, 0xdc, 0xce, 0xa4, 0x63, 0x0a, 0xf5, 0xed, 0xb9, 0x6f, 0x57, - 0x46, 0x38, 0x4e, 0x3f, 0xd6, 0x33, 0x8b, 0x76, 0xef, 0x7b, 0xf7, 0xde, - 0xdf, 0xbd, 0xbf, 0x73, 0xce, 0xef, 0xdc, 0xcb, 0x6a, 0x1f, 0xca, 0x51, - 0xfa, 0x57, 0xc9, 0x4f, 0xfb, 0x23, 0x43, 0x4f, 0x6f, 0x58, 0x6b, 0xad, - 0x95, 0xbf, 0x95, 0x00, 0x54, 0xfc, 0x3f, 0xfe, 0xf3, 0x03, 0xfa, 0x72, - 0x1c, 0xf2, 0x03, 0xcd, 0x67, 0x2f, 0xae, 0xee, 0x30, 0xa1, 0xf9, 0xed, - 0x87, 0x5a, 0x76, 0x9b, 0x80, 0x93, 0x4f, 0x44, 0x37, 0xe3, 0x7f, 0x44, - 0xb6, 0x4e, 0x85, 0x6c, 0xff, 0x23, 0xfb, 0x8b, 0x75, 0x6f, 0xdc, 0x67, - 0x5c, 0x3f, 0xe1, 0x87, 0xa6, 0xdb, 0x93, 0x9a, 0xde, 0x0c, 0xad, 0x81, - 0x7d, 0x7e, 0xd4, 0xb2, 0x2b, 0x88, 0xaa, 0xe5, 0xb1, 0x80, 0x93, 0x39, - 0xc3, 0xda, 0x83, 0x84, 0x7e, 0x8e, 0x0b, 0x72, 0x38, 0xc7, 0x99, 0x3c, - 0x70, 0x28, 0xa7, 0xe0, 0x2a, 0xc7, 0x1c, 0xcf, 0x6b, 0x58, 0xf2, 0x7b, - 0xd3, 0xf5, 0x95, 0xd9, 0xc8, 0x98, 0x53, 0x07, 0x45, 0xc8, 0x44, 0xf6, - 0x0f, 0x6c, 0x33, 0x7e, 0x08, 0xe1, 0xd4, 0x5c, 0x3b, 0x32, 0xab, 0xcf, - 0x6a, 0xd8, 0xe9, 0x36, 0xf4, 0x69, 0x36, 0xf8, 0x8e, 0x82, 0xd4, 0x7d, - 0x1a, 0x7a, 0x0b, 0x71, 0x64, 0x0b, 0x59, 0x38, 0x85, 0x31, 0x7e, 0x34, - 0x84, 0xa6, 0x34, 0x6d, 0xdd, 0xd4, 0xdd, 0xf2, 0x1d, 0x84, 0xa7, 0xae, - 0x8b, 0x6b, 0x49, 0x1d, 0x6f, 0x6f, 0x14, 0xa2, 0xd2, 0x46, 0xb6, 0xa2, - 0x3d, 0x0b, 0xbf, 0x6d, 0x58, 0x5b, 0xfc, 0x0a, 0x3a, 0xbf, 0x6e, 0xc6, - 0xa7, 0x94, 0x07, 0x1f, 0xf4, 0xd9, 0xd0, 0x14, 0x3b, 0xaa, 0x35, 0xe5, - 0x1b, 0x30, 0x51, 0xd0, 0x71, 0xa8, 0x50, 0x87, 0xb1, 0x02, 0x0e, 0xf8, - 0x37, 0x04, 0x31, 0xa7, 0xc3, 0xf9, 0x4e, 0xcb, 0x01, 0xec, 0xcb, 0x0d, - 0x63, 0x77, 0x2e, 0x85, 0xc3, 0x05, 0x19, 0x63, 0x14, 0xa3, 0x05, 0x15, - 0xc1, 0x29, 0x23, 0xf2, 0x73, 0xdc, 0xe9, 0x99, 0x10, 0x63, 0x56, 0x08, - 0x23, 0x56, 0x1c, 0xe3, 0xae, 0x8f, 0xeb, 0x0c, 0x61, 0xd4, 0xbc, 0x21, - 0x06, 0x2c, 0xc3, 0x1a, 0x87, 0x68, 0x3c, 0x6f, 0x19, 0x91, 0x4e, 0x3f, - 0x9c, 0xef, 0x9b, 0x11, 0x8c, 0x33, 0xf6, 0x31, 0xaf, 0xdf, 0x18, 0x3a, - 0x6f, 0xf5, 0x73, 0xd8, 0x4f, 0xc7, 0xc4, 0x57, 0xfb, 0x46, 0xc7, 0x91, - 0x88, 0x4c, 0xc0, 0x87, 0xbe, 0xba, 0x56, 0xf6, 0x6b, 0x8a, 0x4e, 0xc0, - 0x88, 0x73, 0x9c, 0x6c, 0xb0, 0xdd, 0xe1, 0x18, 0x59, 0xf6, 0x37, 0xa2, - 0x67, 0x20, 0xc7, 0x6a, 0xe0, 0xef, 0x76, 0xf6, 0x57, 0xe0, 0xb3, 0x63, - 0xd1, 0x11, 0xf6, 0x39, 0x67, 0xa9, 0x78, 0x93, 0x9f, 0x3e, 0xdd, 0x90, - 0x99, 0x55, 0x42, 0x6c, 0x3f, 0x04, 0x3e, 0x37, 0x2b, 0x70, 0x22, 0x63, - 0x61, 0x84, 0xeb, 0xd6, 0xd8, 0x36, 0xc9, 0xb6, 0x80, 0x69, 0x71, 0x7c, - 0xe8, 0x9d, 0x85, 0x95, 0x98, 0x58, 0xce, 0xcd, 0xef, 0x6b, 0xe7, 0x18, - 0x6e, 0x31, 0xa7, 0xf2, 0x9d, 0xcd, 0xee, 0x4d, 0xf1, 0x88, 0xba, 0xf2, - 0xf9, 0xb0, 0xd2, 0xc1, 0x36, 0x47, 0x6d, 0xc0, 0x21, 0x17, 0x5a, 0xd0, - 0xd4, 0x38, 0x8f, 0x86, 0xf7, 0x72, 0xc3, 0x4a, 0x77, 0xc1, 0x51, 0xba, - 0xe6, 0x3b, 0x14, 0x67, 0x5e, 0x55, 0x3a, 0x67, 0x65, 0xdc, 0x42, 0x3c, - 0x6b, 0x29, 0x8c, 0xf9, 0x07, 0x32, 0x5e, 0x27, 0xaa, 0xdc, 0x14, 0x6b, - 0x62, 0x3e, 0x54, 0x98, 0xdd, 0xca, 0x96, 0x79, 0x21, 0xd2, 0xc9, 0xb4, - 0xd2, 0x33, 0x0f, 0x2d, 0x6c, 0xdb, 0x5a, 0x6e, 0xea, 0x30, 0xb2, 0xab, - 0x4c, 0x1c, 0x77, 0xa3, 0xb8, 0x64, 0xf9, 0x70, 0x62, 0x55, 0x19, 0x54, - 0x53, 0xe1, 0x07, 0xe1, 0xcb, 0x16, 0xd4, 0x2a, 0x7e, 0xbf, 0xb6, 0x43, - 0xc5, 0x58, 0x7b, 0x8f, 0xd2, 0xc9, 0x3e, 0x01, 0xe6, 0xf9, 0x74, 0x2e, - 0x8d, 0x30, 0xb1, 0x53, 0x61, 0xc7, 0x22, 0x79, 0xee, 0xcd, 0xdb, 0x56, - 0x2c, 0xfe, 0xb8, 0xc4, 0x63, 0x8d, 0x11, 0x91, 0x7b, 0x53, 0x69, 0xc7, - 0xe2, 0x67, 0xb9, 0x0f, 0x7e, 0x53, 0xc5, 0xaf, 0xac, 0x00, 0x16, 0x77, - 0x58, 0xcc, 0xa9, 0x8e, 0x20, 0xdb, 0xcf, 0x78, 0xed, 0xf2, 0x37, 0xf4, - 0xae, 0xaf, 0xec, 0x43, 0x71, 0x0f, 0x46, 0xdd, 0x26, 0xc6, 0x5c, 0xdc, - 0x83, 0xed, 0x5c, 0xef, 0xbf, 0x06, 0xe4, 0xd7, 0xaf, 0xdd, 0x6a, 0xdb, - 0xc9, 0x38, 0x7d, 0xb6, 0xb9, 0xb8, 0xda, 0x5f, 0x0f, 0xd4, 0xb6, 0xe3, - 0x30, 0x73, 0xdc, 0x99, 0xbc, 0x1b, 0x59, 0xef, 0x79, 0x9d, 0xbe, 0x65, - 0xb6, 0x16, 0x7d, 0xab, 0xbc, 0x7d, 0xd3, 0xb7, 0xcd, 0x0a, 0xf1, 0x66, - 0x32, 0x88, 0xb3, 0xe6, 0x48, 0xa4, 0x12, 0x59, 0xcb, 0xcf, 0x7c, 0x5f, - 0xe0, 0xfc, 0xf9, 0xa4, 0x1f, 0x27, 0x93, 0x27, 0x90, 0xad, 0x01, 0xe6, - 0x72, 0x92, 0x57, 0xc6, 0xe2, 0x05, 0xfe, 0xd7, 0x57, 0x90, 0xeb, 0xb3, - 0xb8, 0x3e, 0x05, 0x67, 0x4c, 0x89, 0x69, 0x4b, 0x6b, 0x26, 0xbf, 0xf6, - 0x71, 0x3f, 0xeb, 0xdb, 0xc3, 0xc4, 0x27, 0xf0, 0x6e, 0x6e, 0x00, 0x3b, - 0x8b, 0xb1, 0xe0, 0x46, 0x8e, 0xc2, 0xd2, 0x96, 0xc6, 0x89, 0xe2, 0x6f, - 0x72, 0x3c, 0xad, 0x75, 0xe4, 0x8c, 0x4c, 0x1a, 0x89, 0x8b, 0x1d, 0x8a, - 0xec, 0x9f, 0xd6, 0xd6, 0xe4, 0x83, 0x88, 0xd6, 0x16, 0x9f, 0x57, 0xd8, - 0x5b, 0xb5, 0xc7, 0xa7, 0x14, 0xec, 0x8d, 0xc9, 0x67, 0x5b, 0xb5, 0x96, - 0x3c, 0xb4, 0x4a, 0x7b, 0x48, 0x3b, 0x3b, 0x65, 0xf4, 0xbd, 0xac, 0x24, - 0xa2, 0x53, 0x5e, 0x9f, 0x21, 0xad, 0x35, 0x1f, 0xe2, 0x7a, 0xe2, 0xcc, - 0x09, 0xb4, 0x2a, 0xfb, 0x69, 0xed, 0x57, 0x7c, 0x70, 0xd1, 0xeb, 0xf3, - 0xb4, 0x16, 0xcf, 0xcb, 0x76, 0xc3, 0x8a, 0x2a, 0x21, 0xdc, 0x9b, 0xd4, - 0xb0, 0xa6, 0x45, 0x34, 0x76, 0x25, 0x8d, 0xc5, 0x2e, 0x7f, 0x04, 0xc7, - 0xc9, 0x05, 0xe2, 0xce, 0xf9, 0xc3, 0x96, 0x31, 0x74, 0x15, 0xfc, 0x88, - 0xd6, 0x38, 0x38, 0xe2, 0x86, 0xf0, 0x33, 0xe2, 0xbf, 0xdb, 0xd2, 0x31, - 0xe6, 0x1a, 0xf1, 0x5f, 0x20, 0x91, 0x3a, 0xc5, 0x9c, 0x2d, 0x91, 0x03, - 0x47, 0x0a, 0x4d, 0xf1, 0x53, 0x30, 0x06, 0xbb, 0xc8, 0x01, 0xad, 0x5d, - 0xc6, 0x00, 0x5d, 0xb5, 0xc9, 0x9d, 0x42, 0x03, 0x72, 0xe4, 0x43, 0x97, - 0xc7, 0xab, 0x61, 0xa5, 0xb3, 0xf0, 0x4b, 0x6a, 0x6b, 0x37, 0xf1, 0x85, - 0xea, 0x88, 0x19, 0x44, 0xaa, 0x36, 0x8a, 0xf3, 0xc4, 0x4a, 0xb6, 0xae, - 0x8c, 0xb9, 0x94, 0xf9, 0x7c, 0x87, 0xcf, 0x7b, 0x94, 0xcd, 0xf3, 0x51, - 0xfc, 0xcc, 0xfa, 0x42, 0x38, 0x75, 0x95, 0x6c, 0x0b, 0xac, 0x68, 0xd7, - 0x70, 0xf5, 0x85, 0x72, 0x7c, 0xfc, 0x42, 0x18, 0x9f, 0xbd, 0x40, 0x7e, - 0xbb, 0x68, 0x2f, 0x87, 0x10, 0xa9, 0x36, 0x21, 0x0a, 0x56, 0x2b, 0xde, - 0xab, 0x89, 0x45, 0xaf, 0x40, 0x6a, 0xa3, 0xa3, 0xed, 0xce, 0x19, 0x43, - 0x83, 0x48, 0x38, 0xe7, 0xbc, 0xbd, 0x70, 0xb4, 0xb5, 0xf9, 0xf3, 0x02, - 0x3b, 0x8a, 0x7b, 0x11, 0xb4, 0x3b, 0xb5, 0xb7, 0x98, 0x9b, 0xcb, 0x5e, - 0x6e, 0x3a, 0xb5, 0x75, 0xf9, 0xfb, 0xfd, 0x28, 0x2f, 0x3e, 0x53, 0xed, - 0x8c, 0x36, 0x96, 0x33, 0x7a, 0x27, 0xb9, 0xbe, 0x01, 0xaf, 0x6f, 0x46, - 0x4b, 0x70, 0xef, 0x97, 0x4a, 0xb9, 0xa9, 0xb4, 0x1f, 0xe2, 0x3e, 0x33, - 0xf7, 0xde, 0x3e, 0x3e, 0xc4, 0x3d, 0x96, 0xf3, 0x0d, 0xdf, 0x36, 0xdf, - 0x30, 0xe7, 0x7b, 0x79, 0xc5, 0x7c, 0x07, 0x56, 0xcc, 0x77, 0x60, 0xc5, - 0x7c, 0x29, 0x72, 0xf5, 0x1f, 0xc4, 0x48, 0x5d, 0x71, 0x6c, 0xd5, 0x1e, - 0xbc, 0x6d, 0xee, 0x41, 0xce, 0x7d, 0x54, 0x2c, 0x65, 0x8a, 0xe3, 0x54, - 0xda, 0xfb, 0x57, 0xcc, 0xbd, 0x9f, 0x73, 0x2f, 0x8f, 0xa3, 0x53, 0x8b, - 0x84, 0xd8, 0x66, 0x09, 0xa1, 0xda, 0xa6, 0xde, 0x89, 0xe6, 0x4c, 0x27, - 0xb1, 0x53, 0x8e, 0xc4, 0xa2, 0x0f, 0xe6, 0x70, 0xbd, 0x3f, 0x80, 0xa5, - 0x9a, 0x65, 0x6e, 0x54, 0x96, 0xfe, 0xbe, 0xa4, 0x80, 0x5a, 0xff, 0x6a, - 0xae, 0x9a, 0x63, 0xc4, 0xf4, 0x01, 0x45, 0x88, 0x73, 0x1b, 0x13, 0x83, - 0x7e, 0x24, 0xfa, 0xaa, 0x60, 0x12, 0x43, 0x81, 0x12, 0x17, 0x56, 0xf6, - 0x79, 0xd9, 0xeb, 0x53, 0xf0, 0xfa, 0x08, 0xf1, 0xee, 0x86, 0x0f, 0xc5, - 0x1b, 0x2d, 0x75, 0xf8, 0x29, 0x39, 0xf9, 0x5a, 0x61, 0x59, 0x57, 0xa4, - 0x6e, 0xc0, 0x77, 0xce, 0x0a, 0x32, 0xa6, 0x91, 0x7d, 0xc1, 0xaf, 0xf4, - 0x27, 0x60, 0x4c, 0xd9, 0xe6, 0xc7, 0x2b, 0x49, 0x3c, 0x52, 0x0e, 0xa3, - 0xf7, 0xb0, 0x92, 0x4d, 0x57, 0xc0, 0x70, 0xd6, 0x28, 0xd9, 0x94, 0x06, - 0xc9, 0x1b, 0xb5, 0xe9, 0xb4, 0x69, 0x64, 0xaf, 0xf2, 0x65, 0x75, 0xfa, - 0x4e, 0x31, 0xa8, 0x1c, 0x23, 0x8c, 0x27, 0xdd, 0x0b, 0x58, 0x0c, 0x34, - 0x50, 0x9f, 0xa5, 0x76, 0x72, 0xe0, 0x05, 0x8d, 0x35, 0x2d, 0x44, 0x22, - 0xaa, 0x38, 0xe8, 0xfa, 0xce, 0x37, 0x42, 0x20, 0xd8, 0x16, 0xc0, 0x3b, - 0xe6, 0xa8, 0x55, 0x8f, 0x4d, 0xb8, 0xdc, 0xca, 0x3d, 0x58, 0xa5, 0x22, - 0x32, 0xb7, 0x72, 0xac, 0x08, 0xc7, 0xfa, 0xb3, 0x10, 0xaa, 0xea, 0xa0, - 0x36, 0xab, 0xd8, 0xeb, 0x6a, 0x4a, 0x97, 0x2b, 0xb1, 0x6b, 0x46, 0x4e, - 0xe1, 0x14, 0xb5, 0x82, 0x35, 0xec, 0x8c, 0xaa, 0x6c, 0x99, 0x0d, 0xa1, - 0x7c, 0xe6, 0x13, 0xf1, 0x18, 0xb5, 0x2f, 0xbd, 0x41, 0x08, 0x33, 0x19, - 0x82, 0xc6, 0x79, 0x86, 0xc9, 0xe7, 0xea, 0xb6, 0x5a, 0x5c, 0xfb, 0x3a, - 0xb5, 0xe9, 0xdb, 0x21, 0xf8, 0x67, 0x42, 0x08, 0xce, 0x28, 0x78, 0xa7, - 0x3d, 0x84, 0xfa, 0x39, 0xf9, 0x5b, 0x41, 0xa3, 0x79, 0x14, 0x07, 0x75, - 0x3f, 0x63, 0xfc, 0x2b, 0xf4, 0xeb, 0x0d, 0x98, 0xa4, 0x36, 0x3f, 0xea, - 0x6a, 0xa8, 0x3a, 0x4a, 0x2d, 0xb0, 0x85, 0x38, 0x49, 0xfc, 0x1f, 0x64, - 0x8c, 0x32, 0xde, 0x0b, 0x56, 0x36, 0x1a, 0x42, 0x00, 0xc1, 0x39, 0x23, - 0x3d, 0xc9, 0xe8, 0x52, 0x53, 0xaa, 0xb2, 0x7d, 0x96, 0xb5, 0xd7, 0x36, - 0x7b, 0xeb, 0xfd, 0x42, 0x7c, 0x9a, 0x6c, 0xea, 0x5b, 0xa0, 0x06, 0x8f, - 0xc4, 0x62, 0x99, 0x7e, 0x05, 0x58, 0x73, 0x96, 0x76, 0x64, 0xe6, 0xbf, - 0x44, 0x98, 0xe3, 0x1c, 0xd9, 0x20, 0x30, 0x6e, 0x65, 0x23, 0x01, 0x18, - 0x37, 0x86, 0x50, 0x87, 0x0f, 0x9e, 0x17, 0x42, 0xb4, 0x57, 0xe3, 0x1d, - 0xcb, 0x18, 0x34, 0xfd, 0x02, 0x3f, 0x4e, 0x66, 0x87, 0x22, 0x30, 0x86, - 0x7f, 0xad, 0x44, 0xf1, 0xf1, 0x94, 0x91, 0xbe, 0xa8, 0x04, 0x51, 0x39, - 0x67, 0xea, 0x5b, 0x94, 0x30, 0xca, 0x17, 0xc2, 0x58, 0x7d, 0x36, 0x88, - 0xc0, 0x4c, 0x18, 0xc1, 0x69, 0xf3, 0xe2, 0x2e, 0x78, 0xe3, 0x2c, 0x0e, - 0xa1, 0x19, 0xd5, 0xb3, 0x66, 0xf4, 0x5f, 0x20, 0xb1, 0x1d, 0x86, 0xba, - 0x10, 0x45, 0x7d, 0xc1, 0x44, 0x35, 0xf3, 0x7d, 0xf9, 0xac, 0xcc, 0xb3, - 0x8e, 0xb0, 0xe9, 0xe3, 0xda, 0x1c, 0x65, 0xab, 0x57, 0x37, 0x3a, 0xf9, - 0xe9, 0x56, 0x3a, 0xe6, 0xe5, 0x9e, 0x29, 0x28, 0xe3, 0xb3, 0x8b, 0xd6, - 0x4d, 0xb1, 0x2f, 0x26, 0xeb, 0x44, 0x19, 0x02, 0x76, 0x8f, 0xf2, 0xc0, - 0x3c, 0x8b, 0x90, 0xa7, 0xef, 0x65, 0x4a, 0xc0, 0x2e, 0x6a, 0xfb, 0x25, - 0x6a, 0xfb, 0x89, 0x92, 0xb6, 0x57, 0x51, 0xdb, 0x17, 0xfe, 0x4f, 0x6d, - 0x67, 0xbd, 0x9f, 0xf1, 0xe1, 0xbc, 0x19, 0xc2, 0x71, 0xab, 0x69, 0xb1, - 0x1e, 0x21, 0x54, 0xb7, 0xe9, 0xa8, 0x5e, 0xb0, 0xf0, 0x1c, 0xf7, 0x16, - 0x77, 0x15, 0xf5, 0xfd, 0x9b, 0x52, 0xf3, 0x4b, 0x5e, 0xed, 0x71, 0x77, - 0x59, 0x13, 0xc2, 0xd4, 0x2a, 0x55, 0xe9, 0xa1, 0x9e, 0x3f, 0x90, 0xbc, - 0x29, 0xe2, 0x31, 0x23, 0x4e, 0xce, 0xde, 0x38, 0x89, 0xa2, 0x46, 0xc4, - 0xa8, 0x97, 0x4b, 0xb5, 0x71, 0x1c, 0x73, 0x65, 0x4d, 0xeb, 0x64, 0x4d, - 0x53, 0x30, 0x12, 0x2b, 0x6a, 0xc4, 0xea, 0xbc, 0x6c, 0xd7, 0x51, 0x4f, - 0x9d, 0x5c, 0xd7, 0x16, 0xc1, 0x31, 0x6a, 0xa4, 0x4b, 0x9f, 0xb3, 0x9d, - 0xe3, 0x6d, 0x9b, 0x35, 0xb2, 0xdb, 0x99, 0x9f, 0xf3, 0xc4, 0xc5, 0x14, - 0xab, 0xc3, 0x89, 0x1a, 0x6a, 0x67, 0x73, 0x08, 0x13, 0xd4, 0xcb, 0xf3, - 0xf4, 0x10, 0x2f, 0xb1, 0xdf, 0xb8, 0x6b, 0x44, 0x5f, 0x22, 0xaf, 0xc7, - 0x4b, 0x9a, 0xf9, 0x12, 0x7d, 0xc3, 0x38, 0xf3, 0xf4, 0x53, 0x3e, 0x7b, - 0xcd, 0x35, 0x1c, 0xe9, 0x1f, 0xfc, 0x9e, 0x7f, 0x30, 0xe2, 0x7e, 0x45, - 0x7a, 0x88, 0x08, 0xde, 0x68, 0x91, 0x58, 0x24, 0xc6, 0x6f, 0xe9, 0xa7, - 0xaa, 0x7c, 0x6b, 0xf6, 0xba, 0xc8, 0xc7, 0xca, 0x55, 0xc9, 0xbf, 0xb1, - 0xa4, 0xc4, 0x93, 0x10, 0x65, 0x76, 0x98, 0x5e, 0xcb, 0x8c, 0x7f, 0x84, - 0x18, 0x71, 0x1b, 0xe1, 0xb3, 0x30, 0xfc, 0x67, 0xb7, 0xa8, 0x9e, 0x8f, - 0x5d, 0x90, 0x7e, 0x8b, 0x79, 0x9a, 0x32, 0x7b, 0xa7, 0x94, 0x58, 0x66, - 0x40, 0x91, 0xcf, 0x75, 0x94, 0x9f, 0x5d, 0x22, 0x77, 0x23, 0xe4, 0x6e, - 0x1d, 0x5e, 0xbf, 0x8d, 0xbf, 0xd4, 0x55, 0xdf, 0x00, 0xf9, 0x9b, 0xad, - 0x1b, 0xe9, 0xf7, 0x7f, 0x85, 0x7b, 0x87, 0x24, 0x7f, 0xd9, 0xe6, 0xc7, - 0xb3, 0x49, 0xec, 0x2c, 0x83, 0x91, 0x79, 0x4c, 0xc9, 0x3a, 0xe4, 0x71, - 0xaa, 0x4c, 0xc9, 0xd2, 0x31, 0x7d, 0xc9, 0xdf, 0x37, 0xf9, 0xb6, 0x9f, - 0xfc, 0xed, 0xab, 0xbb, 0x9d, 0xbf, 0x47, 0x38, 0x86, 0x8a, 0x27, 0xdc, - 0xe3, 0x98, 0x0b, 0x04, 0x11, 0x99, 0x09, 0x20, 0x34, 0xa3, 0xa2, 0x92, - 0x5c, 0x09, 0xdb, 0xd9, 0x78, 0x08, 0x46, 0xfa, 0x35, 0x44, 0x90, 0x98, - 0xd2, 0xf0, 0xe7, 0x2d, 0x01, 0x9c, 0x89, 0x19, 0x99, 0xfd, 0x4a, 0x84, - 0x58, 0x1f, 0x61, 0x44, 0x46, 0x34, 0xea, 0x2b, 0xf2, 0x35, 0xd0, 0x1c, - 0x84, 0x36, 0x23, 0xb9, 0x2e, 0x0e, 0xfa, 0xec, 0x6c, 0x54, 0x23, 0x46, - 0x7f, 0x40, 0x6c, 0x5c, 0x99, 0x12, 0x62, 0x73, 0xbb, 0x79, 0xf1, 0x3d, - 0xbf, 0x41, 0xdd, 0x53, 0x89, 0xd3, 0xe2, 0xf8, 0x15, 0x33, 0x1a, 0x82, - 0x47, 0xbd, 0xf1, 0x6f, 0xbc, 0xce, 0x28, 0x3e, 0x75, 0x55, 0x65, 0x2b, - 0x71, 0x40, 0x6e, 0x45, 0xe6, 0xa9, 0x7d, 0x87, 0x93, 0x46, 0x7a, 0x8b, - 0xd2, 0xe4, 0x34, 0xf3, 0xbb, 0x2f, 0x19, 0x8b, 0xf6, 0xf3, 0x9d, 0xf7, - 0x0b, 0x45, 0x0e, 0xd7, 0x9b, 0xbb, 0xf1, 0x17, 0xe4, 0x70, 0x95, 0xf9, - 0x14, 0x9e, 0xf4, 0xf4, 0x88, 0x38, 0x98, 0x2e, 0x27, 0xb7, 0x1d, 0x65, - 0x17, 0x71, 0xbf, 0x73, 0x9e, 0xba, 0x32, 0xd3, 0xee, 0x69, 0x51, 0xc8, - 0xec, 0x54, 0x7a, 0xe7, 0xbb, 0x3d, 0x0f, 0xb5, 0x7d, 0xd6, 0x87, 0xd7, - 0xad, 0x4d, 0xf4, 0x2b, 0x69, 0x65, 0xfb, 0xbc, 0xc4, 0x7c, 0x8f, 0xf2, - 0x4d, 0xe2, 0x3f, 0x7a, 0x97, 0x8a, 0x39, 0x6b, 0x93, 0x12, 0xf4, 0xf0, - 0x1f, 0x80, 0x93, 0x29, 0x62, 0xdf, 0x6f, 0xc7, 0xac, 0x73, 0x2b, 0xb0, - 0xdf, 0x7d, 0x07, 0x5f, 0x23, 0xf5, 0x03, 0x45, 0x2d, 0xd7, 0x3b, 0x99, - 0xaf, 0x67, 0x4a, 0x18, 0x7f, 0x92, 0xed, 0x81, 0x19, 0x68, 0xe5, 0xc4, - 0x71, 0xcf, 0x54, 0x18, 0xd3, 0x1e, 0x56, 0x04, 0x5e, 0x65, 0x4d, 0xc8, - 0x27, 0x0d, 0x6b, 0xbf, 0x62, 0xa4, 0xbb, 0x95, 0x44, 0x76, 0x4d, 0xa9, - 0x1e, 0xde, 0xcb, 0x9a, 0x86, 0xbb, 0xa8, 0x0b, 0x16, 0xb4, 0x10, 0xf1, - 0xfd, 0x6f, 0xac, 0x4f, 0xff, 0x51, 0xaa, 0x87, 0xc9, 0x7c, 0x39, 0xaa, - 0x5b, 0xa8, 0xef, 0xc4, 0x73, 0x97, 0xc4, 0x33, 0x3d, 0xc4, 0x18, 0xeb, - 0xff, 0x4e, 0xe2, 0x79, 0x75, 0x9b, 0x91, 0xed, 0xa4, 0x77, 0xf6, 0xad, - 0x8f, 0x10, 0xab, 0x71, 0xfa, 0xd5, 0x31, 0x74, 0x70, 0xae, 0xf4, 0xac, - 0x11, 0xe9, 0x20, 0x07, 0x54, 0xf6, 0x79, 0x89, 0x7d, 0x96, 0x6a, 0xa5, - 0xaf, 0x0e, 0xe1, 0x59, 0xf6, 0x31, 0x93, 0x8e, 0xa7, 0x15, 0x92, 0x03, - 0x13, 0x48, 0x64, 0x24, 0x07, 0x9c, 0x55, 0xad, 0xf4, 0xf8, 0x92, 0x03, - 0xc4, 0xa0, 0x4b, 0x0c, 0x16, 0x79, 0x30, 0x28, 0x79, 0x50, 0x45, 0x0f, - 0xb1, 0x40, 0x0f, 0x51, 0x61, 0x47, 0xc9, 0x01, 0xc9, 0x89, 0xa2, 0x8f, - 0xe8, 0x2c, 0xf1, 0x60, 0x8b, 0x37, 0x9f, 0x4a, 0xed, 0x0b, 0xa3, 0x69, - 0xda, 0xd0, 0x55, 0xe5, 0x3f, 0xc5, 0x2e, 0xd3, 0x5c, 0xdc, 0x4b, 0x2f, - 0xf0, 0x59, 0x5b, 0x8c, 0x79, 0x0f, 0x63, 0xdd, 0x42, 0x79, 0x40, 0xe2, - 0xbc, 0x7e, 0x3a, 0x8c, 0xea, 0x69, 0xc9, 0x83, 0xec, 0x24, 0xf5, 0x6f, - 0xc8, 0xf2, 0xfd, 0x13, 0xf1, 0x1f, 0x25, 0x2e, 0x54, 0xa5, 0x8b, 0x63, - 0x54, 0xcd, 0xe8, 0x68, 0x9d, 0x36, 0x06, 0x17, 0x70, 0x4d, 0xbc, 0x1a, - 0x33, 0x33, 0x87, 0x98, 0xff, 0x3d, 0xc9, 0x18, 0xf7, 0x4a, 0xc7, 0xbd, - 0xb7, 0xc6, 0xf0, 0x38, 0xe1, 0xf4, 0x5b, 0xe1, 0x92, 0xaf, 0xd6, 0xd0, - 0xef, 0x02, 0x7b, 0x5c, 0x1a, 0x5b, 0xd3, 0xb7, 0x36, 0x88, 0xeb, 0x38, - 0x49, 0xf4, 0x0f, 0xe8, 0x0e, 0xf3, 0x1f, 0xc2, 0xde, 0xd2, 0x3b, 0x45, - 0xbf, 0xfd, 0xe3, 0xd2, 0x79, 0xf2, 0x17, 0xfe, 0xe2, 0xdf, 0xbf, 0x55, - 0x97, 0xcf, 0x97, 0xfd, 0xc4, 0xe0, 0x66, 0x62, 0xb0, 0x9b, 0x39, 0xda, - 0x6b, 0x91, 0xdf, 0xcc, 0x67, 0x56, 0x0d, 0x51, 0x0f, 0x9b, 0xfa, 0x2a, - 0xa9, 0x6b, 0x87, 0xa9, 0x51, 0x3f, 0x37, 0xcb, 0xe9, 0xb7, 0x1d, 0xfa, - 0xed, 0x0e, 0x6a, 0x68, 0x27, 0xf5, 0x53, 0x62, 0x2b, 0x4d, 0x1c, 0x69, - 0x4a, 0x9a, 0x1e, 0x36, 0x90, 0xa4, 0xd7, 0xae, 0x5b, 0xf6, 0xda, 0x32, - 0x4e, 0xe9, 0xaf, 0x8d, 0xb8, 0x2c, 0xb5, 0x4f, 0x32, 0x0f, 0x8b, 0x35, - 0x9b, 0xa0, 0xda, 0x9b, 0x14, 0xd5, 0x96, 0xe7, 0x09, 0x15, 0xdf, 0xa5, - 0xd6, 0x2e, 0xed, 0x90, 0xe7, 0x0a, 0xae, 0x8b, 0x6d, 0x11, 0x33, 0x16, - 0x3d, 0x4e, 0x5c, 0x1d, 0xfb, 0x9d, 0x73, 0x46, 0x11, 0x6f, 0xa3, 0xae, - 0x7a, 0xcb, 0x33, 0x4b, 0x7d, 0xd8, 0x74, 0x0b, 0x6f, 0x1a, 0x9e, 0x68, - 0x89, 0x12, 0x8f, 0x12, 0x6b, 0x1a, 0xf2, 0x2f, 0x96, 0xe3, 0xd5, 0x17, - 0xc3, 0x78, 0xe5, 0x45, 0x21, 0xc6, 0x93, 0xe0, 0x69, 0x46, 0x6a, 0xec, - 0x46, 0xbc, 0xac, 0xc7, 0xa2, 0xcf, 0x7a, 0x9e, 0xd5, 0xa1, 0x67, 0x35, - 0x06, 0x2f, 0xe0, 0x26, 0xf5, 0x4b, 0x72, 0x3a, 0x41, 0xbe, 0x15, 0xb1, - 0xe8, 0x79, 0xdb, 0x1a, 0x0d, 0x57, 0x88, 0xbf, 0x6a, 0xe2, 0xef, 0x37, - 0xd4, 0xdd, 0x6b, 0x25, 0xdd, 0x5d, 0x9b, 0x27, 0x1f, 0xdb, 0x42, 0xe8, - 0x96, 0x6b, 0x21, 0x0e, 0x47, 0x6f, 0xe1, 0x50, 0x88, 0x0f, 0xb8, 0xe7, - 0x17, 0x2c, 0x23, 0xbe, 0x99, 0x78, 0x9c, 0xb3, 0x0c, 0xa7, 0x83, 0xde, - 0x75, 0xd4, 0xc3, 0x24, 0xf5, 0x37, 0x26, 0x71, 0x49, 0x1c, 0x32, 0x27, - 0x87, 0xd9, 0xe7, 0x3c, 0xfb, 0x4c, 0x94, 0xbc, 0xeb, 0xdb, 0x48, 0xa4, - 0xa5, 0x77, 0x8d, 0x12, 0x83, 0x87, 0x3d, 0xef, 0x2a, 0xbd, 0xaa, 0xf4, - 0xa9, 0x32, 0xce, 0x76, 0x2f, 0xce, 0xae, 0x5b, 0x38, 0xa4, 0x86, 0xd5, - 0x48, 0xfc, 0x7d, 0x03, 0x13, 0xcf, 0x57, 0xa1, 0xda, 0xbc, 0x07, 0x97, - 0x33, 0xdf, 0x50, 0x23, 0x26, 0xf4, 0x7a, 0xbb, 0x88, 0xc7, 0x9d, 0x85, - 0x14, 0x5c, 0xf7, 0x2d, 0xe1, 0xd6, 0x19, 0xce, 0x05, 0xcf, 0x7f, 0x0e, - 0xb2, 0xd6, 0xdc, 0x14, 0xbe, 0x98, 0x71, 0xb1, 0x9f, 0x1e, 0xac, 0xc9, - 0x5f, 0xf4, 0x72, 0x1b, 0xf3, 0xbf, 0x14, 0xa8, 0x2d, 0xae, 0x53, 0xa5, - 0x7f, 0x1b, 0x23, 0xe7, 0xc6, 0xcd, 0xa2, 0x97, 0x8b, 0xe5, 0xaf, 0x06, - 0xa4, 0xa6, 0xfb, 0xda, 0xe4, 0xb8, 0x69, 0x6a, 0xc8, 0xf2, 0xd8, 0x5f, - 0xea, 0xf2, 0x18, 0x31, 0x38, 0x2a, 0x7d, 0x15, 0x7d, 0x09, 0xcf, 0xe5, - 0x2b, 0x34, 0x75, 0xd8, 0x0f, 0x53, 0xb6, 0x39, 0xca, 0x03, 0x5c, 0x83, - 0x66, 0x0e, 0x2b, 0x69, 0x9e, 0x3b, 0x0f, 0x11, 0x5f, 0xdd, 0xac, 0xc3, - 0x57, 0xad, 0x66, 0x72, 0x98, 0xf5, 0x89, 0xb5, 0xf8, 0xb0, 0xb9, 0x7c, - 0x7e, 0x93, 0x35, 0x99, 0x35, 0xcc, 0xad, 0x64, 0xfd, 0xee, 0x61, 0xcd, - 0xe6, 0x28, 0xcc, 0xe9, 0x67, 0x31, 0xd1, 0xb8, 0xb6, 0xcd, 0x18, 0xdc, - 0xe6, 0x0f, 0x21, 0x47, 0xbc, 0x1f, 0x63, 0x1d, 0x72, 0xb9, 0xa7, 0xd3, - 0x05, 0x23, 0x95, 0xc5, 0x18, 0xb6, 0x71, 0x4f, 0x79, 0xde, 0x71, 0xfe, - 0x2e, 0x56, 0x3c, 0x0f, 0xef, 0x65, 0x7d, 0x9b, 0x2c, 0x71, 0xfb, 0x43, - 0x24, 0x2c, 0xc9, 0xed, 0x45, 0xd6, 0xb7, 0x49, 0x8f, 0xdb, 0x46, 0x4a, - 0xf2, 0xb9, 0xac, 0x54, 0xd7, 0x3e, 0x82, 0xe4, 0xf0, 0xed, 0x35, 0x4d, - 0xe2, 0xd9, 0x0e, 0x4a, 0x1f, 0xeb, 0xba, 0xb2, 0x26, 0xc9, 0x5a, 0xb4, - 0x5c, 0x97, 0x34, 0x79, 0x77, 0x90, 0x69, 0x9c, 0x3a, 0x28, 0x7c, 0xc5, - 0xfb, 0x87, 0x8b, 0xef, 0xfa, 0xc3, 0xa9, 0xd4, 0x7d, 0xc8, 0x44, 0xce, - 0x6a, 0xd8, 0xe1, 0x36, 0xf4, 0x85, 0x6c, 0xf0, 0x1d, 0x05, 0xd6, 0x1f, - 0x6b, 0xc8, 0xdc, 0x76, 0xff, 0xf0, 0x41, 0x4e, 0xd3, 0xaa, 0xa7, 0xee, - 0x96, 0xef, 0xe0, 0x93, 0xdc, 0x1d, 0xef, 0x1f, 0xd2, 0xbf, 0xef, 0xfe, - 0xe1, 0x59, 0xf2, 0x63, 0xa2, 0x78, 0xff, 0xe0, 0x7c, 0xa7, 0xc5, 0x8f, - 0xb9, 0x3a, 0x1c, 0x78, 0xaf, 0x5d, 0xc5, 0xd5, 0x9c, 0x11, 0x79, 0x19, - 0x07, 0x30, 0xe0, 0xdd, 0x35, 0xf0, 0xcc, 0x6f, 0x0f, 0xe1, 0xd7, 0xed, - 0xf2, 0xae, 0x21, 0x25, 0xd7, 0x38, 0xc9, 0xe5, 0x43, 0xa3, 0xde, 0x6c, - 0x61, 0x2d, 0xd8, 0xb7, 0x51, 0xc1, 0x03, 0xc9, 0x7b, 0x3c, 0x6c, 0x4f, - 0x16, 0x8c, 0x74, 0x94, 0xcf, 0xd6, 0x4d, 0xc9, 0x1a, 0xf9, 0x30, 0xcf, - 0x86, 0xd0, 0x1a, 0xed, 0x5e, 0x4d, 0xb8, 0x4d, 0x91, 0x0f, 0x15, 0xc3, - 0x39, 0x09, 0x79, 0x1f, 0x90, 0xb8, 0xe8, 0x57, 0x8c, 0xc5, 0x77, 0xfd, - 0x46, 0xaa, 0xde, 0xc3, 0xcc, 0xc3, 0x3c, 0xa7, 0xc9, 0xbf, 0xbd, 0xf2, - 0x8c, 0x87, 0x6d, 0x1c, 0xf3, 0xd2, 0x46, 0x79, 0xee, 0xfc, 0x54, 0x64, - 0x57, 0x19, 0xce, 0x92, 0xa2, 0x31, 0x37, 0xa0, 0x3e, 0x49, 0x0d, 0x7f, - 0x98, 0x1a, 0x2e, 0xcf, 0x08, 0xbd, 0x3c, 0x23, 0x34, 0x2d, 0xc6, 0xfd, - 0x46, 0xe6, 0x06, 0xf5, 0x8e, 0x63, 0xf6, 0xf5, 0x2a, 0x46, 0xef, 0x02, - 0xf5, 0x7f, 0xbf, 0x52, 0x1c, 0x73, 0x4d, 0x69, 0xcc, 0x7b, 0xf3, 0x9a, - 0xb2, 0xd9, 0x05, 0x75, 0x07, 0xd1, 0x3d, 0x16, 0xb5, 0xa3, 0x50, 0x4e, - 0x8e, 0x99, 0x72, 0xcd, 0x8c, 0xad, 0x95, 0xb1, 0x29, 0xf8, 0xb0, 0x45, - 0xbe, 0xdb, 0x2a, 0xe3, 0x70, 0x2a, 0xec, 0x14, 0xb5, 0xf7, 0xb9, 0x60, - 0x49, 0xbf, 0x7c, 0xfd, 0xd6, 0x2a, 0x38, 0x75, 0xa8, 0x0e, 0x98, 0xb5, - 0x18, 0xd7, 0x51, 0x19, 0x36, 0x9b, 0x91, 0xd3, 0x83, 0xe8, 0xb7, 0x7e, - 0x2b, 0xa8, 0x93, 0x7c, 0x1f, 0x78, 0xec, 0x79, 0x9e, 0xd7, 0xcd, 0xeb, - 0x88, 0x25, 0x9f, 0xc6, 0x19, 0x7d, 0x08, 0xe5, 0xac, 0xa5, 0xaf, 0x78, - 0x7a, 0x62, 0x13, 0xcf, 0x0a, 0x31, 0x64, 0xcb, 0x5a, 0x77, 0xdb, 0xd8, - 0xf2, 0xfe, 0xe1, 0x7d, 0x91, 0x2d, 0x8e, 0xe1, 0xec, 0xb1, 0x32, 0x8c, - 0xeb, 0x4b, 0xdd, 0xdd, 0x47, 0xdd, 0xa5, 0xb7, 0xfc, 0x5a, 0x39, 0x75, - 0x77, 0xb7, 0xf5, 0x6d, 0x3c, 0x46, 0x8e, 0x57, 0x98, 0x9f, 0x88, 0xc7, - 0xeb, 0xe4, 0x98, 0xd4, 0xd7, 0xaa, 0x95, 0xe3, 0xff, 0x33, 0xc7, 0x94, - 0x73, 0xc8, 0x7a, 0x78, 0x59, 0x48, 0x6f, 0x56, 0x61, 0x0f, 0x2b, 0xdb, - 0xc8, 0xa9, 0x45, 0x96, 0xde, 0xef, 0x92, 0x4f, 0x4b, 0xcc, 0x4f, 0xe3, - 0x1d, 0xf8, 0xd4, 0x48, 0x3e, 0xed, 0x5a, 0xc1, 0xa7, 0xe3, 0xe4, 0x53, - 0x2f, 0xf9, 0xd4, 0xd2, 0xf6, 0x27, 0xd4, 0x15, 0x21, 0x82, 0x6d, 0x37, - 0xc5, 0x9b, 0x9e, 0xff, 0x95, 0x9e, 0x37, 0xad, 0x74, 0xcd, 0x4b, 0x7d, - 0xaa, 0xa4, 0x27, 0xee, 0xa1, 0x1f, 0x06, 0x06, 0xc8, 0xa7, 0xc7, 0x4d, - 0xd1, 0xb8, 0x2f, 0x69, 0xa4, 0x16, 0xe9, 0x6b, 0x7a, 0xc8, 0xa9, 0xb7, - 0xc8, 0xa9, 0xb1, 0x42, 0x51, 0xa7, 0x0e, 0x73, 0xdd, 0xf7, 0x53, 0xa7, - 0x7a, 0x0a, 0x52, 0xdb, 0x1c, 0xe2, 0x3f, 0x84, 0x4f, 0xc9, 0xa9, 0xf9, - 0xa4, 0xa7, 0x53, 0xd6, 0x6f, 0x90, 0x18, 0x3a, 0x2f, 0xf9, 0x44, 0x9d, - 0x72, 0x0b, 0x4d, 0xd6, 0x79, 0xae, 0x69, 0xd2, 0x35, 0x6e, 0x74, 0x93, - 0x53, 0x81, 0x76, 0xe3, 0xe2, 0x55, 0x62, 0x37, 0x14, 0x83, 0x1e, 0xb1, - 0xe5, 0x9a, 0x58, 0x63, 0x59, 0x27, 0x8f, 0x13, 0xff, 0xdd, 0xd4, 0x8c, - 0xde, 0x82, 0x8d, 0x43, 0x85, 0x95, 0x7b, 0xca, 0x3a, 0x74, 0xc7, 0x7d, - 0x19, 0x0d, 0xdd, 0xb9, 0x9d, 0xf5, 0xea, 0x8e, 0xed, 0x92, 0xaf, 0x7a, - 0x48, 0xf2, 0x75, 0xd4, 0xfd, 0x61, 0xe0, 0xce, 0xef, 0xc8, 0xfb, 0x33, - 0x21, 0x4e, 0x5b, 0xf2, 0xfe, 0x41, 0xfa, 0x1e, 0xfa, 0x68, 0x4b, 0xde, - 0xa1, 0x75, 0x44, 0x55, 0x18, 0x91, 0x47, 0xf1, 0xb9, 0xc8, 0xd6, 0x39, - 0xf1, 0x80, 0x57, 0x23, 0x0d, 0xbd, 0x8f, 0xb5, 0x6e, 0xb1, 0x74, 0xce, - 0x9b, 0xcb, 0x09, 0xf1, 0x16, 0xeb, 0xd4, 0x69, 0x9e, 0xe9, 0x46, 0xf2, - 0x9f, 0x8b, 0xc5, 0x3a, 0x15, 0x63, 0xe6, 0xad, 0xfb, 0x48, 0x4f, 0xc7, - 0x4e, 0xf2, 0xd9, 0x44, 0x7e, 0xb9, 0x46, 0x51, 0x33, 0x4d, 0x21, 0x76, - 0x9b, 0xff, 0x2d, 0xfa, 0xbf, 0xf2, 0xae, 0x10, 0xd3, 0x8c, 0xe1, 0x8a, - 0x85, 0x03, 0x01, 0xc4, 0xfa, 0x6e, 0xb0, 0xae, 0x5f, 0xda, 0x68, 0x64, - 0xf2, 0x4a, 0xa2, 0x77, 0xab, 0x22, 0xbd, 0x9e, 0xaf, 0xb3, 0x8c, 0xef, - 0xb4, 0xd0, 0x1b, 0x7d, 0xc8, 0x0c, 0x06, 0xf9, 0xfd, 0x4d, 0xcb, 0xa0, - 0x7f, 0x16, 0xa2, 0x3f, 0x25, 0xc7, 0x10, 0xa2, 0xc3, 0x92, 0xe7, 0x80, - 0x31, 0x9e, 0x03, 0xb2, 0xa2, 0xc2, 0xbc, 0x42, 0x6d, 0x32, 0x32, 0x63, - 0x8a, 0xc9, 0xbe, 0x51, 0x78, 0x3a, 0xcb, 0x67, 0xda, 0x54, 0x04, 0x7f, - 0xed, 0xf9, 0xe7, 0x28, 0x35, 0xab, 0x01, 0x7f, 0xe3, 0xe9, 0x96, 0x8a, - 0x3d, 0xcf, 0x1b, 0x29, 0x55, 0x39, 0x88, 0xf7, 0x2d, 0x43, 0xff, 0x21, - 0xe3, 0xa6, 0xd6, 0x3c, 0xb7, 0x19, 0x51, 0x70, 0x8e, 0x6c, 0x9f, 0xbf, - 0x46, 0xd1, 0x58, 0x3b, 0xbe, 0xdf, 0x22, 0x6b, 0xf7, 0x10, 0xba, 0x9b, - 0xf7, 0xf3, 0xa3, 0xa2, 0x76, 0x46, 0x55, 0x76, 0xd0, 0x93, 0x54, 0xcf, - 0x54, 0x63, 0xef, 0x7a, 0x21, 0xd6, 0xae, 0x77, 0xc0, 0x33, 0x5f, 0xfc, - 0x02, 0x6b, 0xd0, 0x89, 0x1a, 0x23, 0x0d, 0xfc, 0x04, 0x3b, 0xe9, 0x65, - 0x53, 0x6d, 0x39, 0xe0, 0x1e, 0xb9, 0xc6, 0x9f, 0x60, 0xb3, 0xf4, 0xc0, - 0x56, 0xb5, 0xf4, 0x5b, 0x1e, 0x7e, 0x8b, 0x77, 0x48, 0x4c, 0xf5, 0xd1, - 0xac, 0x28, 0x37, 0x8d, 0xbe, 0x79, 0xd6, 0xdb, 0x4b, 0xb1, 0xbb, 0xf5, - 0x6f, 0xcd, 0x4b, 0x0f, 0x6c, 0x46, 0xb7, 0x28, 0x82, 0xb9, 0x78, 0x86, - 0xb9, 0x88, 0x39, 0x61, 0x5a, 0x86, 0x6a, 0x3b, 0xe6, 0x54, 0x2b, 0xc3, - 0xca, 0x83, 0xe4, 0x43, 0x5f, 0xb0, 0x9c, 0x1e, 0xc2, 0xa1, 0x7f, 0xf0, - 0xa1, 0xf2, 0xa8, 0xf4, 0x14, 0x21, 0x6a, 0x4d, 0x53, 0x2f, 0x4f, 0x17, - 0xd8, 0x97, 0x94, 0xfe, 0x83, 0x58, 0x3f, 0x7a, 0x53, 0x6c, 0xa6, 0xc7, - 0xdd, 0x5c, 0xf2, 0xb8, 0xbb, 0x66, 0xd3, 0xf4, 0xc0, 0x9a, 0x22, 0xef, - 0xd3, 0x52, 0x6d, 0x3c, 0x94, 0x3e, 0x28, 0x7d, 0x88, 0x5c, 0x83, 0x8e, - 0x6b, 0x49, 0x89, 0x5d, 0x1d, 0xa3, 0xed, 0x46, 0x24, 0x0b, 0x79, 0x7f, - 0x73, 0xbb, 0xbf, 0x80, 0x9e, 0xfe, 0x1d, 0xcf, 0x01, 0x7d, 0x07, 0x63, - 0x31, 0x82, 0x42, 0xd4, 0x26, 0xfd, 0xe8, 0xf3, 0xce, 0x73, 0x11, 0x3d, - 0x4d, 0xde, 0x5f, 0xa4, 0x4f, 0xf0, 0xf3, 0xdc, 0x7c, 0x90, 0x58, 0xfa, - 0xac, 0x65, 0xe4, 0x58, 0x3d, 0xb2, 0x93, 0xb5, 0x30, 0xac, 0xfb, 0xa9, - 0xab, 0x57, 0x72, 0x0f, 0xb2, 0x9e, 0xfb, 0xda, 0x23, 0x3c, 0x03, 0x34, - 0xce, 0x64, 0x45, 0x3d, 0xfd, 0xe0, 0x37, 0x78, 0xee, 0xad, 0x69, 0x8b, - 0xd3, 0x6f, 0x2f, 0xef, 0x95, 0x0f, 0x4f, 0x59, 0x26, 0x1c, 0xef, 0x77, - 0x58, 0xef, 0x9a, 0xbd, 0x29, 0xe6, 0xcc, 0xbb, 0xf5, 0x8e, 0x62, 0x5c, - 0x6a, 0x99, 0x6d, 0xa1, 0x65, 0x03, 0xcf, 0x8e, 0x77, 0x88, 0xa9, 0x47, - 0x7a, 0x9f, 0x40, 0xb1, 0xdf, 0x9f, 0xce, 0x36, 0xe8, 0xdb, 0x59, 0xef, - 0x16, 0x89, 0x95, 0x5d, 0xeb, 0x2d, 0x19, 0xcb, 0xa2, 0x8c, 0x85, 0xfe, - 0xd2, 0xb9, 0xdf, 0x47, 0x5f, 0x92, 0x04, 0xaa, 0xcf, 0x3e, 0x45, 0x5e, - 0xf9, 0x5a, 0xab, 0x91, 0x1d, 0x62, 0x8c, 0xc7, 0xfe, 0x91, 0x5b, 0x33, - 0x30, 0x8d, 0x01, 0x1f, 0xfb, 0x4c, 0x59, 0xc0, 0x13, 0x0b, 0x3c, 0x97, - 0x4e, 0xc7, 0xe8, 0xcb, 0xe9, 0x23, 0x17, 0x34, 0x3c, 0x3a, 0x5b, 0x8e, - 0xef, 0xcd, 0x86, 0xb1, 0x6f, 0xd6, 0xbb, 0xd7, 0xda, 0x5a, 0xcb, 0xf7, - 0x3a, 0x92, 0x42, 0xcc, 0x5b, 0xeb, 0xf1, 0x1e, 0x3d, 0xd4, 0x6a, 0xc5, - 0x87, 0xc8, 0x51, 0xe8, 0x3a, 0x71, 0x53, 0xd3, 0xf2, 0x3d, 0x26, 0x58, - 0x08, 0x73, 0xbd, 0xd4, 0xc9, 0x67, 0xbc, 0xef, 0x63, 0xf4, 0x8f, 0x19, - 0x89, 0x41, 0x97, 0x18, 0x74, 0x89, 0xc9, 0x5b, 0x9e, 0x5a, 0x62, 0x39, - 0x4e, 0x1f, 0xfd, 0xb4, 0x28, 0x62, 0xe3, 0x0b, 0x71, 0xda, 0x7c, 0x95, - 0xfc, 0x55, 0xa9, 0xa1, 0xc0, 0xdf, 0xe7, 0x22, 0xfa, 0x8e, 0x82, 0xcc, - 0xff, 0x5f, 0x96, 0xf2, 0xbf, 0x18, 0x2a, 0xea, 0x85, 0xe1, 0xcc, 0xa3, - 0x01, 0xd3, 0x6e, 0x83, 0xbe, 0xd5, 0x1d, 0x19, 0xd6, 0x90, 0x8d, 0x56, - 0xc3, 0x18, 0x9c, 0x86, 0xaf, 0x35, 0x0c, 0xb9, 0x76, 0x20, 0xef, 0xad, - 0x51, 0x88, 0x09, 0xea, 0x9b, 0xcc, 0xc1, 0xbf, 0xe7, 0xd0, 0xea, 0x63, - 0x3e, 0x1c, 0xc6, 0xbe, 0x8f, 0x7b, 0xf0, 0x71, 0x5e, 0xde, 0x73, 0xc6, - 0xd2, 0x5d, 0xb8, 0xee, 0x8d, 0xf9, 0x51, 0x3e, 0x85, 0x23, 0xee, 0x25, - 0x71, 0xa4, 0xae, 0xa8, 0xf1, 0x69, 0x9e, 0x8f, 0xaa, 0x8f, 0x96, 0xbc, - 0x10, 0x39, 0x5c, 0xc9, 0xf5, 0x5e, 0x4b, 0x7a, 0xde, 0x9f, 0x35, 0x72, - 0x50, 0x3b, 0x6d, 0x6e, 0xe4, 0xda, 0x6e, 0x8a, 0x89, 0x58, 0xb3, 0x56, - 0x8c, 0x29, 0xa1, 0x9f, 0x42, 0x19, 0xb1, 0x2b, 0xcf, 0x48, 0x52, 0x3f, - 0xe4, 0x6f, 0x9e, 0x4f, 0x54, 0x27, 0xe2, 0xe7, 0xba, 0x9c, 0x87, 0x64, - 0x5b, 0xa8, 0xe4, 0x57, 0x97, 0xbd, 0x48, 0x07, 0x9f, 0x49, 0x2f, 0xf2, - 0xb9, 0xe8, 0xab, 0xeb, 0xb8, 0xa5, 0x39, 0x59, 0xbe, 0x31, 0xee, 0xca, - 0xfb, 0xab, 0x16, 0x3a, 0x62, 0x05, 0xe7, 0x18, 0xf9, 0xa9, 0xd6, 0x98, - 0x3e, 0xca, 0xf1, 0x1c, 0x5d, 0x27, 0x97, 0x0f, 0xd2, 0x2f, 0xf3, 0x9d, - 0x42, 0x0b, 0xfb, 0x48, 0x2d, 0xdb, 0xc1, 0xb5, 0xfe, 0xb6, 0x59, 0x62, - 0x7b, 0xd4, 0x7d, 0xc3, 0xa7, 0x9a, 0x72, 0x9d, 0x89, 0xd4, 0x28, 0xe3, - 0x59, 0xd2, 0xa5, 0xb7, 0x76, 0xa8, 0x6d, 0x09, 0xaf, 0x7f, 0x56, 0x95, - 0x71, 0x78, 0xf1, 0xb0, 0x4d, 0x6a, 0x96, 0x91, 0x39, 0x87, 0x84, 0x33, - 0x20, 0xcd, 0xc1, 0x2a, 0x19, 0x43, 0x53, 0x64, 0x80, 0xf1, 0x9c, 0xa8, - 0xf3, 0xf4, 0x90, 0xcf, 0x38, 0x9f, 0xeb, 0xdb, 0x5a, 0x0e, 0x81, 0xd5, - 0x49, 0xef, 0xdc, 0x5f, 0xfa, 0x7f, 0x18, 0x2a, 0x7d, 0x88, 0xc4, 0xe2, - 0xff, 0x02, 0xc7, 0x2a, 0x26, 0xcf, 0x94, 0x1a, 0x00, 0x00, 0x00 }; + 0xbd, 0x59, 0x6d, 0x70, 0x5b, 0x55, 0x7a, 0x7e, 0xae, 0x74, 0x25, 0x5d, + 0xdb, 0xb2, 0x75, 0x8d, 0x95, 0x20, 0xb7, 0x2e, 0xd6, 0x8d, 0xaf, 0x6c, + 0x11, 0xb9, 0xe1, 0x2a, 0x36, 0x45, 0x19, 0xee, 0x94, 0x1b, 0x7f, 0x21, + 0x92, 0x10, 0x94, 0x42, 0x5b, 0x67, 0x96, 0x19, 0x4c, 0xe2, 0x4d, 0x4c, + 0x08, 0x6c, 0xba, 0xcb, 0x4c, 0xdd, 0xd9, 0x4c, 0x23, 0xfc, 0x15, 0x93, + 0xc8, 0x16, 0x6b, 0x20, 0x26, 0x3b, 0x3b, 0x43, 0xc6, 0xf9, 0x70, 0x0a, + 0x72, 0x14, 0xda, 0x3f, 0x3b, 0xd3, 0x65, 0xf0, 0x6c, 0x12, 0x12, 0x58, + 0xd8, 0xb4, 0xd3, 0x3f, 0xc9, 0xf4, 0xc7, 0x7a, 0x21, 0xa1, 0x81, 0x42, + 0x36, 0xed, 0x0c, 0x9d, 0x50, 0x68, 0x4e, 0x9f, 0x73, 0x25, 0x07, 0x13, + 0xb2, 0xfd, 0xd9, 0xcc, 0x08, 0x4b, 0xe7, 0xde, 0x73, 0xce, 0x7b, 0xce, + 0xfb, 0x3c, 0xcf, 0xfb, 0x9c, 0xc3, 0x0a, 0x05, 0x95, 0x28, 0xff, 0xab, + 0xe6, 0xa7, 0xfd, 0xc9, 0x5d, 0xcf, 0xad, 0x5e, 0xd5, 0xbe, 0x8a, 0x5f, + 0x57, 0x2b, 0xcb, 0x55, 0x15, 0xff, 0x8f, 0xff, 0xbc, 0x80, 0xbe, 0x18, + 0x87, 0xfc, 0x40, 0xf3, 0xd8, 0xf3, 0x77, 0x75, 0x98, 0xd0, 0xbc, 0xf6, + 0x63, 0x4d, 0x5b, 0x4d, 0xc0, 0x29, 0x24, 0xa2, 0x9d, 0xf8, 0x1f, 0x91, + 0x0d, 0xab, 0x90, 0xed, 0x7f, 0x64, 0x7f, 0x7d, 0xcf, 0x5b, 0xf7, 0x19, + 0xd7, 0x0e, 0x79, 0xa1, 0xe9, 0xf6, 0xb8, 0xaa, 0x37, 0x43, 0x6b, 0x60, + 0x9f, 0x9f, 0xb5, 0xf4, 0xfb, 0x50, 0xb3, 0x38, 0x16, 0x70, 0x38, 0x67, + 0x58, 0xdb, 0x90, 0xd0, 0x4f, 0x41, 0x85, 0xc3, 0x39, 0x8e, 0x15, 0x80, + 0xbd, 0x39, 0x05, 0x97, 0x39, 0xe6, 0x68, 0x41, 0xc3, 0x82, 0xd7, 0x9d, + 0xae, 0xaf, 0xc2, 0x46, 0xc6, 0x9c, 0xd8, 0x23, 0x02, 0x26, 0xb2, 0x7f, + 0x60, 0x9b, 0xf1, 0xbd, 0x08, 0xa6, 0x66, 0xda, 0x91, 0x59, 0x31, 0xa7, + 0x61, 0x73, 0xbe, 0xa1, 0x4f, 0xb3, 0xc1, 0x77, 0x14, 0xa4, 0xee, 0xd3, + 0xd0, 0x5b, 0x8c, 0x23, 0x5b, 0xcc, 0xc2, 0x29, 0x8e, 0xf0, 0xa3, 0x21, + 0x30, 0xa1, 0x69, 0xf7, 0x4c, 0x2c, 0x97, 0xef, 0x20, 0x38, 0x71, 0x4d, + 0x5c, 0x4d, 0xea, 0x78, 0x6f, 0x8d, 0x10, 0xd5, 0x36, 0xb2, 0x55, 0xed, + 0x59, 0x78, 0x6d, 0xc3, 0x5a, 0xef, 0x55, 0xd0, 0xf5, 0xc7, 0x66, 0x7c, + 0x42, 0x79, 0xf4, 0x51, 0x8f, 0x0d, 0x4d, 0xb1, 0xa3, 0x6a, 0x53, 0xa1, + 0x01, 0x63, 0x45, 0x1d, 0x7b, 0x8b, 0x61, 0x8c, 0x14, 0xb1, 0xdb, 0x7b, + 0xaf, 0x1f, 0x33, 0x3a, 0x9c, 0xef, 0xb5, 0xec, 0xc6, 0x8e, 0xdc, 0x20, + 0xb6, 0xe6, 0x52, 0xd8, 0x57, 0x94, 0x31, 0x46, 0x31, 0x5c, 0x54, 0xe1, + 0x9f, 0x30, 0x22, 0xef, 0xe2, 0x76, 0xcf, 0x84, 0x18, 0xb1, 0x02, 0x18, + 0xb2, 0xe2, 0x18, 0xcd, 0x7b, 0xb8, 0xce, 0x00, 0x86, 0xcd, 0xeb, 0xa2, + 0xdf, 0x32, 0xac, 0x51, 0x88, 0xc6, 0xd3, 0x96, 0x11, 0xe9, 0xf2, 0xc2, + 0xf9, 0xb1, 0x19, 0xc1, 0x28, 0x63, 0x1f, 0x71, 0xfb, 0x8d, 0xa0, 0xeb, + 0x66, 0x3f, 0x87, 0xfd, 0x74, 0x8c, 0x7d, 0xbb, 0x6f, 0x74, 0x14, 0x89, + 0xc8, 0x18, 0x3c, 0xe8, 0x0b, 0xb7, 0xb2, 0x5f, 0x53, 0x74, 0x0c, 0x46, + 0x9c, 0xe3, 0x64, 0xfd, 0xed, 0x0e, 0xc7, 0xc8, 0xb2, 0xbf, 0x11, 0x3d, + 0x06, 0x39, 0x56, 0x03, 0x7f, 0xb7, 0xb3, 0xbf, 0x02, 0x8f, 0x1d, 0x8b, + 0x0e, 0xb1, 0xcf, 0x29, 0x4b, 0xc5, 0x19, 0x7e, 0xfa, 0x74, 0x43, 0x66, + 0x56, 0x09, 0xb0, 0x7d, 0x2f, 0xf8, 0xdc, 0xac, 0xc2, 0xa1, 0x8c, 0x85, + 0x21, 0xae, 0x5b, 0x63, 0xdb, 0x38, 0xdb, 0x7c, 0xa6, 0xc5, 0xf1, 0xa1, + 0x77, 0x15, 0x97, 0x62, 0x62, 0x31, 0x37, 0xbf, 0xaf, 0x9d, 0x63, 0xe4, + 0x4b, 0x39, 0x95, 0xef, 0x74, 0xe6, 0x6f, 0x88, 0x27, 0xd5, 0xa5, 0xcf, + 0x07, 0x95, 0x0e, 0xb6, 0x39, 0x6a, 0x03, 0xf6, 0xe6, 0xa1, 0xf9, 0x4d, + 0x8d, 0xf3, 0x68, 0xf8, 0x28, 0x37, 0xa8, 0xf4, 0x14, 0x1d, 0xa5, 0x7b, + 0xb6, 0x43, 0x71, 0x66, 0x55, 0xa5, 0x6b, 0x5a, 0xc6, 0x2d, 0xc4, 0x0b, + 0x96, 0xc2, 0x98, 0x7f, 0x22, 0xe3, 0x75, 0xa2, 0xca, 0x0d, 0xb1, 0x32, + 0xe6, 0x41, 0x95, 0xd9, 0xa3, 0xac, 0x9f, 0x15, 0x22, 0x9d, 0x4c, 0x2b, + 0xeb, 0x66, 0xa1, 0x05, 0x6d, 0x5b, 0xcd, 0x4d, 0xec, 0x43, 0x76, 0x99, + 0x89, 0x83, 0xf9, 0x28, 0x3e, 0xb0, 0x3c, 0x38, 0xb4, 0xac, 0x02, 0xaa, + 0xa9, 0xf0, 0x83, 0xe0, 0x79, 0x0b, 0x6a, 0x0d, 0xbf, 0x5f, 0xdd, 0xa4, + 0x62, 0xa4, 0x7d, 0x9d, 0xd2, 0xc5, 0x3e, 0x3e, 0xe6, 0xf9, 0x68, 0x2e, + 0x8d, 0x20, 0xb1, 0x53, 0x65, 0xc7, 0x22, 0x05, 0xee, 0xcd, 0x7b, 0x56, + 0x2c, 0xfe, 0xb4, 0xc4, 0x63, 0xad, 0x11, 0x91, 0x7b, 0x53, 0x6d, 0xc7, + 0xe2, 0x73, 0xdc, 0x07, 0xaf, 0xa9, 0xe2, 0xd7, 0x96, 0x0f, 0xf3, 0x9b, + 0x2c, 0xe6, 0x54, 0x87, 0x9f, 0xed, 0xc7, 0xdc, 0x76, 0xf9, 0x1b, 0x7a, + 0xf7, 0xb7, 0xf6, 0xa1, 0xb4, 0x07, 0xc3, 0xf9, 0x26, 0xc6, 0x5c, 0xda, + 0x83, 0x47, 0xb8, 0xde, 0xdf, 0xfa, 0xe4, 0xd7, 0xbb, 0x6e, 0xb6, 0x6d, + 0x66, 0x9c, 0x1e, 0xdb, 0x9c, 0x5f, 0xe1, 0xad, 0x07, 0xea, 0xda, 0xb1, + 0x8f, 0x39, 0xee, 0x4a, 0x2e, 0x47, 0xd6, 0x7d, 0x1e, 0xd6, 0xd7, 0x4f, + 0xd7, 0xa1, 0x6f, 0x99, 0xbb, 0x6f, 0xfa, 0xc6, 0x69, 0x21, 0xce, 0x24, + 0xfd, 0x98, 0x33, 0x87, 0x22, 0xd5, 0xc8, 0x5a, 0x5e, 0xe6, 0xfb, 0x2c, + 0xe7, 0x2f, 0x24, 0xbd, 0x38, 0x9c, 0x3c, 0x84, 0x6c, 0x2d, 0x30, 0x93, + 0x93, 0xbc, 0x32, 0xe6, 0xcf, 0xf2, 0xbf, 0x9e, 0xa2, 0x5c, 0x9f, 0xc5, + 0xf5, 0x29, 0x38, 0x66, 0x4a, 0x4c, 0x5b, 0x6a, 0x33, 0xf9, 0xb5, 0x83, + 0xfb, 0x59, 0xdf, 0x1e, 0x24, 0x3e, 0x81, 0x0f, 0x73, 0xfd, 0xd8, 0x5c, + 0x8a, 0x05, 0xd7, 0x73, 0x50, 0x7c, 0x6d, 0x69, 0x1c, 0x2a, 0xfd, 0x26, + 0xc7, 0xd3, 0x6a, 0x47, 0xce, 0xc8, 0xa4, 0x91, 0x38, 0xd7, 0xa1, 0xc8, + 0xfe, 0x69, 0x75, 0x65, 0xc1, 0x8f, 0x68, 0x5d, 0xe9, 0x79, 0x95, 0xbd, + 0x41, 0x7d, 0x7a, 0x42, 0xc1, 0xf6, 0x98, 0x7c, 0xb6, 0x41, 0x6d, 0x29, + 0x40, 0xab, 0xb6, 0x77, 0xa9, 0x73, 0x13, 0x46, 0xdf, 0x71, 0x25, 0x11, + 0x9d, 0x70, 0xfb, 0xec, 0x52, 0x5b, 0x0b, 0x01, 0xae, 0x27, 0xce, 0x9c, + 0x40, 0xab, 0xb1, 0x9f, 0x53, 0x7f, 0xcd, 0x07, 0xe7, 0xdc, 0x3e, 0xcf, + 0xa9, 0xf1, 0x82, 0x6c, 0x37, 0xac, 0xa8, 0x12, 0xc0, 0xdd, 0x49, 0x0d, + 0x2b, 0x5b, 0x44, 0x63, 0x77, 0xd2, 0x98, 0xef, 0xf6, 0x46, 0x70, 0x90, + 0x5c, 0x20, 0xee, 0x9c, 0x3f, 0x6c, 0x19, 0x41, 0x77, 0xd1, 0x8b, 0x68, + 0xad, 0x83, 0xfd, 0xf9, 0x00, 0x7e, 0x49, 0xfc, 0xf7, 0x58, 0x3a, 0x46, + 0xf2, 0x46, 0xfc, 0x57, 0x48, 0xa4, 0x8e, 0x30, 0x67, 0x0b, 0xe4, 0xc0, + 0xfe, 0x62, 0x53, 0xfc, 0x08, 0x8c, 0x81, 0x6e, 0x72, 0x40, 0x6b, 0x97, + 0x31, 0x40, 0x57, 0x6d, 0x72, 0xa7, 0xd8, 0x80, 0x1c, 0xf9, 0xd0, 0xed, + 0xf2, 0x6a, 0x50, 0xe9, 0x2a, 0xbe, 0x4f, 0x6d, 0xed, 0x21, 0xbe, 0x10, + 0x8a, 0x98, 0x7e, 0xa4, 0xea, 0xa2, 0x38, 0x4d, 0xac, 0x64, 0xc3, 0x15, + 0xcc, 0xa5, 0xcc, 0xe7, 0x45, 0x3e, 0x5f, 0xa7, 0x74, 0xce, 0x46, 0xf1, + 0x4b, 0xeb, 0x6b, 0xe1, 0x84, 0xab, 0xd9, 0xe6, 0x5b, 0xd2, 0xae, 0xe1, + 0xf2, 0xcb, 0x95, 0xf8, 0xf4, 0xe5, 0x20, 0xbe, 0x7c, 0x99, 0xfc, 0xce, + 0xa3, 0xbd, 0x12, 0x42, 0xa4, 0xda, 0x84, 0x28, 0x5a, 0xad, 0xf8, 0xa8, + 0x36, 0x16, 0xbd, 0x00, 0xa9, 0x8d, 0x8e, 0xba, 0x35, 0x67, 0xec, 0x1a, + 0x40, 0xc2, 0x39, 0xe5, 0xee, 0x85, 0xa3, 0xae, 0x2a, 0x9c, 0x16, 0xd8, + 0x54, 0xda, 0x0b, 0xbf, 0xdd, 0xa5, 0xbe, 0xc3, 0xdc, 0x9c, 0x77, 0x73, + 0xd3, 0xa5, 0xde, 0x53, 0xb8, 0xdf, 0x83, 0xca, 0xd2, 0x33, 0xd5, 0xce, + 0xa8, 0x23, 0x39, 0xa3, 0x77, 0x9c, 0xeb, 0xeb, 0x77, 0xfb, 0x66, 0xd4, + 0x04, 0xf7, 0x7e, 0xa1, 0x9c, 0x9b, 0x6a, 0xfb, 0x31, 0xee, 0x33, 0x73, + 0xef, 0xee, 0xe3, 0x63, 0xdc, 0x63, 0x39, 0xdf, 0xe0, 0x2d, 0xf3, 0x0d, + 0x72, 0xbe, 0xe3, 0x4b, 0xe6, 0xdb, 0xbd, 0x64, 0xbe, 0xdd, 0x4b, 0xe6, + 0x4b, 0x91, 0xab, 0xff, 0x22, 0x86, 0xc2, 0xa5, 0xb1, 0x55, 0x7b, 0xe0, + 0x96, 0xb9, 0x07, 0x38, 0xf7, 0x01, 0xb1, 0x90, 0x29, 0x8d, 0x53, 0x6d, + 0xef, 0x5c, 0x32, 0xf7, 0x4e, 0xce, 0xbd, 0x38, 0x8e, 0x4e, 0x2d, 0x12, + 0x62, 0xa3, 0x25, 0x84, 0x6a, 0x9b, 0x7a, 0x17, 0x9a, 0x33, 0x5d, 0xc4, + 0x4e, 0x25, 0x12, 0xf3, 0x1e, 0x98, 0x83, 0xf5, 0x5e, 0x1f, 0x16, 0x6a, + 0x17, 0xb9, 0x51, 0x5d, 0xfe, 0xfb, 0x9a, 0x02, 0x6a, 0xfd, 0x1b, 0xb9, + 0x10, 0xc7, 0x88, 0xe9, 0xfd, 0x8a, 0x10, 0xa7, 0xd6, 0x24, 0x06, 0xbc, + 0x48, 0xf4, 0xd5, 0xc0, 0x24, 0x86, 0x7c, 0x65, 0x2e, 0x2c, 0xed, 0x73, + 0xdc, 0xed, 0x53, 0x74, 0xfb, 0x08, 0xf1, 0xe1, 0xbd, 0x57, 0xc4, 0x5b, + 0x2d, 0x61, 0xbc, 0x4d, 0x4e, 0x9e, 0x2c, 0x2e, 0xea, 0x8a, 0xd4, 0x0d, + 0x78, 0x4e, 0x59, 0x7e, 0xc6, 0x34, 0xb4, 0xc3, 0xff, 0xad, 0xfe, 0x04, + 0x8c, 0x29, 0xdb, 0xbc, 0x78, 0x3d, 0x89, 0x27, 0x2b, 0x61, 0xf4, 0xee, + 0x53, 0xb2, 0xe9, 0x2a, 0x18, 0xce, 0x4a, 0x25, 0x9b, 0xd2, 0x20, 0x79, + 0xa3, 0x36, 0x1e, 0x35, 0x8d, 0xec, 0x65, 0xbe, 0xac, 0x4e, 0xde, 0x2e, + 0x06, 0x95, 0x63, 0x04, 0xf1, 0x6c, 0xfe, 0x7d, 0xcc, 0xfb, 0xa4, 0x86, + 0x49, 0xed, 0xe4, 0xc0, 0x27, 0xa4, 0x86, 0x05, 0x48, 0x44, 0x15, 0x7b, + 0xf2, 0x9e, 0xd3, 0x8d, 0x10, 0xf0, 0xb7, 0xf9, 0x70, 0xd1, 0x1c, 0xb6, + 0xea, 0xb1, 0x16, 0xe7, 0x5b, 0xb9, 0x07, 0xcb, 0x54, 0x44, 0x66, 0x96, + 0x8e, 0x15, 0xe1, 0x58, 0x11, 0x7c, 0x92, 0x13, 0xa2, 0xd2, 0x36, 0xe2, + 0x0b, 0x30, 0x19, 0x47, 0x04, 0x57, 0x0a, 0x5b, 0xfc, 0xa8, 0x09, 0x43, + 0x6d, 0x56, 0xb1, 0x3d, 0xaf, 0x29, 0xdd, 0x79, 0xe8, 0x5e, 0xdb, 0x8c, + 0x1e, 0xc6, 0x51, 0xc6, 0xc3, 0xba, 0x76, 0x4c, 0x55, 0x36, 0x4e, 0x07, + 0x50, 0x3d, 0xf5, 0x99, 0x78, 0x9f, 0x7a, 0xf8, 0xc6, 0xbd, 0xac, 0x17, + 0xc9, 0x00, 0xaa, 0xdc, 0xb9, 0x85, 0xf8, 0xb8, 0xad, 0x0e, 0x17, 0x39, + 0x5f, 0xf4, 0x2f, 0x03, 0xf0, 0x4e, 0x05, 0xe0, 0x9b, 0x52, 0x30, 0xd3, + 0x1e, 0x80, 0x67, 0x46, 0xfe, 0x56, 0x10, 0x30, 0xa7, 0xb1, 0x5d, 0x6f, + 0xc0, 0x78, 0x9e, 0x45, 0xda, 0xfc, 0x19, 0x06, 0xdc, 0xef, 0x2a, 0x9e, + 0xca, 0x6b, 0x08, 0x1d, 0x10, 0xa2, 0xd1, 0x16, 0x22, 0x96, 0xf4, 0x60, + 0xd6, 0x1c, 0x8e, 0x06, 0xb8, 0x8e, 0x61, 0x4b, 0x6a, 0x8e, 0x0f, 0xea, + 0x8c, 0x91, 0x39, 0xc7, 0xa8, 0x37, 0x4f, 0xa8, 0x4a, 0xef, 0xf4, 0x1e, + 0xc1, 0x98, 0xfa, 0x1e, 0xf0, 0x0a, 0x51, 0xd3, 0xd6, 0x34, 0x70, 0x9e, + 0xda, 0x3c, 0x13, 0x8b, 0xf5, 0x0e, 0x29, 0xc0, 0xfa, 0x39, 0x1f, 0xfc, + 0x53, 0xff, 0xc5, 0x3a, 0x2b, 0x44, 0xe1, 0x5e, 0x81, 0x77, 0xad, 0x6c, + 0xbc, 0x02, 0x46, 0xea, 0x24, 0xc2, 0xb8, 0xf4, 0xa2, 0x10, 0xdb, 0xdb, + 0x43, 0x78, 0xcd, 0x32, 0x76, 0x7d, 0xec, 0x15, 0xb8, 0x98, 0xcc, 0x0e, + 0xd6, 0x53, 0xb7, 0xae, 0x29, 0x51, 0x54, 0xe5, 0x8d, 0xcc, 0x15, 0x85, + 0x4b, 0x9f, 0x31, 0xf5, 0x9d, 0x4a, 0x10, 0x55, 0x27, 0x82, 0xe8, 0x98, + 0xf3, 0xa3, 0x62, 0x2a, 0x08, 0xef, 0xa4, 0x79, 0xfd, 0x41, 0xb8, 0xe3, + 0x58, 0x27, 0xd1, 0x8c, 0x8b, 0x2f, 0x1b, 0xf3, 0xc7, 0x89, 0x93, 0xed, + 0x88, 0xe2, 0x37, 0x05, 0x13, 0x17, 0x0b, 0x41, 0xa8, 0x27, 0x74, 0xd4, + 0xbb, 0xf5, 0x4e, 0x47, 0xb5, 0xe9, 0x61, 0x5e, 0x1c, 0xe5, 0x61, 0xb7, + 0x9e, 0x74, 0xf1, 0xd3, 0xa3, 0x74, 0xb0, 0xae, 0x6c, 0x98, 0x26, 0x95, + 0xf9, 0xec, 0x9c, 0x75, 0x43, 0xec, 0x8f, 0xa5, 0x59, 0x47, 0x2a, 0xe0, + 0xb3, 0xd7, 0xb1, 0x8e, 0xb0, 0x38, 0xb9, 0xba, 0x5f, 0xa1, 0xf8, 0xec, + 0xef, 0x6a, 0x7e, 0x88, 0x9a, 0x5f, 0xfc, 0x3f, 0x35, 0x5f, 0x85, 0x3a, + 0xe5, 0xc1, 0x98, 0x19, 0xc0, 0x6f, 0xac, 0xa6, 0x73, 0x8d, 0x08, 0x20, + 0xd5, 0xa6, 0x23, 0x72, 0xc2, 0xc2, 0x8b, 0xdc, 0x5b, 0xdc, 0x71, 0x6b, + 0x3d, 0x04, 0x76, 0x92, 0x53, 0x15, 0xd4, 0x86, 0xbb, 0x27, 0x82, 0xd4, + 0x29, 0x55, 0x59, 0x4f, 0x9d, 0xdf, 0x91, 0xbc, 0x21, 0xd2, 0x31, 0x23, + 0x1e, 0x57, 0x12, 0xa9, 0xbf, 0x43, 0x49, 0x3b, 0x62, 0xd4, 0xd1, 0x05, + 0x7d, 0x91, 0x83, 0x5d, 0x2e, 0x07, 0x67, 0x62, 0x25, 0xed, 0x58, 0x51, + 0x28, 0xf1, 0xef, 0x01, 0xea, 0xe7, 0xf5, 0xb6, 0x92, 0x76, 0xbe, 0x4a, + 0xff, 0xd3, 0xcb, 0xf1, 0x1e, 0x99, 0x36, 0xb2, 0xbd, 0xcc, 0xcf, 0x25, + 0x62, 0x63, 0x92, 0x19, 0x9c, 0xaf, 0xa5, 0xa6, 0x36, 0x07, 0x18, 0xe3, + 0x75, 0x71, 0x9a, 0xde, 0x62, 0x98, 0xfd, 0x46, 0xf3, 0x46, 0x74, 0x98, + 0x7c, 0x1f, 0x2d, 0x6b, 0xe9, 0x30, 0xfd, 0xc4, 0x28, 0xf3, 0xf4, 0x36, + 0x9f, 0x9d, 0xcc, 0x1b, 0xe9, 0x2e, 0x57, 0x53, 0xa5, 0xaf, 0x90, 0x31, + 0x49, 0x6f, 0x11, 0xc1, 0x5b, 0x2d, 0x52, 0x5f, 0x1b, 0xa8, 0xaf, 0x8b, + 0xba, 0x2a, 0xf1, 0x70, 0x4d, 0x84, 0x5a, 0x42, 0x5e, 0xc9, 0xcb, 0x4b, + 0x49, 0x21, 0xaa, 0xec, 0x20, 0x2a, 0x27, 0xcc, 0xf4, 0x7a, 0x25, 0x16, + 0x31, 0x95, 0xbb, 0xd8, 0xce, 0x1c, 0xce, 0x6d, 0xf2, 0xba, 0xde, 0xf6, + 0x84, 0x10, 0x21, 0x5b, 0x47, 0xcd, 0x84, 0x49, 0xdc, 0xc4, 0xfa, 0x8e, + 0xb8, 0xcf, 0x75, 0x04, 0xe7, 0x16, 0xc8, 0xe7, 0x08, 0xf9, 0x1c, 0xc6, + 0x9b, 0xb7, 0x70, 0x9a, 0x5a, 0xeb, 0xe9, 0x27, 0xa7, 0xb3, 0xe1, 0xa1, + 0x2d, 0xde, 0x6f, 0xf1, 0x71, 0xbf, 0xe4, 0x34, 0xdb, 0xbc, 0x78, 0x21, + 0x89, 0xcd, 0xc4, 0x47, 0xe6, 0x29, 0x25, 0xeb, 0x90, 0xdb, 0xa9, 0x0a, + 0x25, 0x4b, 0x17, 0xf5, 0x0d, 0xa7, 0xcf, 0xf0, 0x6d, 0x2f, 0x39, 0xdd, + 0x17, 0xbe, 0x95, 0xd3, 0x2c, 0xbe, 0xcc, 0xf7, 0x33, 0xf9, 0x83, 0x98, + 0xf1, 0xf9, 0x11, 0x99, 0xf2, 0x21, 0x30, 0xa5, 0x92, 0x5f, 0x0a, 0xfd, + 0x41, 0x36, 0x1e, 0x80, 0x91, 0x3e, 0x89, 0x08, 0x12, 0x13, 0x1a, 0xfe, + 0xaa, 0xc5, 0x87, 0x63, 0x31, 0x23, 0xb3, 0x93, 0x3c, 0x5d, 0x39, 0x37, + 0xc4, 0x88, 0x8c, 0x68, 0xd4, 0x53, 0xe2, 0xab, 0xaf, 0xd9, 0x0f, 0x6d, + 0xca, 0xe5, 0xe0, 0x1e, 0x8f, 0x9d, 0x8d, 0x6a, 0x30, 0x76, 0xfd, 0x84, + 0xb8, 0xb8, 0x30, 0x21, 0x44, 0x67, 0xbb, 0x79, 0xee, 0x23, 0xaf, 0x41, + 0x2d, 0x54, 0x71, 0x7e, 0xae, 0x34, 0x7e, 0xd5, 0x94, 0x06, 0xff, 0x01, + 0x77, 0xfc, 0xeb, 0x6f, 0x32, 0x8a, 0xcf, 0xf3, 0x12, 0x9f, 0x42, 0x04, + 0x6c, 0x33, 0x32, 0x4b, 0x3d, 0xdc, 0x97, 0x34, 0xb8, 0x7f, 0x4d, 0x4e, + 0x33, 0xbf, 0x7b, 0x92, 0xb1, 0xe8, 0x16, 0xbe, 0x73, 0xa9, 0x58, 0xe2, + 0x70, 0xbd, 0xb9, 0x15, 0x7f, 0xa3, 0x7b, 0x51, 0x63, 0xfe, 0x10, 0xcf, + 0xba, 0x1a, 0x45, 0xec, 0x4f, 0x56, 0xa2, 0x91, 0x98, 0x7f, 0x82, 0x98, + 0xdf, 0x3c, 0x4b, 0xad, 0x99, 0x6a, 0x67, 0x7e, 0x25, 0xdf, 0xbb, 0x94, + 0xde, 0xd9, 0x1e, 0xd7, 0x57, 0x3d, 0x32, 0xed, 0xc1, 0x9b, 0xd6, 0x5a, + 0x7a, 0x98, 0xb4, 0xf2, 0xc8, 0xac, 0xc4, 0xfb, 0x3a, 0xe5, 0x41, 0x62, + 0x3f, 0x7a, 0x87, 0x8a, 0x19, 0x6b, 0xad, 0xe2, 0x77, 0xb1, 0xef, 0x83, + 0x93, 0x29, 0xe1, 0xde, 0x6b, 0xc7, 0xac, 0x53, 0x4b, 0x70, 0xdf, 0x73, + 0x1b, 0xaf, 0x23, 0xb5, 0x03, 0x25, 0x7d, 0xd7, 0xbb, 0x98, 0xaf, 0xe7, + 0xcb, 0xf8, 0x7e, 0x96, 0xed, 0xbe, 0x29, 0x68, 0x95, 0xc4, 0xf0, 0x3a, + 0x62, 0x7c, 0x92, 0x38, 0x79, 0x78, 0x5a, 0xe0, 0x0d, 0xd6, 0x89, 0x42, + 0xd2, 0xb0, 0x76, 0x2a, 0x46, 0xba, 0x47, 0x49, 0x64, 0x57, 0x96, 0x6b, + 0xe4, 0xdd, 0xac, 0x73, 0xb8, 0x43, 0xe0, 0xe7, 0x16, 0xb4, 0x00, 0xb1, + 0xfd, 0x6f, 0xac, 0x59, 0xff, 0x51, 0xae, 0x91, 0xc9, 0x42, 0x25, 0x42, + 0x2d, 0xd4, 0x7c, 0x62, 0xb9, 0x9b, 0x58, 0x3e, 0x44, 0x3e, 0x8c, 0xd0, + 0x13, 0x6c, 0x26, 0x96, 0x57, 0xb4, 0x19, 0xd9, 0x2e, 0xfa, 0x69, 0xcf, + 0xea, 0x08, 0x71, 0x1a, 0xa7, 0x87, 0x1d, 0x41, 0x07, 0xe7, 0x4a, 0x4f, + 0x1b, 0x91, 0x0e, 0xe2, 0x5f, 0x65, 0x9f, 0xd7, 0xd8, 0x67, 0xa1, 0x4e, + 0x7a, 0xed, 0x00, 0x5e, 0x60, 0x1f, 0x33, 0xe9, 0xb8, 0x3a, 0x21, 0xf1, + 0x3f, 0x86, 0x44, 0x46, 0xe2, 0xdf, 0x59, 0xd6, 0x4a, 0xdf, 0x2f, 0xf1, + 0x4f, 0x0c, 0xe6, 0x89, 0xc1, 0x12, 0x07, 0x06, 0x24, 0x07, 0x6a, 0xe8, + 0x2b, 0x4e, 0xd0, 0x57, 0x54, 0xd9, 0x51, 0xe2, 0x5f, 0xf2, 0xa1, 0xe4, + 0x2d, 0xba, 0xca, 0x1c, 0x58, 0xef, 0xce, 0x27, 0x35, 0x20, 0x88, 0xa6, + 0x49, 0x43, 0x57, 0x95, 0xff, 0x14, 0x4f, 0x98, 0xe6, 0xfc, 0x76, 0xfa, + 0x83, 0x2f, 0xdb, 0x62, 0xcc, 0x7b, 0x10, 0xf7, 0x9c, 0x08, 0xa9, 0x12, + 0xe7, 0xf5, 0x93, 0x41, 0x84, 0x26, 0x25, 0x0f, 0xb2, 0xe3, 0x11, 0x62, + 0xc4, 0xf2, 0xfc, 0x96, 0xf8, 0x8f, 0x12, 0x17, 0xaa, 0xd2, 0xcd, 0x31, + 0x6a, 0xa6, 0x74, 0xb4, 0x4e, 0x1a, 0x03, 0x27, 0x70, 0x55, 0xbc, 0x11, + 0x33, 0x33, 0x7b, 0x99, 0xff, 0x6d, 0xc9, 0x18, 0xf7, 0x4a, 0xc7, 0xdd, + 0x37, 0xc7, 0x70, 0x39, 0xe1, 0x6c, 0xb1, 0x82, 0x65, 0xaf, 0xad, 0x61, + 0x4b, 0x1e, 0xd8, 0x96, 0xa7, 0xd9, 0x35, 0x3d, 0xab, 0xfc, 0xb8, 0x86, + 0xc3, 0x44, 0x7f, 0xbf, 0xee, 0x30, 0xff, 0x01, 0xea, 0x7d, 0xe9, 0x9d, + 0x92, 0x07, 0xff, 0x79, 0xf9, 0x8c, 0xf9, 0x2b, 0x4f, 0xe9, 0xef, 0xdb, + 0xde, 0xc5, 0x33, 0xe7, 0x16, 0x62, 0xb0, 0x93, 0x18, 0xec, 0x61, 0x8e, + 0xb6, 0x5b, 0xe4, 0x36, 0xf3, 0x99, 0x55, 0x03, 0xf4, 0xd4, 0x4d, 0x7d, + 0xd5, 0xd4, 0xb4, 0x7d, 0xd4, 0xa7, 0x77, 0xcd, 0x4a, 0x7a, 0x70, 0x87, + 0xda, 0xd9, 0x41, 0xdd, 0xec, 0x52, 0x1e, 0x72, 0xb1, 0x95, 0x26, 0x8e, + 0x34, 0x25, 0x4d, 0x5f, 0xeb, 0x63, 0xed, 0x38, 0x14, 0x5e, 0xf4, 0xdf, + 0x32, 0x4e, 0xe9, 0xb9, 0x8d, 0xb8, 0x2c, 0xbf, 0xcf, 0xba, 0x3a, 0xb4, + 0x16, 0xaa, 0xbd, 0x56, 0x51, 0x6d, 0x79, 0xc6, 0x50, 0xf1, 0x03, 0xea, + 0xec, 0xc2, 0x26, 0x79, 0xd6, 0xe0, 0xba, 0xd8, 0x16, 0x31, 0x63, 0xd1, + 0x83, 0xc4, 0xd5, 0xab, 0xdf, 0x39, 0x7b, 0x94, 0xf0, 0x36, 0x9c, 0x57, + 0x6f, 0xfa, 0x68, 0xa9, 0x0f, 0x6b, 0x6f, 0xe2, 0x4d, 0xc3, 0x33, 0x2d, + 0x51, 0xe2, 0x51, 0x62, 0x4d, 0x43, 0xe1, 0x95, 0x4a, 0xbc, 0xf1, 0x4a, + 0x10, 0xaf, 0xbf, 0x22, 0xc4, 0x68, 0x12, 0x3c, 0xe1, 0x08, 0xf1, 0x50, + 0x72, 0x0d, 0x8e, 0xeb, 0xb1, 0xe8, 0x0b, 0xae, 0x8f, 0x75, 0xe8, 0x63, + 0x8d, 0x81, 0xb3, 0xb8, 0x21, 0x0a, 0x2e, 0xa7, 0x13, 0xe4, 0x5b, 0x09, + 0x8b, 0xae, 0xdf, 0xad, 0xd5, 0x70, 0x81, 0xf8, 0x0b, 0x11, 0x7f, 0xbf, + 0xa3, 0xe6, 0x5e, 0x2d, 0x6b, 0xee, 0xaa, 0x02, 0xf9, 0xd8, 0x16, 0x40, + 0x8f, 0x5c, 0x0b, 0x71, 0x38, 0x7c, 0x13, 0x87, 0xac, 0xbd, 0xdc, 0xf3, + 0xb3, 0x96, 0x11, 0xef, 0x24, 0x1e, 0x67, 0x2c, 0xc3, 0xe9, 0xa0, 0x9f, + 0x1d, 0x76, 0x31, 0x49, 0xed, 0x8d, 0x49, 0x5c, 0x12, 0x87, 0xcc, 0xc9, + 0x3e, 0xf6, 0x39, 0xcd, 0x3e, 0x63, 0x65, 0x3f, 0xfb, 0x1e, 0x12, 0x69, + 0xe9, 0x67, 0xa3, 0xc4, 0xe0, 0x3e, 0xd7, 0xcf, 0x4a, 0xff, 0x2a, 0xbd, + 0xab, 0x8c, 0xb3, 0xdd, 0x8d, 0xb3, 0xfb, 0x26, 0x0e, 0xa9, 0x61, 0xb5, + 0x12, 0x7f, 0x0f, 0x60, 0xec, 0xa5, 0x1a, 0x84, 0xcc, 0x3b, 0x71, 0x3e, + 0xf3, 0x80, 0x1a, 0x31, 0xa1, 0xd7, 0xdb, 0x25, 0x3c, 0x6e, 0x2e, 0xa6, + 0x90, 0xcf, 0xbf, 0x23, 0xf2, 0x61, 0xc3, 0x39, 0xeb, 0x7a, 0xd2, 0x01, + 0x7a, 0xc4, 0x1b, 0xc2, 0x13, 0x33, 0xce, 0x6d, 0xa1, 0x2f, 0x6b, 0xf2, + 0x96, 0xfc, 0xdd, 0x9a, 0xc2, 0xfb, 0x02, 0x75, 0xa5, 0x75, 0xaa, 0xf4, + 0x74, 0x23, 0xe4, 0xdc, 0xa8, 0x59, 0xf2, 0x77, 0xb1, 0xc2, 0xa7, 0xaa, + 0xd4, 0x73, 0x4f, 0x9b, 0x1c, 0x37, 0x4d, 0x0d, 0x59, 0x1c, 0xfb, 0x1b, + 0x5d, 0x1e, 0x21, 0x06, 0x87, 0xa5, 0xd7, 0xa2, 0x2f, 0xe1, 0x59, 0x7d, + 0x89, 0xa6, 0xee, 0xf6, 0xc2, 0x94, 0x6d, 0x8e, 0xf2, 0x10, 0xd7, 0xa0, + 0x99, 0x83, 0x4a, 0x9a, 0xb5, 0x79, 0x2f, 0xf1, 0xd5, 0xc3, 0x1a, 0x7c, + 0xd9, 0x6a, 0x26, 0x87, 0x05, 0xeb, 0xd0, 0x0d, 0xb1, 0xcf, 0x5c, 0x3c, + 0xd3, 0xc9, 0xf3, 0x5c, 0x9c, 0x71, 0x57, 0xb3, 0x76, 0xaf, 0x63, 0xbd, + 0xe6, 0x69, 0x91, 0x39, 0xfd, 0x32, 0x26, 0x1a, 0x57, 0xb5, 0x19, 0x03, + 0x1b, 0xbd, 0x01, 0xe4, 0x88, 0xf7, 0x57, 0x59, 0x83, 0xf2, 0xdc, 0xd3, + 0xc9, 0xa2, 0x91, 0xca, 0x62, 0x04, 0x1b, 0xb9, 0xa7, 0x3c, 0x03, 0x39, + 0xff, 0x18, 0x2b, 0x9d, 0x91, 0xb7, 0xb3, 0xb6, 0x8d, 0x97, 0xb9, 0x7d, + 0x05, 0x09, 0x4b, 0x72, 0x7b, 0x9e, 0xb5, 0x6d, 0xdc, 0xe5, 0xb6, 0x91, + 0x92, 0x7c, 0xae, 0x28, 0xd7, 0xb4, 0x4f, 0x20, 0x39, 0x7c, 0x6b, 0x3d, + 0x93, 0x78, 0x5e, 0xeb, 0x93, 0xde, 0x36, 0x9f, 0x97, 0x35, 0x49, 0xd6, + 0xa2, 0xc5, 0xba, 0xa4, 0xc9, 0xfb, 0x84, 0x4c, 0xe3, 0xc4, 0x1e, 0xe1, + 0x29, 0xdd, 0x49, 0x9c, 0xfb, 0xd0, 0x1b, 0x4c, 0xa5, 0xee, 0x43, 0x26, + 0x32, 0xa7, 0x61, 0x53, 0xbe, 0xa1, 0x2f, 0x60, 0x83, 0xef, 0x28, 0xb0, + 0xfe, 0x44, 0x43, 0xe6, 0x96, 0x3b, 0x89, 0x8f, 0x73, 0x9a, 0x16, 0x9a, + 0x58, 0x2e, 0xdf, 0xc1, 0x67, 0xb9, 0xdb, 0xde, 0x49, 0xa4, 0x7f, 0xdf, + 0x9d, 0xc4, 0x0b, 0xe4, 0xc7, 0x58, 0xe9, 0x4e, 0xc2, 0xf9, 0x5e, 0x8b, + 0x17, 0x33, 0x61, 0xec, 0xfe, 0xa8, 0x5d, 0xc5, 0xe5, 0x9c, 0x11, 0x39, + 0x8e, 0xdd, 0xe8, 0x77, 0xef, 0x1f, 0x90, 0xf5, 0xdb, 0xbb, 0xf0, 0x4f, + 0xed, 0xf2, 0xfe, 0x21, 0x25, 0xd7, 0x38, 0xce, 0xe5, 0x43, 0xa3, 0xde, + 0xac, 0x67, 0x2d, 0xd8, 0xb1, 0x46, 0xc1, 0x43, 0xc9, 0x3b, 0x5d, 0x6c, + 0x8f, 0x17, 0x8d, 0x74, 0x94, 0xcf, 0xee, 0x99, 0x90, 0x35, 0xf2, 0x71, + 0x9e, 0x17, 0xa1, 0x35, 0xda, 0xbd, 0xaa, 0xc8, 0x37, 0x45, 0xae, 0x28, + 0x86, 0x73, 0x18, 0xf2, 0x8e, 0x20, 0x71, 0xce, 0xab, 0x18, 0xf3, 0x1f, + 0x7a, 0x8d, 0x54, 0xbd, 0x8b, 0x99, 0xc7, 0x79, 0x76, 0x93, 0x7f, 0x7b, + 0xe5, 0xb9, 0x0f, 0x1b, 0x39, 0xe6, 0x07, 0x6b, 0xe4, 0x59, 0xf4, 0x73, + 0x91, 0x5d, 0x66, 0x38, 0x0b, 0x8a, 0xc6, 0xdc, 0x80, 0xfa, 0x24, 0x35, + 0xfc, 0x71, 0x6a, 0xb8, 0xf4, 0x2c, 0xbd, 0xf4, 0x2c, 0x4d, 0xf3, 0x71, + 0xaf, 0x91, 0xb9, 0x4e, 0xbd, 0xe3, 0x98, 0x7d, 0xbd, 0x8a, 0xd1, 0x7b, + 0x82, 0xfa, 0xbf, 0x53, 0x29, 0x8d, 0xb9, 0xb2, 0x3c, 0xe6, 0xdd, 0x05, + 0x4d, 0xe9, 0xcc, 0x83, 0xba, 0x83, 0xe8, 0x36, 0x8b, 0xda, 0x51, 0xac, + 0x24, 0xc7, 0x4c, 0xb9, 0x66, 0xc6, 0xd6, 0xca, 0xd8, 0x14, 0x5c, 0x69, + 0x91, 0xef, 0xb6, 0xca, 0x38, 0x9c, 0x2a, 0x3b, 0x45, 0xed, 0x7d, 0xc5, + 0x57, 0xd6, 0x2f, 0xcf, 0x16, 0x6b, 0x19, 0x9c, 0x30, 0x42, 0x3e, 0xb3, + 0x0e, 0xa3, 0xb4, 0x81, 0x41, 0xb3, 0x19, 0x39, 0xdd, 0x8f, 0x2d, 0xd6, + 0x17, 0x82, 0x3a, 0xc9, 0xf7, 0x81, 0xa7, 0x5e, 0xe2, 0x19, 0xde, 0xbc, + 0x86, 0x58, 0xf2, 0x39, 0x1c, 0xd3, 0x77, 0xd1, 0x0f, 0x6e, 0xc5, 0xeb, + 0xae, 0x9e, 0xd8, 0xc4, 0xb3, 0x42, 0x0c, 0xd9, 0xb2, 0xd6, 0xdd, 0x32, + 0xb6, 0xbc, 0x93, 0xb8, 0x24, 0xb2, 0xa5, 0x31, 0x9c, 0x6d, 0x56, 0x86, + 0x71, 0x7d, 0xa3, 0xbb, 0x3b, 0xa8, 0xbb, 0x15, 0xa6, 0xe7, 0xae, 0x4a, + 0xea, 0xee, 0x56, 0xeb, 0xcf, 0xf1, 0x14, 0x39, 0x5e, 0x65, 0x7e, 0x26, + 0x9e, 0x0e, 0xcb, 0x31, 0xa9, 0xaf, 0x35, 0x4b, 0xc7, 0xff, 0x90, 0x63, + 0xca, 0x39, 0x64, 0x3d, 0x3c, 0x2f, 0x0e, 0xd5, 0xca, 0x31, 0x07, 0x95, + 0x8d, 0xe4, 0xd4, 0x3c, 0x4b, 0xef, 0x0f, 0xc8, 0xa7, 0x05, 0xe6, 0xa7, + 0xf1, 0x36, 0x7c, 0x6a, 0x24, 0x9f, 0x9e, 0x58, 0xc2, 0xa7, 0x83, 0x79, + 0xe9, 0xbd, 0x14, 0xb4, 0xb4, 0xfd, 0x29, 0x75, 0x45, 0x08, 0x7f, 0xdb, + 0x0d, 0x71, 0xc6, 0xf5, 0xbe, 0xd2, 0xef, 0xa6, 0x95, 0xee, 0x59, 0xa9, + 0x4f, 0xd5, 0x08, 0x92, 0x4f, 0x1b, 0xc8, 0xa7, 0x7e, 0xf2, 0xe9, 0x69, + 0x53, 0x34, 0xee, 0x48, 0x1a, 0xa9, 0x79, 0xfa, 0x9a, 0x75, 0xe4, 0xd4, + 0x3b, 0xe4, 0xd4, 0x48, 0xb1, 0xa4, 0x53, 0xfb, 0xb8, 0xee, 0xfb, 0xa9, + 0x53, 0xeb, 0x8a, 0x52, 0xdb, 0x1c, 0xe2, 0x3f, 0x80, 0xcf, 0xc9, 0xa9, + 0xd9, 0xa4, 0xab, 0x53, 0xd6, 0xef, 0x90, 0xd8, 0x75, 0x5a, 0xf2, 0x89, + 0x3a, 0x95, 0x2f, 0x36, 0x59, 0xa7, 0xb9, 0xa6, 0xf1, 0xbc, 0x71, 0xbd, + 0x87, 0x9c, 0xf2, 0xb5, 0x1b, 0xe7, 0x2e, 0x13, 0xbb, 0x81, 0x18, 0xf4, + 0x88, 0x2d, 0xd7, 0xc4, 0x1a, 0xcb, 0x3a, 0x79, 0x90, 0xf8, 0xef, 0xa1, + 0x66, 0xf4, 0x16, 0x6d, 0xec, 0x2d, 0x2e, 0xdd, 0x53, 0xd6, 0xa1, 0xdb, + 0xee, 0xcb, 0xb8, 0xff, 0xf6, 0xed, 0xac, 0x57, 0xb7, 0x6d, 0x97, 0x7c, + 0x5d, 0xe6, 0x97, 0x7c, 0x1d, 0xce, 0xbf, 0xa6, 0xde, 0xfe, 0x1d, 0x79, + 0xa7, 0x26, 0xc4, 0x51, 0x4b, 0xde, 0x49, 0x48, 0xdf, 0xa3, 0x60, 0xc8, + 0x92, 0xf7, 0x6a, 0x1d, 0x51, 0x15, 0x46, 0xe4, 0xfb, 0xf8, 0x4a, 0x64, + 0xc3, 0x4e, 0xdc, 0xe7, 0xd6, 0x48, 0x43, 0xef, 0x63, 0xad, 0x9b, 0x2f, + 0x9f, 0xfd, 0x66, 0x78, 0x3e, 0x7b, 0x87, 0x75, 0xea, 0x28, 0xcf, 0x79, + 0x43, 0x85, 0xaf, 0xc4, 0x7c, 0x58, 0xc5, 0x88, 0x79, 0xf3, 0x8e, 0xd2, + 0xd5, 0xb1, 0xc3, 0x7c, 0x36, 0x56, 0x58, 0xac, 0x51, 0xd4, 0x4c, 0x53, + 0x88, 0xad, 0xe6, 0x7f, 0x8b, 0x2d, 0xdf, 0x7a, 0x57, 0x88, 0x49, 0xc6, + 0x70, 0xc1, 0xc2, 0x6e, 0x1f, 0x62, 0x7d, 0xd7, 0x59, 0xd7, 0x3f, 0x58, + 0x63, 0x64, 0x0a, 0x4a, 0xa2, 0x77, 0x83, 0x22, 0xbd, 0x9e, 0xa7, 0xab, + 0x82, 0xef, 0xb4, 0xd0, 0x1b, 0x5d, 0x61, 0x06, 0xfd, 0xfc, 0x7e, 0xc6, + 0x32, 0x22, 0x47, 0xf8, 0x77, 0x4b, 0x4a, 0x8e, 0x21, 0x44, 0x87, 0x25, + 0xef, 0xbb, 0x46, 0xd4, 0xdc, 0x44, 0x56, 0x54, 0x99, 0x17, 0xa8, 0x4d, + 0x46, 0x66, 0x44, 0x91, 0x3e, 0x3b, 0x0a, 0x57, 0x67, 0xf9, 0x4c, 0x9b, + 0x88, 0xe0, 0xef, 0x5d, 0xff, 0x1c, 0xa5, 0x66, 0x35, 0xe0, 0x1f, 0x5c, + 0xdd, 0x52, 0xb1, 0xed, 0x25, 0x23, 0xa5, 0x2a, 0x7b, 0x70, 0xc9, 0x32, + 0xf4, 0x9f, 0x32, 0x6e, 0x6a, 0xcd, 0x8b, 0x9d, 0x3c, 0x3f, 0x71, 0x8e, + 0x6c, 0x9f, 0xb7, 0x56, 0xd1, 0x58, 0x3b, 0x7e, 0xdc, 0x22, 0x6b, 0xf7, + 0x2e, 0xf4, 0x34, 0xef, 0xe4, 0x47, 0x45, 0xdd, 0x94, 0xaa, 0x6c, 0xa2, + 0x27, 0x09, 0x4d, 0x85, 0xb0, 0x7d, 0xb5, 0x10, 0xab, 0x56, 0x3b, 0xf8, + 0x3c, 0xd9, 0x14, 0x3f, 0xcb, 0x1a, 0x74, 0xa8, 0xd6, 0x48, 0x03, 0xbf, + 0xc0, 0x66, 0x7a, 0xd9, 0x54, 0x5b, 0x0e, 0xb8, 0x53, 0xae, 0xf1, 0x17, + 0xe8, 0x94, 0x1e, 0xd8, 0x0a, 0x49, 0xbf, 0xe5, 0xe2, 0xb7, 0x74, 0xaf, + 0xc4, 0xd4, 0x1d, 0xc8, 0x8a, 0x4a, 0xd3, 0xe8, 0x9b, 0x65, 0xbd, 0xfd, + 0x20, 0xb6, 0x5c, 0x7f, 0x78, 0x56, 0x7a, 0x60, 0x33, 0xba, 0x5e, 0x11, + 0xcc, 0xc5, 0xf3, 0xcc, 0x45, 0xcc, 0x09, 0xd2, 0x32, 0xf0, 0xac, 0xe5, + 0x84, 0x94, 0x41, 0xe5, 0x51, 0xf2, 0xa1, 0xcf, 0x5f, 0x49, 0x0f, 0xe1, + 0xd0, 0x3f, 0x78, 0x50, 0x7d, 0x40, 0x7a, 0x8a, 0x00, 0xb5, 0xa6, 0xa9, + 0x37, 0xc8, 0xfc, 0xec, 0x48, 0x4a, 0xff, 0x41, 0xac, 0x1f, 0xb8, 0x21, + 0x3a, 0xe9, 0x71, 0x3b, 0xcb, 0x1e, 0xf7, 0x89, 0xe9, 0x34, 0x3d, 0xb0, + 0xa6, 0xc8, 0x3b, 0xb6, 0x54, 0x1b, 0x0f, 0xa4, 0x8f, 0x4a, 0x1f, 0x22, + 0xd7, 0xa0, 0xe3, 0x6a, 0x52, 0x62, 0x57, 0xc7, 0x70, 0xbb, 0x11, 0xc9, + 0x42, 0xde, 0xe9, 0xdc, 0xea, 0x2f, 0xa0, 0xa7, 0xbf, 0xe3, 0x39, 0xa0, + 0x6f, 0x62, 0x2c, 0x86, 0x5f, 0x88, 0xba, 0xa4, 0x17, 0x7d, 0xee, 0x59, + 0x2e, 0xa2, 0xa7, 0xc9, 0xfb, 0x73, 0xf4, 0x09, 0x5e, 0x9e, 0x99, 0xf7, + 0x10, 0x4b, 0x5f, 0xb6, 0x0c, 0xbd, 0x5a, 0x8f, 0xec, 0x78, 0x1d, 0xcf, + 0xa8, 0xf7, 0x53, 0x57, 0x2f, 0xe4, 0x1e, 0x65, 0x3d, 0xf7, 0xb4, 0x47, + 0x78, 0x06, 0x68, 0x9c, 0xca, 0x8a, 0x7a, 0xfa, 0x41, 0x9e, 0x97, 0x51, + 0xdb, 0x16, 0xa7, 0xdf, 0x5e, 0xdc, 0x2b, 0x0f, 0x7e, 0x68, 0x99, 0x70, + 0xdc, 0xdf, 0x41, 0xbd, 0x7b, 0x9a, 0xe7, 0x68, 0x73, 0xb9, 0xde, 0x51, + 0x8a, 0x4b, 0xad, 0xb0, 0x2d, 0xb4, 0xdc, 0x0b, 0xfd, 0xc1, 0xdb, 0xc4, + 0xb4, 0x4e, 0x7a, 0x1f, 0x5f, 0xa9, 0xdf, 0x9f, 0x4d, 0x37, 0xe8, 0x8f, + 0xb0, 0xde, 0xcd, 0x13, 0x2b, 0x4f, 0xac, 0xb6, 0x64, 0x2c, 0xf3, 0x32, + 0x16, 0xfa, 0x4b, 0xe7, 0x7e, 0x0f, 0x7d, 0x49, 0x12, 0x08, 0xcd, 0xfd, + 0x35, 0x79, 0xe5, 0x69, 0x0d, 0x21, 0xbb, 0x8b, 0x31, 0xbe, 0xfa, 0xaf, + 0xdc, 0x9a, 0xfe, 0x49, 0xf4, 0x7b, 0xd8, 0x67, 0xc2, 0x02, 0x9e, 0x39, + 0x01, 0x3c, 0x3d, 0x19, 0xa3, 0x2f, 0xa7, 0x8f, 0x3c, 0xa1, 0xe1, 0xfb, + 0xd3, 0x95, 0xf8, 0xd1, 0x74, 0x10, 0x3b, 0xa6, 0xdd, 0xbb, 0xae, 0x0d, + 0x75, 0x7c, 0xaf, 0x83, 0x67, 0xbb, 0x59, 0x6b, 0x35, 0x3e, 0xa2, 0x87, + 0x5a, 0xa1, 0x78, 0x10, 0x39, 0x00, 0x5d, 0x27, 0x6e, 0x6a, 0x5b, 0x7e, + 0x44, 0x2e, 0x0b, 0x61, 0xae, 0x96, 0x3a, 0xf9, 0xbc, 0xfb, 0x7d, 0x84, + 0xfe, 0x31, 0x23, 0x31, 0x98, 0x27, 0x06, 0xf3, 0xc4, 0xe4, 0x4d, 0x4f, + 0x2d, 0xb1, 0x1c, 0xa7, 0x8f, 0x7e, 0x4e, 0x94, 0xb0, 0xf1, 0xb5, 0x38, + 0x6a, 0x9e, 0x24, 0x7f, 0x55, 0x6a, 0x28, 0xf0, 0xcf, 0xb9, 0x88, 0xbe, + 0xa9, 0x28, 0xf3, 0xff, 0xb7, 0xe5, 0xfc, 0x9f, 0xf1, 0x97, 0xf4, 0xc2, + 0x70, 0x66, 0xd1, 0x80, 0xc9, 0x7c, 0x83, 0xbe, 0x21, 0x3f, 0x34, 0xa8, + 0x21, 0x1b, 0x0d, 0xc1, 0x18, 0x98, 0x84, 0xa7, 0x35, 0x08, 0xb9, 0x76, + 0xa0, 0xe0, 0xae, 0x51, 0x88, 0x31, 0xea, 0x9b, 0xcc, 0xc1, 0xbf, 0xe7, + 0xd0, 0xea, 0x61, 0x3e, 0x1c, 0xc8, 0xb3, 0x35, 0xf0, 0x69, 0x41, 0xde, + 0x7d, 0xc6, 0xd2, 0xdd, 0xf8, 0xc2, 0x1d, 0xf3, 0x93, 0x42, 0x0a, 0xfb, + 0xf3, 0x1f, 0x88, 0xfd, 0xe1, 0x92, 0xc6, 0xa7, 0x79, 0x3e, 0x0a, 0x1d, + 0x28, 0x7b, 0x21, 0x72, 0xb8, 0x9a, 0xeb, 0xbd, 0x9a, 0x74, 0xbd, 0x3f, + 0x6b, 0xe4, 0x80, 0x7a, 0xd4, 0x64, 0xb1, 0xab, 0xb9, 0x21, 0xc6, 0x62, + 0x89, 0x40, 0x29, 0xa6, 0x84, 0x7e, 0x04, 0x15, 0xc4, 0xae, 0x3c, 0x23, + 0x49, 0xfd, 0x90, 0xbf, 0x79, 0x3e, 0x51, 0x9d, 0x88, 0x97, 0xeb, 0x72, + 0x1e, 0x93, 0x6d, 0x81, 0xb2, 0x5f, 0x5d, 0xf4, 0x22, 0x1d, 0x7c, 0x26, + 0xbd, 0xc8, 0x57, 0xa2, 0x2f, 0xdc, 0x71, 0x53, 0x73, 0xb2, 0x7c, 0x63, + 0x34, 0x2f, 0xef, 0xb4, 0x5a, 0xe8, 0x88, 0x15, 0x9c, 0x62, 0xe4, 0x47, + 0x5a, 0x63, 0xfa, 0x30, 0xc7, 0x73, 0x74, 0x9d, 0x5c, 0xde, 0x43, 0xbf, + 0xcc, 0x77, 0x8a, 0x2d, 0xec, 0x23, 0xb5, 0xec, 0x2f, 0xb8, 0xd6, 0x2f, + 0x9a, 0x25, 0xb6, 0x87, 0xf3, 0x6f, 0x79, 0x54, 0x53, 0xae, 0x33, 0x91, + 0x1a, 0x66, 0x3c, 0x0b, 0xba, 0xf4, 0xd6, 0x0e, 0xb5, 0x2d, 0xe1, 0xf6, + 0xcf, 0xaa, 0x32, 0x0e, 0x37, 0x1e, 0xb6, 0x49, 0xcd, 0x32, 0x32, 0xa7, + 0x90, 0x70, 0xfa, 0xa5, 0x39, 0x58, 0x26, 0x63, 0x68, 0x8a, 0xf4, 0x33, + 0x9e, 0x43, 0x61, 0x57, 0x0f, 0xf9, 0x8c, 0xf3, 0xe5, 0x3d, 0x1b, 0x2a, + 0x21, 0xb0, 0x22, 0xe9, 0x9e, 0xf9, 0xcb, 0xff, 0x5f, 0x43, 0xa5, 0x0f, + 0x91, 0x58, 0xfc, 0x5f, 0x69, 0xd7, 0x8a, 0xc0, 0xa8, 0x1a, 0x00, 0x00, + 0x00 }; static const u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 }; static const u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 }; static struct fw_info bnx2_tpat_fw_06 = { - /* Firmware version: 4.0.5 */ + /* Firmware version: 4.4.22 */ .ver_major = 0x4, - .ver_minor = 0x0, - .ver_fix = 0x5, + .ver_minor = 0x4, + .ver_fix = 0x16, - .start_addr = 0x08000888, + .start_addr = 0x08000488, - .text_addr = 0x08000800, - .text_len = 0x1a90, + .text_addr = 0x08000400, + .text_len = 0x1aa4, .text_index = 0x0, .gz_text = bnx2_TPAT_b06FwText, .gz_text_len = sizeof(bnx2_TPAT_b06FwText), @@ -3686,11 +3639,11 @@ static struct fw_info bnx2_tpat_fw_06 = { .data_index = 0x0, .data = bnx2_TPAT_b06FwData, - .sbss_addr = 0x080022c0, + .sbss_addr = 0x08001ec0, .sbss_len = 0x44, .sbss_index = 0x0, - .bss_addr = 0x08002304, + .bss_addr = 0x08001f04, .bss_len = 0x450, .bss_index = 0x0, @@ -3717,862 +3670,862 @@ static const struct cpu_reg cpu_reg_tpat = { }; static u8 bnx2_TXP_b06FwText[] = { - 0xad, 0x7b, 0x7f, 0x70, 0x9b, 0x75, 0x7a, 0xe7, 0xe7, 0xd5, 0x0f, 0x5b, - 0xb2, 0x65, 0x59, 0x0e, 0x4a, 0x90, 0x77, 0xbd, 0x8d, 0x5e, 0xf4, 0xca, - 0x16, 0xd8, 0x49, 0x5e, 0x25, 0xce, 0xc6, 0x59, 0xab, 0x44, 0x75, 0x1c, - 0xdb, 0x71, 0x1c, 0x30, 0xc1, 0xdd, 0x3a, 0x3d, 0xae, 0xf1, 0x25, 0x26, - 0x31, 0x10, 0xc0, 0xe9, 0xa6, 0x7b, 0x62, 0x8f, 0xd6, 0xc2, 0x76, 0x82, - 0x43, 0x64, 0xbf, 0xce, 0x2a, 0x59, 0x87, 0x4e, 0x67, 0xd6, 0x60, 0x07, - 0x07, 0x56, 0x8e, 0x60, 0xdb, 0x6b, 0xbb, 0x73, 0xbb, 0x83, 0x8e, 0x40, - 0xf0, 0x72, 0x01, 0xb6, 0xfd, 0xa3, 0x47, 0x6f, 0xee, 0xda, 0xcc, 0x02, - 0x59, 0xa0, 0x4b, 0xa0, 0x3b, 0x7b, 0x53, 0x67, 0x0b, 0xbc, 0xf7, 0x79, - 0xde, 0x57, 0x4a, 0xb2, 0x94, 0x4e, 0x67, 0x3a, 0xe7, 0x19, 0x8f, 0xac, - 0xf7, 0xc7, 0xf3, 0x7d, 0x7e, 0x3f, 0x9f, 0xe7, 0xf9, 0x7e, 0x5d, 0x0f, - 0x54, 0xa0, 0xf8, 0x53, 0xc5, 0xdf, 0xe6, 0xe1, 0xd4, 0xe1, 0x8d, 0x6b, - 0xf5, 0xb5, 0xd6, 0x05, 0x37, 0x5c, 0x72, 0xf3, 0xab, 0x0a, 0x30, 0xf0, - 0x01, 0xfe, 0x5d, 0x3f, 0x5f, 0xf9, 0xf7, 0xbd, 0x66, 0xfd, 0x38, 0x81, - 0x40, 0x89, 0x2f, 0xf9, 0x85, 0xc7, 0x91, 0x40, 0x6b, 0x9b, 0x06, 0x8f, - 0x33, 0xf1, 0x67, 0x89, 0x7d, 0x1a, 0x90, 0xcc, 0x35, 0x86, 0xb7, 0xe2, - 0x53, 0x33, 0x1d, 0x74, 0x41, 0xae, 0x7f, 0x25, 0xf1, 0xc9, 0xc8, 0x8f, - 0x36, 0xa9, 0x1f, 0xcf, 0x3a, 0xe1, 0x09, 0x24, 0x4e, 0x23, 0x50, 0x0f, - 0x4f, 0x1d, 0xdf, 0xf9, 0x93, 0x86, 0x6a, 0x27, 0xfc, 0x25, 0x5a, 0x2d, - 0x18, 0x33, 0x90, 0xf6, 0x24, 0x86, 0x51, 0xbe, 0x11, 0x78, 0x37, 0x13, - 0xd5, 0xc7, 0x80, 0x69, 0x47, 0x22, 0x1a, 0x7e, 0x09, 0x3a, 0x8e, 0xe4, - 0xc3, 0x68, 0xe7, 0xef, 0x76, 0xe3, 0x33, 0x33, 0xec, 0x46, 0xda, 0xc9, - 0xe7, 0xf6, 0x36, 0x03, 0xdb, 0x32, 0x3a, 0x8e, 0x1a, 0xf0, 0xd4, 0x26, - 0x1e, 0xc5, 0x66, 0x7e, 0xfa, 0x13, 0x29, 0xbc, 0x31, 0x19, 0x09, 0x3f, - 0x03, 0xb5, 0x5f, 0x73, 0xaa, 0x29, 0xa0, 0x71, 0x68, 0x50, 0x51, 0x07, - 0xde, 0x54, 0xd4, 0xde, 0x49, 0x05, 0x1e, 0x85, 0xcf, 0x35, 0xe6, 0xe4, - 0x33, 0x85, 0xdb, 0x72, 0x1e, 0x5c, 0x72, 0xca, 0xfa, 0xbf, 0x49, 0x7d, - 0x2b, 0x70, 0x69, 0x2d, 0x18, 0x27, 0x0f, 0xee, 0x84, 0x82, 0xa7, 0x9b, - 0xa3, 0xa1, 0x51, 0xc8, 0xfd, 0x30, 0xb6, 0xe6, 0xe5, 0x53, 0xa5, 0xd4, - 0xa6, 0x39, 0xae, 0x9b, 0xe6, 0x19, 0xbd, 0x1c, 0xe9, 0x80, 0x1a, 0x02, - 0x14, 0x8c, 0xea, 0x0e, 0x24, 0x03, 0x6d, 0x61, 0x17, 0xd4, 0xd0, 0xbd, - 0xf8, 0x67, 0xca, 0x9c, 0x8c, 0xb9, 0x61, 0x3f, 0x3f, 0x80, 0x72, 0x14, - 0x02, 0xb6, 0xd6, 0x9e, 0xce, 0x98, 0xe6, 0x05, 0xcd, 0x85, 0x33, 0xd4, - 0xcf, 0x68, 0xee, 0x9f, 0xcd, 0x02, 0x75, 0x33, 0xae, 0x95, 0xd6, 0xf7, - 0x60, 0x36, 0x60, 0x9a, 0x73, 0xbc, 0x77, 0x34, 0x57, 0xd2, 0xb3, 0x69, - 0x3a, 0x34, 0xd3, 0xdc, 0xa7, 0xfd, 0xca, 0xdc, 0xfb, 0x6b, 0xcf, 0x9a, - 0xe6, 0x13, 0xfa, 0x4d, 0x38, 0x9b, 0x6d, 0x57, 0xba, 0x17, 0x56, 0xf9, - 0xb7, 0xcf, 0x98, 0xb8, 0xa0, 0x23, 0xe0, 0x48, 0x74, 0x28, 0xdb, 0x17, - 0xba, 0x94, 0x6d, 0xf9, 0x5d, 0x4a, 0xc7, 0xdc, 0xef, 0x2a, 0x5d, 0x0b, - 0x03, 0x4a, 0x67, 0x3e, 0x84, 0x79, 0x23, 0x88, 0x39, 0xa3, 0x5f, 0x69, - 0x5f, 0xe8, 0x53, 0x6c, 0x39, 0x52, 0x4a, 0x5b, 0xbe, 0x44, 0xeb, 0xba, - 0x1e, 0xb7, 0x67, 0x12, 0x98, 0x30, 0xca, 0xb9, 0xce, 0xb2, 0xf9, 0xa3, - 0x86, 0x65, 0xca, 0xa9, 0xe3, 0x58, 0xfe, 0x09, 0xec, 0x9c, 0x31, 0xcd, - 0x5c, 0x1c, 0xc8, 0xe5, 0x81, 0xef, 0x19, 0x91, 0xde, 0x21, 0xc5, 0x34, - 0x3b, 0xa3, 0xe6, 0xea, 0xcb, 0x7a, 0x63, 0xec, 0x65, 0xfc, 0x93, 0x39, - 0x1b, 0x44, 0xda, 0x47, 0x1a, 0xc7, 0x69, 0xb3, 0xfb, 0x27, 0xe1, 0x29, - 0x4f, 0x8c, 0xe3, 0x67, 0x19, 0x78, 0xca, 0x12, 0x69, 0x5c, 0xc8, 0x8c, - 0x06, 0x3c, 0x88, 0x84, 0xb6, 0x2b, 0xe9, 0x94, 0x03, 0xea, 0xf0, 0xdb, - 0x50, 0xc3, 0xb4, 0xc7, 0xd2, 0x79, 0x45, 0x2d, 0xbc, 0x0c, 0x35, 0xf9, - 0x2b, 0x45, 0xed, 0xaa, 0x75, 0x22, 0xe9, 0x88, 0x7a, 0xf0, 0xa3, 0x06, - 0xb1, 0xc9, 0x38, 0xd6, 0x5a, 0xb6, 0x49, 0xe3, 0xd6, 0x6b, 0xb6, 0x49, - 0x60, 0x94, 0x7c, 0x1d, 0x25, 0x5f, 0xaf, 0xe8, 0x6a, 0xe8, 0x69, 0x98, - 0xab, 0x07, 0x75, 0xb9, 0x97, 0xc0, 0x78, 0xde, 0x0c, 0xfb, 0x13, 0x97, - 0xc8, 0x2f, 0xd2, 0x5f, 0x4a, 0x78, 0xd2, 0xd5, 0x89, 0x4f, 0xcd, 0xd7, - 0x37, 0x86, 0xf0, 0x62, 0x3e, 0x88, 0x17, 0xf2, 0x01, 0x3c, 0x9f, 0x6f, - 0x87, 0x91, 0x87, 0x7f, 0x67, 0xfe, 0x8b, 0xfc, 0xd8, 0x84, 0x8f, 0xcf, - 0x93, 0x6f, 0xff, 0x8e, 0xbc, 0x6b, 0xa0, 0x2c, 0x81, 0xde, 0x1f, 0x67, - 0x46, 0xcc, 0x0a, 0x0d, 0x03, 0x35, 0x09, 0x2d, 0x79, 0x9b, 0xe2, 0x6b, - 0xa1, 0x1f, 0xf6, 0xbe, 0x9a, 0x6b, 0x71, 0x69, 0x53, 0x5e, 0xb8, 0xa9, - 0xff, 0x6d, 0x79, 0xd3, 0x1c, 0xd3, 0x0f, 0xad, 0xdb, 0xdb, 0xf2, 0xa7, - 0x85, 0x5e, 0xad, 0x07, 0xe9, 0xfc, 0x20, 0xe0, 0x4f, 0xf0, 0x93, 0xa1, - 0xb8, 0xab, 0xa9, 0x3d, 0x7c, 0xee, 0x41, 0x97, 0xed, 0xcf, 0xe4, 0x81, - 0x7a, 0x7f, 0xc1, 0x20, 0x0f, 0xc6, 0xb4, 0x1f, 0x15, 0x61, 0xca, 0xf7, - 0x13, 0xf2, 0x19, 0xc3, 0xf7, 0xf3, 0x1a, 0x79, 0x6b, 0x22, 0x8f, 0x61, - 0xf2, 0xe7, 0xc1, 0xde, 0xac, 0x3a, 0x9d, 0x86, 0x3a, 0x31, 0x8b, 0x35, - 0x48, 0x06, 0x03, 0xf4, 0xc1, 0x3f, 0x86, 0x4d, 0xa3, 0x07, 0x53, 0x06, - 0xd6, 0x07, 0x12, 0xb4, 0x6f, 0x1c, 0x8f, 0x96, 0x21, 0x3a, 0xf0, 0xb1, - 0xa2, 0xe0, 0xf5, 0x68, 0x0f, 0x26, 0x29, 0x4f, 0x4f, 0xce, 0x8b, 0x07, - 0xb2, 0x15, 0xb8, 0x2f, 0x6b, 0xe2, 0xfe, 0x38, 0x12, 0x15, 0x94, 0x27, - 0x16, 0x8f, 0x86, 0xdf, 0x83, 0x0b, 0xed, 0xb9, 0x1e, 0xc6, 0xd2, 0x56, - 0x24, 0xcb, 0x3c, 0xd8, 0x9a, 0xf3, 0x31, 0x1e, 0x93, 0x38, 0x3d, 0xe3, - 0x81, 0x7b, 0x83, 0x03, 0xb3, 0xc1, 0x32, 0xc4, 0xea, 0x1d, 0xfc, 0x0d, - 0xfa, 0xdb, 0x66, 0xea, 0xfc, 0xdb, 0x0c, 0x17, 0x0e, 0x18, 0x0e, 0x8c, - 0x64, 0x4d, 0xb3, 0x5d, 0x37, 0x71, 0x75, 0x43, 0x00, 0x3f, 0xa0, 0xfe, - 0x0e, 0x19, 0x21, 0x9c, 0xcd, 0x3f, 0x4e, 0x5e, 0x82, 0x36, 0xbf, 0x06, - 0x79, 0x37, 0xc8, 0xbb, 0x41, 0xbe, 0x0d, 0xe1, 0xf3, 0x3c, 0x63, 0x46, - 0xa7, 0x5c, 0x5e, 0xf2, 0x50, 0x89, 0x21, 0xf2, 0x11, 0x89, 0x9b, 0x70, - 0xc4, 0xd5, 0xf4, 0x5e, 0x26, 0xaf, 0xd5, 0xf5, 0xa6, 0xf9, 0xf1, 0x06, - 0x91, 0x85, 0x36, 0x77, 0xf4, 0x48, 0x8c, 0xfe, 0x56, 0x15, 0xe3, 0xea, - 0x6f, 0xa9, 0xb7, 0x27, 0xf3, 0x5e, 0xa4, 0xb2, 0x96, 0xdf, 0x1e, 0x2e, - 0x23, 0xdf, 0xc2, 0x57, 0x5e, 0x8b, 0x32, 0x46, 0xa3, 0xfd, 0x8c, 0x51, - 0xec, 0x20, 0xcf, 0xf7, 0x1b, 0xd1, 0x96, 0x5d, 0x8a, 0x0b, 0x9d, 0xb9, - 0xa0, 0xbf, 0xfd, 0x06, 0x3e, 0x29, 0xaf, 0xc4, 0x20, 0x65, 0x0d, 0x90, - 0xbf, 0x20, 0xf6, 0x91, 0xcf, 0x17, 0x8a, 0x7c, 0xce, 0xe5, 0x65, 0xad, - 0xcf, 0xf3, 0x5a, 0xe2, 0x13, 0xe9, 0x15, 0x89, 0xa0, 0x82, 0x0a, 0x1f, - 0x76, 0xe5, 0xde, 0xa2, 0x2d, 0xea, 0xf0, 0xa7, 0xb4, 0xc1, 0x8b, 0x8c, - 0x91, 0xef, 0x5f, 0xf3, 0x17, 0xb1, 0xc7, 0x63, 0xb4, 0x83, 0x7a, 0x3a, - 0x0d, 0x1f, 0x06, 0xf2, 0x49, 0x1c, 0x99, 0x41, 0x72, 0x5e, 0x3f, 0xce, - 0x78, 0x5f, 0x05, 0xa7, 0x56, 0x9e, 0x0c, 0x68, 0x15, 0xd8, 0x37, 0x17, - 0xc4, 0x70, 0xbe, 0x0d, 0x46, 0x36, 0x88, 0x83, 0xf4, 0xcd, 0x2b, 0xf1, - 0xe4, 0xfd, 0x7e, 0x08, 0xef, 0x41, 0x3c, 0xc0, 0x77, 0x9e, 0x98, 0x09, - 0x62, 0x88, 0x3a, 0xda, 0x1e, 0x8f, 0xb6, 0x78, 0x79, 0xed, 0x00, 0xaf, - 0x1d, 0xa5, 0xfe, 0xcf, 0xeb, 0x93, 0x18, 0xe8, 0x55, 0x63, 0x40, 0x10, - 0xfb, 0x0d, 0x04, 0xe8, 0xc2, 0x8f, 0x31, 0xbf, 0xc5, 0xce, 0xf3, 0xfb, - 0xbd, 0xf9, 0x0a, 0xca, 0xe9, 0x47, 0x48, 0xfb, 0xc4, 0x74, 0x37, 0x9b, - 0xe6, 0x77, 0xf5, 0xe8, 0xd2, 0x4f, 0x9d, 0x2e, 0x3c, 0x92, 0x77, 0x20, - 0x35, 0x57, 0x81, 0xdf, 0xcf, 0xba, 0x70, 0x57, 0x7d, 0x05, 0x0e, 0xcd, - 0x25, 0x31, 0x36, 0x53, 0x81, 0xc1, 0x2c, 0x56, 0xef, 0xd7, 0xc7, 0x6a, - 0xca, 0xa0, 0x2e, 0xb7, 0x23, 0x86, 0xab, 0xb4, 0xc3, 0x23, 0x73, 0x3e, - 0x7f, 0xff, 0x4c, 0x00, 0xa9, 0x05, 0x2f, 0x9f, 0x77, 0xf0, 0xf9, 0x72, - 0xe8, 0xeb, 0x23, 0xa9, 0x00, 0x84, 0xc7, 0x4a, 0x3c, 0x34, 0xe7, 0xc5, - 0x83, 0xd9, 0x00, 0x0e, 0xce, 0x34, 0x63, 0xda, 0x48, 0xe2, 0x18, 0x73, - 0xc7, 0xf7, 0xe2, 0x6a, 0xef, 0x41, 0x45, 0x4d, 0x6e, 0x53, 0x92, 0x68, - 0x88, 0xbb, 0x71, 0x89, 0x79, 0xc8, 0x1d, 0x6f, 0x6c, 0x79, 0x9e, 0xb9, - 0xa1, 0x2c, 0x11, 0xe4, 0x77, 0x75, 0x82, 0x31, 0x9b, 0x74, 0x3b, 0x36, - 0x00, 0x2b, 0x25, 0x7e, 0x83, 0xfe, 0x6e, 0x23, 0xe0, 0xef, 0xce, 0xd7, - 0xf9, 0xb7, 0x1b, 0x21, 0xff, 0x76, 0xc6, 0xd7, 0x36, 0xf1, 0x47, 0xc3, - 0x83, 0xe3, 0xf1, 0x4f, 0xcd, 0x81, 0x1a, 0x2b, 0x9f, 0xf9, 0x77, 0xce, - 0xa8, 0xe9, 0x59, 0xa8, 0x3a, 0xab, 0x01, 0x26, 0x17, 0x5c, 0xb4, 0x9f, - 0x82, 0x1a, 0xad, 0x99, 0x79, 0x3c, 0x80, 0x87, 0x98, 0x53, 0xfe, 0x9a, - 0x39, 0x65, 0x70, 0x2a, 0x12, 0x98, 0x86, 0x97, 0xfa, 0x06, 0xf6, 0x9e, - 0x0b, 0xd2, 0xe6, 0x5d, 0x78, 0x9c, 0x7c, 0x6d, 0xdf, 0x18, 0xc4, 0x7d, - 0xf9, 0x80, 0xbf, 0x8b, 0xf6, 0x7b, 0x2f, 0x17, 0xf2, 0x6f, 0xa5, 0x2d, - 0xdf, 0xce, 0xa9, 0xe1, 0x02, 0xfe, 0xaf, 0xf8, 0x53, 0x0c, 0x0e, 0x60, - 0xff, 0x94, 0x1b, 0x85, 0xa0, 0xac, 0x45, 0x9d, 0x1b, 0x2f, 0x9a, 0x3e, - 0x4d, 0x3b, 0x7d, 0x90, 0xba, 0xfe, 0x46, 0xde, 0x87, 0x07, 0x0d, 0x35, - 0xf6, 0x7d, 0xc5, 0x47, 0x9d, 0x7a, 0xa8, 0x07, 0x26, 0x98, 0x55, 0xf2, - 0x5c, 0x1c, 0xe1, 0x55, 0x76, 0xae, 0x3d, 0x34, 0x27, 0x7e, 0x42, 0xdb, - 0x1b, 0xf4, 0x01, 0xfa, 0xcf, 0xf7, 0xaf, 0xc5, 0xaa, 0x1a, 0x48, 0x5b, - 0xb9, 0x3b, 0x46, 0x7f, 0xb1, 0x75, 0x74, 0x62, 0x46, 0xf4, 0xa0, 0x4e, - 0xc3, 0x91, 0xc4, 0xba, 0xf5, 0x7f, 0x6d, 0x5e, 0x5a, 0x29, 0xfa, 0x08, - 0x60, 0x84, 0x3a, 0x3c, 0x6d, 0x98, 0xe6, 0xd5, 0x0d, 0x1f, 0x9a, 0x2d, - 0x37, 0x8b, 0x5e, 0x44, 0xd6, 0x1f, 0x28, 0x52, 0x47, 0x6a, 0x34, 0xff, - 0xff, 0x07, 0x5f, 0xf9, 0xa6, 0x39, 0x60, 0xc9, 0x27, 0xfe, 0xe2, 0xa2, - 0x2f, 0x3e, 0x4e, 0xda, 0x0e, 0x0c, 0x90, 0xde, 0xc3, 0x86, 0xf9, 0x51, - 0x6d, 0xe2, 0x33, 0xb3, 0x65, 0x93, 0x36, 0xbc, 0xac, 0xfc, 0x4f, 0x5e, - 0x0f, 0xe2, 0xa1, 0x7c, 0x0b, 0x75, 0xd7, 0x8e, 0x27, 0xa8, 0xc3, 0xa3, - 0x86, 0xe4, 0xc4, 0x10, 0xfd, 0xb9, 0x8e, 0xfe, 0xed, 0x52, 0xb6, 0x19, - 0x39, 0x6c, 0x9f, 0x4c, 0xa3, 0x93, 0xfe, 0xbe, 0x94, 0x89, 0xb4, 0x3c, - 0x0b, 0x35, 0x4d, 0x19, 0xfc, 0x5d, 0xd4, 0x71, 0xbb, 0xa1, 0x76, 0x89, - 0x4d, 0xdb, 0x99, 0x97, 0x5e, 0xca, 0x84, 0xfc, 0x6d, 0x79, 0xd1, 0x77, - 0x9d, 0x7f, 0x6b, 0xfe, 0xab, 0xb4, 0xbd, 0x82, 0xcd, 0x6b, 0x3c, 0xcc, - 0x33, 0x77, 0xc1, 0xb6, 0xab, 0x6d, 0xbb, 0xd7, 0xe3, 0x8d, 0x03, 0x1f, - 0x32, 0x3f, 0xa5, 0x57, 0xda, 0xd7, 0x52, 0xbc, 0x56, 0xbd, 0x01, 0xfe, - 0x3b, 0xe9, 0x07, 0x7b, 0xe8, 0x07, 0x57, 0x37, 0x7c, 0x6a, 0x86, 0x6f, - 0xb2, 0xfd, 0xa0, 0x6d, 0xc6, 0xe5, 0xef, 0xa0, 0x9e, 0xb6, 0xe9, 0x0a, - 0xe6, 0xf4, 0x0c, 0x06, 0xae, 0x61, 0x87, 0xe4, 0xec, 0x59, 0x3d, 0xc9, - 0x3c, 0xf2, 0x9b, 0x70, 0xd5, 0x60, 0xf6, 0x59, 0xfd, 0x71, 0x84, 0x6d, - 0xdf, 0xc1, 0xc1, 0xac, 0x17, 0xe9, 0xbb, 0x02, 0x98, 0x6f, 0x08, 0xe0, - 0x61, 0xd2, 0xbe, 0x12, 0x6f, 0x1c, 0x7a, 0x83, 0x3a, 0x98, 0xad, 0x91, - 0x6b, 0x49, 0xfc, 0xa5, 0xfe, 0x28, 0x70, 0x93, 0xbd, 0xf6, 0x82, 0xc4, - 0xe8, 0x42, 0x33, 0x8e, 0xe6, 0xfb, 0x15, 0x3b, 0x6f, 0xaa, 0x5d, 0x49, - 0xfc, 0xc4, 0x94, 0x5c, 0xba, 0x60, 0x30, 0xc7, 0x51, 0x1f, 0xe3, 0xf4, - 0xa3, 0xd1, 0x5c, 0x9d, 0xbf, 0x93, 0x7e, 0xf4, 0x78, 0x4e, 0x64, 0x8a, - 0xea, 0xba, 0xb3, 0x96, 0xb5, 0x99, 0xfa, 0x31, 0xac, 0x9a, 0x5f, 0x1d, - 0xd0, 0x8e, 0x61, 0xda, 0xe2, 0x2d, 0xa5, 0xf4, 0x13, 0x63, 0x30, 0x64, - 0xaa, 0xcb, 0xb5, 0x43, 0x78, 0xdc, 0xba, 0x16, 0xf4, 0xef, 0x9e, 0x49, - 0x3a, 0x1c, 0x1a, 0x02, 0x95, 0x89, 0x76, 0x65, 0x37, 0xeb, 0x6e, 0xc7, - 0x4c, 0x87, 0xd2, 0xb1, 0x20, 0x31, 0xd0, 0xa5, 0x6c, 0x67, 0xcd, 0x4d, - 0xb2, 0xe6, 0x26, 0x59, 0x73, 0x93, 0xe4, 0x23, 0xc9, 0x5a, 0xdb, 0x96, - 0x4f, 0x29, 0x3b, 0x44, 0xff, 0xf4, 0xaf, 0xe7, 0x0d, 0x1b, 0x47, 0x30, - 0x07, 0xf9, 0x3b, 0xf3, 0x6b, 0x1d, 0x36, 0xb6, 0x4b, 0x29, 0x45, 0x2c, - 0xe3, 0xa9, 0xd0, 0x58, 0xcb, 0x8c, 0x94, 0xd2, 0xcd, 0x7a, 0xdb, 0x6f, - 0xe9, 0x32, 0x32, 0xfc, 0x0e, 0xeb, 0xec, 0xeb, 0xac, 0xb3, 0xb9, 0x38, - 0xe3, 0x6a, 0xcd, 0x55, 0x73, 0x60, 0xa5, 0x5d, 0x13, 0xc6, 0xc8, 0xef, - 0x77, 0x69, 0xb3, 0x02, 0x6b, 0x69, 0xbb, 0x53, 0xc1, 0x7e, 0x0d, 0xd5, - 0xb5, 0xcc, 0xa9, 0x47, 0xf3, 0xac, 0x03, 0x7a, 0xa4, 0xe5, 0x7d, 0x2a, - 0xf6, 0xa8, 0xe6, 0xc6, 0xd5, 0x9b, 0x08, 0x76, 0xb4, 0x36, 0x1c, 0xcf, - 0x96, 0x63, 0x28, 0x9e, 0x5c, 0xe1, 0x21, 0x56, 0xe9, 0x6a, 0xc6, 0xa3, - 0x5c, 0x5a, 0x09, 0x25, 0xa2, 0xf4, 0x1b, 0x24, 0xa7, 0x58, 0x27, 0x26, - 0x8d, 0xaf, 0x22, 0xc7, 0x7a, 0x3a, 0xaf, 0xbb, 0xf0, 0x7a, 0x6e, 0x2d, - 0xf3, 0x5c, 0x54, 0xf7, 0x29, 0x15, 0x8c, 0xdf, 0x04, 0x32, 0x86, 0xe4, - 0x27, 0xd3, 0x9c, 0x17, 0x1e, 0xa2, 0xd1, 0xe4, 0x28, 0x24, 0x67, 0x99, - 0xab, 0xef, 0x8d, 0x97, 0x61, 0x73, 0xd4, 0x8f, 0xd5, 0xda, 0x80, 0xd2, - 0x95, 0x8f, 0xea, 0xe7, 0xf1, 0xbb, 0xca, 0x9e, 0x85, 0x04, 0x63, 0xbb, - 0x9f, 0xba, 0xa9, 0xc0, 0xa5, 0xa0, 0xf0, 0x88, 0x6a, 0xb7, 0xe6, 0xc0, - 0xbb, 0x77, 0x2b, 0x08, 0x68, 0x49, 0x5c, 0x68, 0x0e, 0xd0, 0xaf, 0xba, - 0x88, 0x31, 0xc2, 0x70, 0x2e, 0x86, 0xfc, 0x3b, 0x68, 0x8b, 0xca, 0xc5, - 0x3a, 0xda, 0x87, 0xbe, 0x47, 0x1d, 0xb6, 0x51, 0x87, 0xdd, 0x73, 0x08, - 0x54, 0x24, 0xfa, 0x94, 0x8e, 0x7c, 0xbb, 0xd2, 0x9e, 0x57, 0xa9, 0x27, - 0xd1, 0xc9, 0x37, 0x89, 0x95, 0xc4, 0x57, 0x4a, 0xb6, 0x14, 0x7f, 0xbd, - 0xd1, 0x9e, 0xfd, 0x0e, 0x89, 0xb9, 0xcd, 0x6b, 0x12, 0x8c, 0x47, 0x07, - 0xf9, 0x12, 0x1e, 0x3c, 0xa8, 0x6e, 0x30, 0x57, 0x5f, 0x89, 0x33, 0x79, - 0x56, 0x24, 0x30, 0x95, 0xef, 0xa1, 0x5d, 0x36, 0x14, 0xfd, 0x2b, 0xe0, - 0xdf, 0x36, 0xd3, 0xae, 0x6c, 0x5b, 0x58, 0xe1, 0xef, 0xa5, 0x0d, 0x7b, - 0x17, 0x42, 0x42, 0x97, 0xeb, 0x8b, 0x6d, 0x93, 0x70, 0x68, 0xff, 0x9a, - 0x2d, 0xbf, 0x41, 0x5a, 0x62, 0x4f, 0x6f, 0xc9, 0x4f, 0xfd, 0x7b, 0x66, - 0x92, 0x78, 0x77, 0x83, 0x9b, 0x35, 0xb5, 0x84, 0x29, 0xaa, 0x8a, 0x9f, - 0xa7, 0x1d, 0xd0, 0x52, 0x4a, 0x97, 0xf8, 0x91, 0xdb, 0x5e, 0xf3, 0xce, - 0x19, 0xb8, 0x09, 0x15, 0xc2, 0x4e, 0x62, 0xba, 0x0f, 0xe3, 0xd1, 0x81, - 0x73, 0x4a, 0x8f, 0xd2, 0x93, 0x97, 0x1a, 0x6c, 0xfb, 0x54, 0x1b, 0x7d, - 0xaa, 0x9d, 0xfc, 0xb4, 0xd3, 0xa7, 0xba, 0xc9, 0x4f, 0xb7, 0xe5, 0x53, - 0xe2, 0x9b, 0xbf, 0xce, 0xcb, 0xd6, 0xfc, 0x1e, 0x4b, 0x2f, 0x3b, 0xf8, - 0x6e, 0x17, 0xe5, 0xe8, 0xe2, 0x7b, 0x7b, 0xf8, 0xde, 0x9e, 0x85, 0xff, - 0x2d, 0xfc, 0x51, 0x16, 0x3b, 0xf6, 0xaf, 0xd7, 0x34, 0xc9, 0x01, 0xaf, - 0x15, 0x31, 0x05, 0xd2, 0x8e, 0x84, 0xe4, 0x88, 0x61, 0xf4, 0x36, 0xc3, - 0xb3, 0x22, 0xf1, 0x93, 0xd6, 0x5d, 0xf5, 0xcc, 0x67, 0xcc, 0xa7, 0x9e, - 0x29, 0x62, 0x69, 0xe6, 0xe8, 0xf9, 0x16, 0x05, 0x63, 0xfa, 0xcd, 0x8c, - 0x53, 0x1d, 0x13, 0x79, 0xb5, 0x2b, 0xcc, 0x7b, 0x4d, 0x93, 0x82, 0xf1, - 0x0f, 0xa2, 0x8d, 0xb8, 0x2e, 0x94, 0x18, 0x42, 0xc8, 0x88, 0x84, 0x26, - 0x14, 0x75, 0x68, 0x2b, 0xd4, 0x25, 0xd6, 0x86, 0xd4, 0x9c, 0xa2, 0x0e, - 0xd7, 0x3a, 0xd5, 0xe4, 0x9b, 0x16, 0xbe, 0x3e, 0x88, 0x35, 0x16, 0x86, - 0x1b, 0x42, 0x8c, 0x58, 0x76, 0x07, 0x69, 0x1e, 0xd8, 0xac, 0xe0, 0xb2, - 0xfe, 0x21, 0xed, 0xa8, 0x26, 0xd3, 0x8a, 0x8e, 0x0c, 0xf3, 0x44, 0x68, - 0x4a, 0xb0, 0xfa, 0x41, 0x62, 0x75, 0x78, 0x7c, 0x7c, 0x36, 0x33, 0x19, - 0x49, 0x79, 0x9c, 0x6a, 0x8c, 0x38, 0x3d, 0x49, 0x9a, 0x7a, 0x9e, 0xf8, - 0x9d, 0x6b, 0x84, 0xf7, 0x17, 0x69, 0x46, 0x8b, 0x34, 0xb5, 0x1c, 0x18, - 0x37, 0x13, 0xe8, 0x8c, 0xb2, 0x56, 0x30, 0xe7, 0x1d, 0x93, 0x9e, 0x80, - 0xf4, 0xca, 0xa7, 0x74, 0x7e, 0x4f, 0x29, 0xbb, 0x25, 0xa6, 0xca, 0x6d, - 0x2b, 0x54, 0x73, 0x8d, 0xaa, 0xc4, 0x61, 0x2c, 0x5a, 0x6b, 0x0c, 0xcb, - 0x1a, 0xc3, 0x3f, 0x53, 0xd4, 0xd8, 0x39, 0x45, 0x72, 0x75, 0x63, 0xff, - 0x39, 0xc6, 0xd0, 0x51, 0x45, 0x6d, 0x39, 0x4e, 0xf1, 0xbd, 0x9a, 0xd0, - 0x3f, 0x5c, 0x5c, 0x67, 0x18, 0x0d, 0x39, 0xc6, 0x67, 0xde, 0xa3, 0x6c, - 0xcd, 0xb6, 0x61, 0x6c, 0xae, 0x0d, 0xa3, 0x59, 0x05, 0x7b, 0xf4, 0x95, - 0xb8, 0x74, 0xb3, 0xd5, 0xa7, 0x54, 0xad, 0xd6, 0x6a, 0x31, 0x12, 0x40, - 0xb5, 0x43, 0xfb, 0x0a, 0xf6, 0x16, 0x31, 0x7e, 0xe7, 0x89, 0x5e, 0xe6, - 0x7d, 0x13, 0xef, 0x33, 0x96, 0x22, 0x35, 0x48, 0xba, 0x13, 0x2d, 0xc4, - 0xe3, 0x75, 0x4e, 0x3b, 0xde, 0xff, 0xc9, 0x63, 0xdb, 0x40, 0xf4, 0xff, - 0xf9, 0x7b, 0x6d, 0x78, 0x32, 0x5b, 0x86, 0x96, 0x0d, 0xb8, 0x2b, 0x84, - 0x2a, 0x07, 0x6b, 0xdc, 0x5b, 0xbb, 0x94, 0x14, 0xef, 0x59, 0xcf, 0x7a, - 0xbe, 0x9c, 0xe8, 0x4d, 0xfc, 0x97, 0x06, 0xb9, 0x6e, 0xe5, 0x8d, 0x1b, - 0xae, 0x0f, 0x7f, 0xc1, 0x75, 0x05, 0xcf, 0x31, 0x91, 0x7d, 0x8f, 0x35, - 0x25, 0x97, 0x31, 0xe1, 0x4c, 0xb8, 0x30, 0x34, 0x19, 0xc6, 0xc1, 0xc5, - 0x20, 0x16, 0x33, 0xea, 0xc0, 0x25, 0xf6, 0x0f, 0x7b, 0x9b, 0x35, 0x3c, - 0xb8, 0x18, 0xc2, 0x42, 0x06, 0xa6, 0x37, 0xa1, 0x15, 0xbc, 0x4a, 0x0c, - 0x07, 0x16, 0xeb, 0x70, 0x2e, 0xa3, 0x2d, 0x8d, 0x2a, 0xd1, 0x54, 0x2d, - 0x71, 0xc7, 0xc3, 0x8b, 0x4d, 0x78, 0x68, 0xd1, 0xc3, 0x77, 0x4c, 0x74, - 0xc7, 0xeb, 0xf8, 0xbc, 0x03, 0xcf, 0x9e, 0x34, 0x4d, 0xc1, 0x5d, 0x43, - 0x8b, 0xc0, 0xc2, 0x34, 0x6b, 0xd1, 0x19, 0xd6, 0xa5, 0xa7, 0x80, 0x03, - 0x4f, 0x39, 0x30, 0x37, 0x6d, 0x62, 0xaf, 0x3e, 0x5a, 0xeb, 0xa0, 0xc3, - 0x0f, 0xb0, 0x6e, 0xb8, 0x59, 0x03, 0xef, 0x0d, 0xd8, 0xf9, 0xfc, 0x12, - 0xf3, 0xd4, 0xfd, 0x4f, 0xc5, 0xf0, 0x56, 0x26, 0x8d, 0x6e, 0xe2, 0xf3, - 0x14, 0x79, 0x79, 0x33, 0xc3, 0x3a, 0xb6, 0xa8, 0xe3, 0x8d, 0x8c, 0x87, - 0xeb, 0x34, 0xe1, 0xe5, 0x8c, 0x3c, 0x23, 0xcf, 0xfa, 0x30, 0x48, 0x5e, - 0x5e, 0xcf, 0x84, 0xb8, 0x66, 0x10, 0x3f, 0xe6, 0x73, 0xf7, 0x2d, 0x6a, - 0xac, 0x5b, 0x1e, 0xae, 0x1b, 0xc6, 0xab, 0x19, 0x1f, 0x79, 0x0d, 0xb2, - 0x56, 0x0d, 0x62, 0x2c, 0xd3, 0xb8, 0xb4, 0x95, 0x89, 0xda, 0xae, 0x35, - 0x72, 0xed, 0x1d, 0xb3, 0xc7, 0x8a, 0x45, 0x59, 0xa7, 0xb4, 0xee, 0x20, - 0x46, 0x33, 0x6f, 0x38, 0x4b, 0xfd, 0xf4, 0x73, 0xd3, 0xcb, 0x16, 0xf6, - 0x7b, 0xd6, 0xe0, 0xdf, 0x73, 0xc0, 0x39, 0x23, 0x6d, 0x56, 0x27, 0x88, - 0x75, 0x59, 0xa3, 0x7e, 0xba, 0xb1, 0x89, 0xeb, 0x6a, 0x03, 0x2f, 0x29, - 0xd2, 0xef, 0xb8, 0x10, 0x7e, 0x4a, 0xf4, 0x45, 0xcc, 0xbc, 0x00, 0xfc, - 0x25, 0xf1, 0x67, 0xc3, 0xa4, 0x2a, 0x7e, 0xdf, 0x4f, 0x5c, 0xd3, 0x5b, - 0x40, 0x7d, 0xec, 0x41, 0x8c, 0x98, 0x65, 0xc4, 0xe7, 0xd5, 0xc4, 0xb5, - 0x8b, 0x4d, 0xac, 0x53, 0x1b, 0x4d, 0xf3, 0x6f, 0x9b, 0x61, 0x3a, 0x12, - 0x9a, 0x5e, 0xeb, 0x2c, 0x7c, 0xa5, 0x0a, 0xda, 0x92, 0x5f, 0xd1, 0x0a, - 0x3f, 0x45, 0x74, 0xf8, 0x3c, 0x44, 0xaf, 0xc0, 0xda, 0x45, 0x17, 0xd6, - 0x51, 0x9e, 0x6d, 0x93, 0x5c, 0x9b, 0xf8, 0x24, 0x4a, 0x99, 0x76, 0x4e, - 0x12, 0x73, 0x69, 0x3e, 0xac, 0xa1, 0x8e, 0x87, 0x4e, 0x99, 0x66, 0x39, - 0x75, 0xdc, 0x40, 0xfb, 0xec, 0x3f, 0x61, 0xe2, 0x25, 0xfd, 0x25, 0xea, - 0x54, 0x21, 0x6e, 0x6c, 0xe6, 0x3b, 0x41, 0x3e, 0xef, 0xc1, 0x81, 0x49, - 0xe9, 0x97, 0xea, 0xf8, 0xcc, 0x45, 0x1c, 0xcf, 0xc4, 0xd0, 0x44, 0xfd, - 0x85, 0x49, 0xb3, 0x91, 0xef, 0x84, 0x49, 0x2f, 0xbc, 0xf8, 0x35, 0x6c, - 0x3f, 0xa5, 0x40, 0x8b, 0x8a, 0x0e, 0xbe, 0x86, 0xf6, 0x33, 0x5f, 0x94, - 0x13, 0x98, 0xa5, 0xa6, 0xd5, 0x89, 0x02, 0xf1, 0x77, 0x55, 0x62, 0x04, - 0xac, 0xdf, 0x78, 0x73, 0x56, 0xc1, 0xd4, 0x34, 0xfb, 0xbd, 0x8d, 0x30, - 0x2b, 0x28, 0xd3, 0x1b, 0xb3, 0xbf, 0x81, 0x67, 0x4e, 0x52, 0x0f, 0x4f, - 0x07, 0xf1, 0xbd, 0x8c, 0x0b, 0xb7, 0x4e, 0x09, 0xa6, 0xd3, 0x62, 0x07, - 0x15, 0xe9, 0x8f, 0xa4, 0x6f, 0x89, 0x86, 0xdd, 0x8a, 0x03, 0xf5, 0xcf, - 0xb8, 0xa0, 0x9d, 0x0b, 0xc3, 0x5d, 0xef, 0x81, 0x56, 0xff, 0xfb, 0xcc, - 0x35, 0x0e, 0x94, 0xb1, 0x97, 0xed, 0xfc, 0x76, 0x8c, 0xd7, 0x82, 0xbc, - 0x86, 0xdf, 0x28, 0x87, 0x73, 0x95, 0x93, 0x35, 0xbc, 0x4c, 0x23, 0x1e, - 0x73, 0x99, 0xa6, 0x93, 0xb5, 0x61, 0xf7, 0x77, 0x4c, 0x33, 0xb2, 0x41, - 0x9e, 0x0f, 0x20, 0x72, 0x4e, 0xe3, 0x73, 0x76, 0xbd, 0xbc, 0x8e, 0xc7, - 0x9c, 0xf4, 0x23, 0x89, 0x55, 0xd6, 0x7b, 0xab, 0x87, 0xb2, 0x71, 0xfb, - 0x0b, 0x79, 0xc1, 0x36, 0x61, 0x4b, 0x86, 0xb3, 0xd3, 0x0a, 0x73, 0x76, - 0x82, 0xcf, 0x6e, 0x81, 0x33, 0xae, 0x4e, 0xa4, 0xe9, 0x07, 0x7b, 0x03, - 0x2d, 0x78, 0xce, 0x70, 0xa3, 0x52, 0x5b, 0x85, 0x07, 0x7a, 0x03, 0x78, - 0x8e, 0x7d, 0x01, 0x6d, 0x16, 0x2b, 0x80, 0x8d, 0xb4, 0x9f, 0xf4, 0x1c, - 0x3f, 0x84, 0xf6, 0x6d, 0x07, 0xf3, 0x9c, 0xd3, 0xca, 0x73, 0x65, 0xf5, - 0x40, 0x21, 0xe7, 0xc2, 0x05, 0xcd, 0xc6, 0x84, 0x2f, 0x58, 0x35, 0x5b, - 0x0d, 0x14, 0xae, 0x61, 0x41, 0xb5, 0x25, 0xa9, 0x90, 0x19, 0xbf, 0xe8, - 0xae, 0xdf, 0x65, 0xfb, 0xd2, 0xdf, 0x38, 0xa5, 0xe7, 0xb8, 0xfe, 0xbd, - 0x02, 0x8e, 0x84, 0x1a, 0x6a, 0x73, 0xc2, 0xe3, 0x4a, 0x0c, 0xb5, 0x8e, - 0x6b, 0x5f, 0xba, 0x81, 0xf7, 0x26, 0x8c, 0xe5, 0xaf, 0xf7, 0xda, 0x5d, - 0x19, 0xcb, 0x87, 0xba, 0x44, 0xf7, 0x4f, 0xe8, 0x92, 0x67, 0x53, 0x4a, - 0x3b, 0xf3, 0x56, 0xda, 0x85, 0x74, 0x15, 0x9f, 0xa1, 0xfe, 0x71, 0x74, - 0x52, 0xe8, 0x1c, 0xc6, 0x78, 0x46, 0x66, 0x1b, 0xc3, 0xd8, 0x6c, 0x44, - 0x62, 0x4b, 0xec, 0xa1, 0x8f, 0x40, 0xe6, 0x10, 0x8d, 0x85, 0x57, 0x14, - 0x35, 0x75, 0x8b, 0x53, 0x1d, 0x5a, 0x56, 0xec, 0xbc, 0xb5, 0xb6, 0x98, - 0xb7, 0xd6, 0xe4, 0x56, 0xf9, 0x7b, 0x58, 0x0f, 0x7a, 0x16, 0x4a, 0xf5, - 0xa1, 0x47, 0xe9, 0xb4, 0x6a, 0x6b, 0xbf, 0xb2, 0x63, 0xc1, 0xa3, 0x74, - 0x64, 0x3d, 0x78, 0x85, 0x58, 0x6c, 0xb6, 0x0f, 0x81, 0x5b, 0x37, 0xc2, - 0xbb, 0x23, 0xdb, 0x8b, 0x72, 0x4d, 0x7a, 0xc8, 0x72, 0x74, 0x5a, 0x75, - 0xad, 0xce, 0xdf, 0xc3, 0xfa, 0xd3, 0x93, 0xef, 0x63, 0xfe, 0x43, 0xc0, - 0x9b, 0xb0, 0x67, 0x06, 0x92, 0x0b, 0xef, 0xe0, 0xbb, 0x4b, 0xf1, 0x15, - 0x80, 0x5d, 0xff, 0x94, 0x7e, 0xf6, 0x12, 0xd5, 0x1b, 0x14, 0x5c, 0xba, - 0xcb, 0x03, 0xd2, 0x62, 0xcf, 0x7f, 0xb1, 0xf5, 0xc2, 0x74, 0xaf, 0xd2, - 0x31, 0x37, 0xef, 0xdd, 0x66, 0xc8, 0x2c, 0x62, 0xd6, 0xdb, 0x4e, 0x1e, - 0xda, 0x17, 0x9e, 0xf6, 0x6e, 0x25, 0x4f, 0x5b, 0x17, 0x3e, 0x4f, 0x53, - 0xea, 0xca, 0x44, 0x6b, 0x1b, 0x63, 0x7b, 0xb7, 0xfe, 0x91, 0x19, 0xfe, - 0x1d, 0xa1, 0xb3, 0x58, 0xd4, 0x67, 0x92, 0x7c, 0x05, 0x3d, 0x9d, 0xf9, - 0x80, 0x27, 0x99, 0x6f, 0xf7, 0xb6, 0x19, 0xbd, 0xde, 0xad, 0x46, 0x9f, - 0xb7, 0xdd, 0xb8, 0x87, 0xb4, 0x7b, 0xbc, 0x1d, 0x06, 0xe3, 0x3a, 0xdf, - 0x47, 0xbd, 0xf6, 0x62, 0x3c, 0x7f, 0x0f, 0xb1, 0x87, 0xd0, 0x1c, 0x20, - 0x0e, 0xf2, 0x52, 0xc6, 0x11, 0xca, 0x58, 0x08, 0xb9, 0x91, 0x54, 0xdd, - 0xd4, 0xd7, 0x98, 0x65, 0xc7, 0x09, 0x6b, 0x16, 0x55, 0x91, 0x98, 0x6c, - 0xed, 0x3e, 0xc1, 0x7c, 0x9f, 0x38, 0xda, 0x7a, 0xeb, 0x29, 0xd4, 0xb8, - 0x13, 0xd2, 0x3b, 0xb3, 0x1f, 0x8e, 0x46, 0xf5, 0xf7, 0x10, 0x0d, 0xbd, - 0xc2, 0x67, 0x47, 0xe9, 0xbb, 0x63, 0xd6, 0xfc, 0x81, 0x06, 0xc9, 0x35, - 0xa1, 0xdb, 0xf0, 0x78, 0x77, 0xb2, 0x37, 0xf3, 0x27, 0xd4, 0x96, 0x3b, - 0x9c, 0x32, 0x0f, 0x29, 0xfc, 0x96, 0x0f, 0x4d, 0xe8, 0xca, 0x7b, 0x28, - 0xd7, 0x97, 0xf0, 0x0f, 0x27, 0x59, 0xd7, 0x20, 0x7e, 0x68, 0x9a, 0xf7, - 0xb1, 0xaf, 0x39, 0x96, 0xab, 0xc3, 0x65, 0xcb, 0xc6, 0x2e, 0x1c, 0xcd, - 0x85, 0xf1, 0x0e, 0xe5, 0x73, 0x2d, 0xd6, 0xe2, 0xed, 0x69, 0x27, 0xf6, - 0xe9, 0xb7, 0x17, 0xeb, 0x85, 0x03, 0xf7, 0xc6, 0x0e, 0x11, 0x3b, 0x38, - 0x50, 0x4d, 0xfc, 0xf6, 0xb0, 0x75, 0xcd, 0xc9, 0xfe, 0xef, 0xb7, 0x91, - 0xb2, 0xeb, 0x09, 0x79, 0x7c, 0x94, 0x3c, 0x36, 0x7b, 0xb7, 0x66, 0x55, - 0xef, 0x9d, 0x59, 0x78, 0xdc, 0x89, 0xd1, 0xd6, 0x33, 0x27, 0x4d, 0x0c, - 0xea, 0xb7, 0xe1, 0xca, 0xc9, 0xd1, 0x21, 0x17, 0xfd, 0xe7, 0xe7, 0xf1, - 0x7e, 0x18, 0x33, 0xb8, 0x40, 0xe4, 0x71, 0xd1, 0xc7, 0xdc, 0xde, 0x10, - 0x8f, 0x06, 0x58, 0x8b, 0xf5, 0x05, 0xc6, 0x66, 0x07, 0xd4, 0x21, 0xd6, - 0xe4, 0xa4, 0x33, 0x11, 0x1d, 0x18, 0x23, 0x78, 0xac, 0x22, 0x3f, 0x5e, - 0xe6, 0x6e, 0xdf, 0x62, 0xd8, 0xbb, 0x9b, 0xf5, 0x26, 0xc4, 0xfe, 0xce, - 0x1b, 0xc5, 0xed, 0xb5, 0x88, 0xc6, 0x96, 0x29, 0xb7, 0x7b, 0xb1, 0xc9, - 0x7b, 0x07, 0xeb, 0xc7, 0xe5, 0xa8, 0x39, 0xf2, 0x92, 0xee, 0x83, 0x7f, - 0x51, 0xa7, 0xbe, 0xfb, 0x31, 0xba, 0xc0, 0x96, 0x2b, 0xca, 0x9e, 0x7f, - 0xb1, 0xc5, 0xbb, 0x93, 0xb1, 0x59, 0x45, 0x13, 0x35, 0x2e, 0x26, 0xbd, - 0xd2, 0xf3, 0x35, 0x2d, 0x6e, 0x22, 0x7f, 0xe2, 0xa3, 0x99, 0xd6, 0xcd, - 0xf4, 0x87, 0xf0, 0x22, 0x3a, 0x99, 0xe6, 0x5e, 0x26, 0xcd, 0xfe, 0x10, - 0x31, 0xec, 0x81, 0x8d, 0x3e, 0xe6, 0x29, 0xd1, 0x25, 0xf5, 0x98, 0x2f, - 0xc9, 0x24, 0x75, 0xf9, 0x68, 0xeb, 0xe2, 0x29, 0xa9, 0xcb, 0xa9, 0xd6, - 0xcc, 0x29, 0x0d, 0xef, 0xb0, 0xb6, 0xac, 0x8d, 0xab, 0xfa, 0x39, 0x25, - 0x12, 0xba, 0x48, 0x59, 0x5c, 0xf8, 0x85, 0xb9, 0x57, 0x8b, 0x16, 0x6e, - 0x61, 0x3c, 0x55, 0x33, 0x37, 0x86, 0x98, 0xf3, 0xab, 0x17, 0xa9, 0x98, - 0x45, 0xa7, 0x1b, 0x15, 0x21, 0x78, 0xa2, 0x1a, 0xde, 0x3d, 0x19, 0xa3, - 0x1e, 0xae, 0xd1, 0x3c, 0x48, 0xa8, 0x35, 0xc8, 0x52, 0xf8, 0xd8, 0x33, - 0xf4, 0xc5, 0x71, 0xae, 0x5b, 0xb6, 0x28, 0x3c, 0xcb, 0xf3, 0x41, 0x3e, - 0x7f, 0x7d, 0xed, 0x6a, 0xae, 0xfd, 0xd1, 0x29, 0xf1, 0xd7, 0x54, 0xeb, - 0x85, 0x93, 0xf6, 0xda, 0xd1, 0x78, 0x0c, 0x1f, 0x9e, 0x54, 0x87, 0xdf, - 0x55, 0x22, 0x03, 0x17, 0x14, 0x59, 0x1f, 0x75, 0x55, 0xb8, 0x62, 0x8e, - 0x46, 0xa3, 0xa9, 0xbd, 0xa4, 0xd9, 0xb2, 0x89, 0xfa, 0xb7, 0xf8, 0xa0, - 0xcf, 0x33, 0xcf, 0xba, 0xc9, 0x8f, 0xcd, 0x4b, 0x1d, 0x69, 0x9f, 0x2c, - 0xf6, 0x6a, 0xec, 0x53, 0xaf, 0xf3, 0x13, 0xa4, 0x1e, 0x3c, 0xbb, 0x9b, - 0x7d, 0xa8, 0xb5, 0x9e, 0x0b, 0xf0, 0x39, 0xd1, 0xc3, 0x2f, 0x15, 0x87, - 0xf6, 0x1e, 0xf3, 0x98, 0xe4, 0x92, 0x20, 0x73, 0xd8, 0x3d, 0xd2, 0xd3, - 0xa6, 0xd3, 0xf4, 0x77, 0x37, 0xfd, 0x7d, 0x9b, 0xf8, 0xb4, 0x41, 0x9f, - 0x36, 0xe8, 0xd3, 0x86, 0x1a, 0x1a, 0x46, 0x24, 0x30, 0x48, 0xbb, 0x25, - 0x43, 0xe2, 0xeb, 0x7d, 0xd8, 0xc7, 0xdf, 0xfd, 0xbc, 0x7f, 0x94, 0x7d, - 0x2e, 0x56, 0xc8, 0x9a, 0x87, 0xd1, 0x6e, 0x3c, 0x86, 0xa1, 0x2c, 0x7e, - 0xe5, 0x6d, 0x2e, 0x47, 0xf9, 0x1a, 0xe9, 0xe1, 0xd5, 0xc0, 0x31, 0x3c, - 0xc6, 0x3e, 0xea, 0x97, 0x4a, 0xa5, 0xe6, 0xea, 0x3d, 0xae, 0xa8, 0x81, - 0x76, 0xf6, 0xc3, 0x7b, 0xf3, 0xf7, 0xd0, 0xbe, 0x91, 0xa1, 0x57, 0x14, - 0xf6, 0x52, 0xb5, 0x5c, 0x9b, 0xb1, 0x74, 0x27, 0xd7, 0x31, 0x84, 0x0f, - 0x2b, 0xdf, 0xfe, 0x1e, 0x44, 0xb7, 0x3f, 0x6a, 0x18, 0xe4, 0xfa, 0x36, - 0x1f, 0xa3, 0xec, 0x29, 0x07, 0x19, 0x63, 0xfb, 0xac, 0xf8, 0xea, 0x23, - 0x8d, 0xeb, 0x79, 0x6c, 0x6b, 0x46, 0x6a, 0xa9, 0x89, 0xc7, 0x75, 0x13, - 0xcf, 0xf2, 0x77, 0x89, 0xb9, 0x6c, 0xec, 0x86, 0x5c, 0xe6, 0xe0, 0x73, - 0xbb, 0xf9, 0x5c, 0x0b, 0x53, 0xe7, 0xc2, 0x9c, 0xcc, 0x06, 0x0f, 0xcb, - 0x6c, 0x10, 0x39, 0x43, 0x74, 0x3f, 0x8c, 0x0b, 0x99, 0x48, 0xca, 0xe9, - 0x34, 0x47, 0x18, 0x57, 0x4b, 0x1f, 0xd1, 0x77, 0x5f, 0xdf, 0xa8, 0xf6, - 0x52, 0x87, 0xb1, 0x49, 0x45, 0x0d, 0xbd, 0x86, 0x42, 0xa7, 0x07, 0x8d, - 0xe1, 0x75, 0xce, 0x68, 0xe0, 0x2c, 0xd4, 0xc2, 0x20, 0x25, 0x7d, 0x3a, - 0x6f, 0xe7, 0xba, 0xcd, 0xc5, 0x5c, 0xd7, 0x92, 0xab, 0x50, 0xee, 0xcc, - 0xb2, 0x3e, 0xcf, 0x99, 0x69, 0x3f, 0xeb, 0x55, 0x7e, 0x4e, 0x68, 0x8f, - 0xa0, 0x31, 0x2e, 0xb4, 0xb4, 0xae, 0x49, 0x05, 0x5f, 0xaf, 0x44, 0x94, - 0xb5, 0x0a, 0x7a, 0xb9, 0x96, 0x36, 0x59, 0x93, 0x02, 0xee, 0x84, 0xd4, - 0xce, 0x1e, 0xf6, 0x2d, 0x7d, 0xcc, 0x8b, 0x82, 0xa9, 0x65, 0x5e, 0x6a, - 0xe7, 0xa3, 0x6d, 0x79, 0xb1, 0x8b, 0xd8, 0x44, 0x6c, 0x73, 0x18, 0x07, - 0xac, 0x79, 0xb4, 0x89, 0x69, 0x5d, 0x72, 0x83, 0xd8, 0xe9, 0x30, 0xf6, - 0xe7, 0xdd, 0xb8, 0x97, 0x79, 0x70, 0xbe, 0x99, 0xba, 0xf2, 0xbb, 0x31, - 0x38, 0x77, 0x3b, 0xf6, 0x65, 0x65, 0x9e, 0xe0, 0xa6, 0xfd, 0x92, 0xc4, - 0x40, 0xcc, 0x3a, 0xc4, 0x3f, 0x65, 0x5a, 0x49, 0xa7, 0x42, 0x5b, 0x74, - 0x5a, 0xfa, 0xbe, 0xe0, 0xb6, 0x75, 0x6c, 0xcf, 0x2d, 0x9d, 0x09, 0x59, - 0xab, 0x34, 0xb3, 0xb4, 0xf5, 0xda, 0x99, 0x91, 0x35, 0x4d, 0x9c, 0xd5, - 0x6d, 0x4c, 0x5b, 0xd2, 0x67, 0x88, 0x32, 0xd7, 0x6c, 0x02, 0xd6, 0xdd, - 0x80, 0x6b, 0x2b, 0x78, 0xad, 0xfb, 0x3a, 0xae, 0xed, 0x17, 0xec, 0x4c, - 0x5c, 0xdb, 0xb5, 0x83, 0xb8, 0xb6, 0x5e, 0x29, 0x61, 0x5a, 0x99, 0x59, - 0x94, 0x70, 0x6d, 0x75, 0x31, 0x7f, 0x1f, 0xc6, 0x5e, 0x62, 0x9e, 0xda, - 0xfa, 0x11, 0x78, 0xd6, 0x3b, 0x3e, 0x73, 0x60, 0x84, 0xbd, 0x4c, 0x19, - 0xb0, 0xd2, 0xc4, 0x2d, 0x1b, 0xd2, 0x66, 0xb9, 0x56, 0x1f, 0x2e, 0x77, - 0xc8, 0x4c, 0x3a, 0x9a, 0x1e, 0x63, 0x9e, 0x71, 0xac, 0x57, 0xd3, 0x49, - 0x78, 0x02, 0x35, 0xda, 0x3d, 0xc5, 0x5e, 0x22, 0xe4, 0xd9, 0x4e, 0x4c, - 0x14, 0x8d, 0x7f, 0x6a, 0xce, 0x06, 0x85, 0x46, 0xa1, 0xe0, 0x41, 0xf2, - 0x11, 0x0f, 0x6b, 0xd4, 0xb2, 0x32, 0x81, 0xd7, 0xa3, 0x21, 0xcf, 0xce, - 0x7c, 0xda, 0xdb, 0xdd, 0x70, 0x0b, 0x7a, 0x4e, 0x49, 0x3d, 0x0a, 0x63, - 0xc7, 0xa9, 0x76, 0xd6, 0x20, 0x0d, 0x1d, 0x93, 0x5d, 0xec, 0xf1, 0x7a, - 0x95, 0xde, 0x39, 0xd1, 0xa1, 0xd8, 0x40, 0x0d, 0x84, 0x1d, 0x37, 0xce, - 0x4c, 0x4b, 0xfd, 0xf2, 0x7b, 0x96, 0x7f, 0x8d, 0xeb, 0x01, 0xea, 0xe7, - 0xaa, 0x1b, 0x7e, 0x13, 0x67, 0x74, 0xf1, 0x4b, 0x7e, 0x37, 0x92, 0xd8, - 0xd6, 0x3c, 0x6d, 0xba, 0x34, 0x99, 0x7d, 0x87, 0x2c, 0x9b, 0x6e, 0x65, - 0x9d, 0x6b, 0x9f, 0xeb, 0xa3, 0x1d, 0x4b, 0x73, 0xee, 0x1b, 0xed, 0xb9, - 0xc5, 0xbb, 0x8d, 0x39, 0x8f, 0x3d, 0xbc, 0xc7, 0xc3, 0x3c, 0xea, 0x39, - 0x65, 0x62, 0x4e, 0x7f, 0xcb, 0x7c, 0x5c, 0x73, 0xd1, 0x6e, 0x5f, 0x65, - 0x4e, 0x16, 0xcc, 0x92, 0xf0, 0xde, 0x31, 0xe3, 0x72, 0x54, 0x25, 0xd0, - 0x5c, 0x46, 0x7f, 0xbc, 0x18, 0xb7, 0xe7, 0x91, 0xc7, 0x73, 0xb7, 0x7b, - 0xbb, 0xb3, 0xec, 0x33, 0xd8, 0x07, 0xdb, 0xbd, 0xdf, 0x57, 0xbd, 0x7b, - 0xb2, 0x4e, 0xa5, 0x36, 0x01, 0x67, 0xcb, 0x26, 0x13, 0x1f, 0x6f, 0x88, - 0xa6, 0x42, 0x0e, 0xe6, 0x4f, 0xd2, 0x32, 0x72, 0xcd, 0xde, 0x7e, 0xe6, - 0xeb, 0x9d, 0x59, 0xba, 0x01, 0x7d, 0xc7, 0xbf, 0x61, 0x74, 0xc0, 0x0f, - 0x99, 0xb3, 0xe1, 0xeb, 0x8c, 0xd8, 0x20, 0xfd, 0x31, 0xd4, 0xa6, 0x44, - 0x97, 0x87, 0x10, 0x5d, 0xfa, 0xd8, 0xf9, 0x96, 0xf9, 0x64, 0x6e, 0x13, - 0x9f, 0xef, 0x62, 0x2e, 0x4d, 0x32, 0xb7, 0x8e, 0xa6, 0xdc, 0x90, 0x77, - 0xd4, 0xfe, 0x37, 0x95, 0x08, 0xe3, 0x00, 0xbf, 0xc3, 0xe7, 0x03, 0x1d, - 0xcc, 0xa3, 0x73, 0x7a, 0x34, 0xb9, 0x15, 0xe9, 0xae, 0x6a, 0xa8, 0x7a, - 0x83, 0x22, 0x73, 0x31, 0xb1, 0x43, 0x0c, 0x3f, 0xe1, 0x9a, 0x2e, 0x4d, - 0xf4, 0xb8, 0x85, 0xbe, 0x48, 0x6c, 0xe0, 0xf8, 0xbc, 0xdf, 0xfd, 0x5e, - 0x19, 0x2a, 0x56, 0x50, 0xb6, 0x9f, 0x58, 0x39, 0xc7, 0xab, 0x69, 0xf8, - 0xaf, 0xc4, 0x4e, 0x7f, 0x96, 0x97, 0xf9, 0x67, 0x09, 0x0f, 0x8a, 0x6f, - 0x64, 0x5a, 0x6f, 0x9d, 0x8d, 0x15, 0xe7, 0xa1, 0x1e, 0x6f, 0xd7, 0x8c, - 0x89, 0xac, 0xee, 0x87, 0xf4, 0xff, 0xe5, 0xf1, 0x02, 0xd1, 0x41, 0x13, - 0x3a, 0x78, 0xbd, 0x7d, 0xa6, 0x52, 0x69, 0xcf, 0x9a, 0xf8, 0x33, 0x5d, - 0x4d, 0xb7, 0x39, 0x19, 0xef, 0xba, 0x7a, 0x16, 0xf8, 0x19, 0x71, 0x94, - 0xf8, 0x98, 0x0b, 0x3e, 0xcd, 0xa6, 0xd5, 0x34, 0x7b, 0x3b, 0xb1, 0x85, - 0xc4, 0x9f, 0x73, 0x6d, 0x05, 0x9a, 0x95, 0x59, 0x97, 0xe8, 0xad, 0x0b, - 0xc9, 0x7c, 0xa5, 0xb2, 0x8b, 0xba, 0xbc, 0x73, 0xbd, 0x17, 0x97, 0x2c, - 0x5d, 0xde, 0x4e, 0x5d, 0xe2, 0x8d, 0xd5, 0x70, 0x5e, 0xa8, 0x05, 0xc1, - 0x44, 0xb9, 0x1a, 0x1e, 0x70, 0x88, 0x4d, 0x18, 0x27, 0x82, 0xd5, 0x50, - 0xc9, 0x7a, 0x9e, 0x24, 0x0e, 0x26, 0x6e, 0x0c, 0xf4, 0xe1, 0xdb, 0xcc, - 0x4b, 0x8f, 0xd3, 0x6f, 0x7f, 0xa1, 0x35, 0xa1, 0xe2, 0x3b, 0xcd, 0xb4, - 0xe9, 0x26, 0xef, 0xf6, 0x6c, 0x3f, 0x9e, 0x58, 0x30, 0xf1, 0x0c, 0x63, - 0xa6, 0x21, 0x9e, 0x0e, 0x94, 0xb3, 0xaf, 0x63, 0xed, 0x5b, 0x3e, 0x61, - 0xf9, 0xfc, 0x68, 0xeb, 0x96, 0xf9, 0x10, 0x9c, 0xdf, 0xb6, 0xf6, 0x7e, - 0x5a, 0xc3, 0xf3, 0xd6, 0xde, 0x0f, 0x3f, 0x4d, 0x0c, 0xeb, 0x6a, 0xf2, - 0x63, 0x67, 0x05, 0x2a, 0xa3, 0xa6, 0x39, 0x1c, 0xb7, 0xf6, 0x1f, 0x5a, - 0x63, 0xd6, 0xfd, 0xa3, 0xfc, 0x2c, 0xcd, 0xae, 0xff, 0x46, 0x30, 0x63, - 0x38, 0x49, 0xf9, 0x77, 0x10, 0x07, 0xf4, 0x13, 0x07, 0xd4, 0x26, 0xd4, - 0xe4, 0x6e, 0xa7, 0xcc, 0x69, 0x0a, 0x87, 0xaa, 0x79, 0xfd, 0x8e, 0x22, - 0x0e, 0xa8, 0x3a, 0x25, 0xb3, 0x3f, 0x62, 0x45, 0xd8, 0x7b, 0x26, 0x3d, - 0xc4, 0x01, 0x15, 0x93, 0x2e, 0x74, 0x13, 0x03, 0xb8, 0x89, 0xd9, 0xb7, - 0xe5, 0x6a, 0xe1, 0x3d, 0xe1, 0x44, 0x24, 0xfe, 0x23, 0x1c, 0xa2, 0xbf, - 0x1d, 0x8a, 0x79, 0x94, 0xf0, 0x2a, 0x07, 0x75, 0xf6, 0x2b, 0x1c, 0x0c, - 0x38, 0x51, 0xa5, 0xbd, 0x86, 0x07, 0xbf, 0xa0, 0xf6, 0xf7, 0x67, 0x25, - 0xce, 0x47, 0x5b, 0xbb, 0x4f, 0xd9, 0xb5, 0xdf, 0x77, 0x6a, 0x74, 0x59, - 0x6a, 0x7f, 0xed, 0x86, 0x7e, 0x9c, 0x9e, 0xc1, 0x37, 0x57, 0x13, 0x64, - 0xd6, 0x72, 0xcd, 0xfa, 0x78, 0x94, 0x3d, 0xb8, 0x3a, 0xd4, 0xa1, 0x44, - 0x27, 0xaa, 0x98, 0x0f, 0x4e, 0xb3, 0xf6, 0x7b, 0x12, 0xd1, 0x40, 0xcc, - 0x81, 0x1e, 0x37, 0x6d, 0xf3, 0x3e, 0xfb, 0xf1, 0x9f, 0xe6, 0xc2, 0xa4, - 0x59, 0x06, 0x17, 0x6b, 0xff, 0xfb, 0x1a, 0x3e, 0x73, 0xd2, 0x0f, 0xdf, - 0x71, 0x7a, 0x70, 0x35, 0x67, 0xd7, 0xfe, 0xea, 0x06, 0x73, 0xe4, 0x72, - 0xdc, 0x87, 0x2b, 0x39, 0x9d, 0xfe, 0xd8, 0x8f, 0xa3, 0xac, 0xfd, 0x97, - 0xb5, 0x00, 0x3e, 0xcc, 0xb5, 0xd0, 0x47, 0x83, 0xf8, 0x39, 0x71, 0xf2, - 0x7a, 0xd6, 0xfe, 0xbb, 0xe8, 0x5f, 0x71, 0xd6, 0xfe, 0x36, 0x0b, 0x97, - 0x64, 0x5a, 0xcf, 0x4c, 0x5b, 0xb5, 0xbf, 0xc1, 0xc1, 0xba, 0xe9, 0x46, - 0x74, 0x99, 0x39, 0xc3, 0xfc, 0xc5, 0x26, 0x1f, 0x9f, 0xa5, 0xde, 0xf2, - 0x1b, 0x30, 0x6b, 0xd5, 0xaa, 0x2d, 0xde, 0x5d, 0x5c, 0x7b, 0xa5, 0x15, - 0x73, 0x26, 0x76, 0xac, 0xff, 0x6b, 0xfc, 0x41, 0x8d, 0x83, 0x3e, 0x99, - 0xf0, 0xde, 0xc9, 0xb8, 0xf3, 0x27, 0x4a, 0xb3, 0x91, 0x18, 0xd7, 0xb9, - 0xdd, 0x7b, 0x17, 0xfd, 0xe4, 0x96, 0xf5, 0xcc, 0x2a, 0x01, 0x3b, 0xe6, - 0xda, 0x19, 0x73, 0x21, 0xc6, 0xdc, 0x6a, 0xc6, 0xdc, 0x93, 0x7a, 0x34, - 0xb6, 0x85, 0xf8, 0xec, 0x95, 0x9c, 0xc4, 0x5d, 0x33, 0xe9, 0xaa, 0x94, - 0x6b, 0x74, 0x40, 0xe2, 0x67, 0xc7, 0xfa, 0xd1, 0xb3, 0x95, 0x10, 0x5d, - 0xe1, 0xb3, 0x95, 0xc4, 0x22, 0xcc, 0x52, 0x4b, 0xcb, 0xce, 0x68, 0xea, - 0x36, 0x67, 0x74, 0xf8, 0x3d, 0xe5, 0x2d, 0xf3, 0x0d, 0xc6, 0xdc, 0x4e, - 0xc6, 0xdc, 0x2e, 0xc6, 0x5c, 0x9b, 0x61, 0xe2, 0x85, 0xb8, 0xda, 0xdf, - 0xe4, 0x88, 0xe8, 0x6d, 0x0e, 0xac, 0xae, 0x64, 0x09, 0xf1, 0x22, 0xda, - 0xf5, 0x07, 0xe4, 0x7f, 0x49, 0x8f, 0xf6, 0xc6, 0x14, 0x89, 0xb3, 0x30, - 0x3e, 0xa0, 0xdc, 0xe5, 0xc5, 0x38, 0x3b, 0x30, 0x77, 0xbe, 0xe8, 0x1b, - 0x25, 0xd9, 0x9d, 0x78, 0x5e, 0x67, 0x5e, 0x5d, 0x21, 0xbe, 0xdb, 0x87, - 0x09, 0xea, 0xd1, 0x1b, 0xed, 0xc3, 0x31, 0xd6, 0xcd, 0xfb, 0x58, 0xaf, - 0xef, 0x37, 0x22, 0x2d, 0xdb, 0xd9, 0x27, 0x5d, 0x0a, 0xa9, 0xe1, 0xb0, - 0xd2, 0x87, 0x41, 0xfa, 0xf0, 0x20, 0xeb, 0x4b, 0x9b, 0xf1, 0x4b, 0xa5, - 0x83, 0x98, 0x62, 0x7f, 0x5e, 0xde, 0x53, 0x63, 0x69, 0xc7, 0x10, 0x06, - 0x16, 0x24, 0xcf, 0x21, 0x70, 0x53, 0xa2, 0x0f, 0x53, 0x46, 0x19, 0xfa, - 0x9a, 0x7b, 0x94, 0x3b, 0xf2, 0x32, 0xa7, 0x63, 0x6c, 0x1a, 0x8c, 0x5d, - 0x8b, 0x5f, 0x05, 0xb9, 0x68, 0x0f, 0x32, 0x12, 0xab, 0xc6, 0x2e, 0xe5, - 0xae, 0x39, 0x89, 0xf7, 0x3e, 0xa5, 0x4f, 0xe2, 0xd9, 0x48, 0x29, 0x77, - 0x4b, 0x7c, 0x5b, 0xb3, 0x6d, 0xc9, 0x01, 0xb2, 0xf7, 0x71, 0x3b, 0xf1, - 0x1e, 0x18, 0x5f, 0xce, 0xef, 0x84, 0x18, 0x83, 0x6d, 0x65, 0x0e, 0xfa, - 0x69, 0x84, 0xb6, 0x73, 0xa0, 0x5d, 0xff, 0xb2, 0x99, 0x0e, 0x0c, 0x30, - 0xa6, 0xfa, 0x70, 0xd4, 0x08, 0x99, 0x97, 0x2d, 0x1c, 0x53, 0xca, 0xf1, - 0x5b, 0x58, 0xeb, 0x56, 0xc1, 0xa3, 0x49, 0x7d, 0xf7, 0x21, 0x56, 0xe3, - 0x41, 0x85, 0x26, 0xb5, 0x27, 0xd3, 0xba, 0x78, 0x42, 0x91, 0x3e, 0xa5, - 0x18, 0xeb, 0x5b, 0xf0, 0x00, 0x73, 0xc2, 0xbe, 0xf8, 0xbd, 0xb8, 0x3f, - 0x50, 0x01, 0x3f, 0xf5, 0xf4, 0x50, 0xc0, 0xc7, 0x5c, 0xfb, 0x7b, 0x45, - 0x3a, 0x7f, 0x51, 0x56, 0xec, 0xbf, 0xaf, 0x61, 0xb0, 0x5a, 0xc6, 0xd8, - 0xe6, 0x19, 0x99, 0x27, 0xa5, 0x5a, 0x43, 0x33, 0x1a, 0xfc, 0xec, 0x7b, - 0xb7, 0xc4, 0xd5, 0xd4, 0x16, 0x67, 0x44, 0x7a, 0x9a, 0x8c, 0x9f, 0xf8, - 0x2f, 0x17, 0x8d, 0xf6, 0x36, 0x89, 0x8e, 0xb5, 0x10, 0x3a, 0xa9, 0xa7, - 0xee, 0x5c, 0x90, 0x31, 0xe4, 0x28, 0x17, 0x2c, 0x95, 0xcc, 0x5d, 0xa7, - 0x15, 0x22, 0xad, 0xd0, 0x8c, 0xe0, 0xba, 0x14, 0x71, 0x9d, 0xc6, 0x38, - 0x34, 0xcd, 0xcd, 0xc4, 0x73, 0xbe, 0x53, 0x32, 0x97, 0x8a, 0x4c, 0x10, - 0x03, 0x37, 0x11, 0x1f, 0xf7, 0xd1, 0xab, 0xcd, 0x5b, 0xea, 0xa3, 0x7a, - 0x9b, 0x82, 0xc7, 0xe6, 0x9b, 0xe1, 0x71, 0x92, 0xe6, 0x3b, 0xb9, 0x00, - 0x2e, 0xe7, 0x42, 0x78, 0x9b, 0xb4, 0x2f, 0x59, 0xb4, 0xeb, 0xf0, 0xb3, - 0x62, 0x0e, 0x8b, 0x33, 0x87, 0x6d, 0xcd, 0x2a, 0xf4, 0xd7, 0x30, 0x46, - 0xf4, 0xbf, 0xfa, 0xec, 0xd2, 0xcd, 0x1e, 0xea, 0x4d, 0x64, 0x71, 0xf1, - 0x73, 0x1c, 0x0f, 0x59, 0x39, 0xfb, 0xb5, 0xcf, 0x66, 0x6b, 0x68, 0x2b, - 0xea, 0xbe, 0xba, 0xf8, 0xde, 0xba, 0xd9, 0x3f, 0x2f, 0xca, 0xdb, 0x53, - 0xb4, 0x35, 0x71, 0x9b, 0x71, 0x9e, 0xd7, 0x04, 0x47, 0x69, 0x70, 0x9c, - 0x8a, 0xa1, 0xec, 0xd4, 0x35, 0xfe, 0x35, 0x89, 0x19, 0x56, 0xde, 0xc7, - 0xbe, 0x4b, 0x9e, 0x1e, 0x21, 0x5e, 0x34, 0xc9, 0xd3, 0x55, 0x8b, 0x97, - 0x20, 0x79, 0xf9, 0xe4, 0xb3, 0x12, 0xb6, 0x0c, 0x5d, 0x7b, 0x27, 0x40, - 0x7d, 0xe0, 0xd1, 0x10, 0xf5, 0x79, 0x65, 0xa3, 0x3c, 0xe7, 0xc3, 0x1d, - 0xb9, 0x44, 0xb9, 0xe4, 0x79, 0xaf, 0xb6, 0x05, 0x7b, 0xe7, 0x3e, 0xaf, - 0xf7, 0x20, 0x6d, 0x11, 0xa0, 0xf1, 0xe4, 0xde, 0x17, 0xd5, 0xd4, 0x3f, - 0x42, 0x8a, 0x3d, 0xd3, 0x23, 0xd9, 0x34, 0x1e, 0xca, 0x7e, 0xcb, 0xda, - 0xcb, 0x5b, 0xb7, 0x01, 0xfb, 0x49, 0xff, 0x60, 0x35, 0xe3, 0xe8, 0x7f, - 0xc4, 0xa3, 0x82, 0xa5, 0x76, 0x55, 0x42, 0xea, 0x6e, 0xb4, 0xe5, 0x36, - 0xc5, 0x44, 0x59, 0x1c, 0xc3, 0xed, 0xcd, 0xd1, 0xd8, 0x65, 0x3c, 0x66, - 0xca, 0x5c, 0xdc, 0x59, 0xac, 0xc1, 0xc4, 0xaf, 0x4a, 0x3b, 0xeb, 0x70, - 0x5b, 0x11, 0x53, 0x6d, 0xcd, 0xbf, 0xf5, 0xb9, 0xd9, 0x83, 0xf4, 0xed, - 0x52, 0x7b, 0xbc, 0x4a, 0x1b, 0xd7, 0x39, 0xca, 0x9c, 0xfd, 0xbc, 0xfe, - 0x52, 0x88, 0x95, 0x19, 0xae, 0xf5, 0x0a, 0x0e, 0x11, 0x3f, 0xa5, 0x83, - 0x26, 0x76, 0xf1, 0xf3, 0x00, 0x71, 0xd6, 0xbb, 0x7a, 0x15, 0x66, 0x03, - 0x01, 0x62, 0x4b, 0xe6, 0x60, 0xc7, 0xdf, 0x49, 0x4d, 0x88, 0x85, 0x1d, - 0xb2, 0x57, 0xff, 0x6f, 0xed, 0xdf, 0xac, 0x27, 0x96, 0x11, 0xd9, 0xbd, - 0x0a, 0x73, 0x68, 0x0c, 0xc4, 0x37, 0x7b, 0xf5, 0x42, 0xd8, 0x81, 0xe4, - 0x55, 0x07, 0xd4, 0xd3, 0xef, 0xb0, 0x1f, 0x7c, 0xa4, 0x5e, 0x3d, 0xdd, - 0xea, 0xd4, 0x90, 0x9a, 0xf2, 0xe0, 0xe1, 0xa9, 0x0e, 0x54, 0x5b, 0x73, - 0xa4, 0x71, 0xda, 0xcc, 0xc1, 0x3e, 0x6c, 0xf4, 0x53, 0x17, 0xfb, 0xb1, - 0xab, 0x1b, 0x1e, 0x45, 0x8b, 0x75, 0x7d, 0x0c, 0xfb, 0xb3, 0x5e, 0xa5, - 0x3b, 0xeb, 0x42, 0xc7, 0x5d, 0x8f, 0xc2, 0xbd, 0x7e, 0x80, 0x7c, 0xc9, - 0x75, 0xf9, 0xfb, 0x6e, 0xf6, 0x71, 0xc2, 0x5f, 0x19, 0xc2, 0xab, 0xc8, - 0xdb, 0x7a, 0x0d, 0x23, 0x53, 0x2e, 0x65, 0xb7, 0xf1, 0x37, 0xe6, 0x55, - 0x6b, 0x6f, 0x48, 0xae, 0x55, 0xc8, 0x99, 0x01, 0x3e, 0x23, 0x39, 0x67, - 0x10, 0x59, 0xc6, 0xf6, 0xdd, 0xd6, 0xfb, 0xa7, 0xca, 0x6c, 0x99, 0x92, - 0xec, 0x6f, 0xdb, 0xe9, 0x1f, 0xf2, 0x4c, 0x5b, 0xf1, 0xda, 0x76, 0x8f, - 0x7d, 0x2e, 0x41, 0xec, 0x3e, 0x88, 0x5b, 0x69, 0x84, 0xfa, 0xa8, 0xf8, - 0xd8, 0x20, 0xea, 0x73, 0x4c, 0xa8, 0xab, 0x6c, 0x7e, 0x1f, 0x34, 0x0a, - 0xec, 0x4d, 0x35, 0xe6, 0x4d, 0xea, 0x6e, 0xa5, 0xbc, 0x4f, 0x47, 0xfd, - 0xb5, 0xf7, 0x4b, 0xf5, 0x54, 0x70, 0xe9, 0x17, 0xdd, 0xff, 0x4d, 0xc8, - 0x3d, 0x97, 0xf6, 0x87, 0x8c, 0xe3, 0x68, 0x6f, 0xa5, 0x43, 0xfc, 0xe7, - 0x0f, 0x71, 0xff, 0x1c, 0x1b, 0xd7, 0x0a, 0xa1, 0x4f, 0xdc, 0x6b, 0xb8, - 0x94, 0x2e, 0xe6, 0x9f, 0x03, 0x53, 0x8e, 0x3b, 0xca, 0xf0, 0xe7, 0x66, - 0xf9, 0xca, 0x11, 0xd4, 0xc7, 0xc7, 0xf8, 0xbc, 0x82, 0x76, 0x62, 0xc8, - 0x27, 0xf4, 0xad, 0xe8, 0xa8, 0x91, 0x1c, 0xf0, 0xbc, 0x39, 0xd8, 0x27, - 0x3a, 0x54, 0xb0, 0x8d, 0xd7, 0x5f, 0xa0, 0x7d, 0x9f, 0xd6, 0x5d, 0xa8, - 0x5f, 0x21, 0x33, 0x41, 0x75, 0x3a, 0x89, 0x3d, 0x1e, 0x7b, 0x8f, 0x2c, - 0x6d, 0x56, 0x6b, 0xda, 0xf0, 0x9d, 0x8e, 0xfa, 0xe9, 0x37, 0xe9, 0x4f, - 0x6d, 0xeb, 0x6f, 0xbc, 0x57, 0xd2, 0x89, 0x8e, 0xd0, 0xfa, 0xe7, 0x4c, - 0xdc, 0x34, 0x8a, 0xc0, 0xfa, 0x1b, 0xed, 0x5f, 0xe2, 0xfb, 0x30, 0x63, - 0x10, 0xe9, 0xea, 0x84, 0xcc, 0x89, 0xa2, 0xa4, 0x73, 0x18, 0xbf, 0x9f, - 0x1f, 0xc3, 0xa1, 0xac, 0xc8, 0xb9, 0x60, 0xf9, 0xb6, 0xb6, 0xfe, 0xba, - 0x6c, 0x0f, 0x66, 0xa3, 0x03, 0x55, 0x45, 0xd9, 0x0e, 0xb2, 0x1f, 0xa9, - 0x64, 0x8e, 0x7d, 0x80, 0x3a, 0x1d, 0xb6, 0x74, 0xda, 0x07, 0x3d, 0x77, - 0x9d, 0xee, 0x10, 0xe9, 0x7a, 0x13, 0xa2, 0x37, 0xd9, 0x97, 0x63, 0x2f, - 0x40, 0xba, 0xfb, 0x6e, 0xa0, 0x3b, 0xa8, 0x5f, 0xa7, 0xbb, 0x37, 0x1b, - 0x3d, 0xed, 0x28, 0xd2, 0xfd, 0xc6, 0x5c, 0x89, 0x46, 0x1a, 0x3b, 0xd7, - 0xa7, 0x91, 0xdb, 0x7c, 0xd0, 0x3c, 0x68, 0xe9, 0xe3, 0xfb, 0xd6, 0xf5, - 0x6d, 0xf5, 0x12, 0x0f, 0xfc, 0x33, 0xa1, 0x59, 0x67, 0x00, 0x6c, 0x1c, - 0x76, 0x63, 0x7c, 0xa8, 0x6f, 0x75, 0x3b, 0x93, 0x8c, 0xe3, 0xa0, 0x67, - 0xfb, 0xe7, 0x66, 0x1f, 0x1d, 0xec, 0xd7, 0x3a, 0x8d, 0x1e, 0x6f, 0x97, - 0xe1, 0x21, 0x06, 0xab, 0x54, 0xb6, 0x65, 0x65, 0x06, 0x22, 0xb1, 0x5c, - 0xc4, 0xc5, 0x79, 0xe9, 0x0b, 0xef, 0x61, 0xcf, 0xb0, 0x81, 0xf6, 0x1d, - 0xc0, 0x44, 0x7e, 0x40, 0x49, 0x06, 0xb9, 0x8e, 0x21, 0x75, 0x05, 0xac, - 0x79, 0xbd, 0xa8, 0xa4, 0x2f, 0x05, 0x13, 0xd3, 0x89, 0x93, 0xf5, 0x26, - 0x88, 0x51, 0x3c, 0x2b, 0x12, 0xb3, 0x89, 0x5d, 0xf5, 0x4e, 0x1c, 0xb7, - 0xb0, 0x98, 0x3a, 0xcb, 0xdf, 0x69, 0x89, 0x99, 0x3b, 0xb3, 0x52, 0xc7, - 0x08, 0x27, 0xb5, 0x11, 0xfc, 0x63, 0xbc, 0x30, 0x5c, 0x83, 0xe4, 0x7d, - 0x35, 0x90, 0x1e, 0x63, 0x02, 0x7f, 0xa9, 0x85, 0x3c, 0xfd, 0x79, 0x97, - 0xd2, 0x6d, 0xcc, 0x7b, 0x77, 0x18, 0x7e, 0xf8, 0xd8, 0xbf, 0xf5, 0x38, - 0x23, 0xec, 0x39, 0xac, 0x19, 0x7d, 0xeb, 0xad, 0xb9, 0x7e, 0x6f, 0xbb, - 0x61, 0xe7, 0xc2, 0x5b, 0x66, 0x3d, 0xde, 0x8e, 0x99, 0x48, 0x68, 0xc2, - 0xc2, 0x62, 0x07, 0x5b, 0x23, 0x39, 0xd3, 0x7c, 0x55, 0x2f, 0x5c, 0x2d, - 0xb7, 0xbe, 0x4f, 0xb7, 0xc6, 0x72, 0x4d, 0xd8, 0x43, 0xfc, 0xd4, 0x36, - 0xd3, 0x04, 0x7d, 0x06, 0x38, 0x31, 0x15, 0xc2, 0xba, 0xac, 0x7a, 0x3a, - 0xe5, 0xec, 0xc7, 0xf4, 0x42, 0x17, 0xb2, 0x79, 0xef, 0x72, 0xd8, 0x41, - 0x8c, 0x1d, 0x77, 0xe0, 0x0e, 0x7d, 0x83, 0x52, 0xb0, 0x62, 0x5a, 0xc1, - 0xdd, 0xfa, 0x2e, 0x65, 0xc0, 0xc2, 0x14, 0xf3, 0xc4, 0x22, 0x0a, 0x6e, - 0xb2, 0x72, 0xef, 0xc9, 0xd6, 0x38, 0xf1, 0xf7, 0x1d, 0x59, 0xa9, 0xef, - 0x26, 0x2e, 0xc6, 0xa9, 0x97, 0x78, 0xba, 0xdf, 0xcd, 0x7e, 0xe8, 0xa0, - 0xa2, 0xf6, 0xea, 0x8a, 0x8d, 0xf1, 0x6e, 0x9b, 0xb7, 0x71, 0xe1, 0xad, - 0xf3, 0xcd, 0x5e, 0xc9, 0x41, 0xed, 0xba, 0x1a, 0x72, 0x39, 0x02, 0x18, - 0xb6, 0x68, 0xa4, 0x5b, 0xf5, 0xf9, 0x32, 0xac, 0xd6, 0xfa, 0x70, 0xda, - 0x92, 0x61, 0xa2, 0x75, 0x0b, 0xb1, 0xf6, 0x93, 0x46, 0x3f, 0x7b, 0x65, - 0xd9, 0x37, 0x8d, 0xc4, 0x5a, 0x9c, 0x6d, 0xc4, 0xb3, 0x91, 0xf0, 0xb2, - 0x92, 0x54, 0xd2, 0xae, 0xc6, 0xe4, 0x3c, 0x58, 0x51, 0x6a, 0xec, 0xfa, - 0x26, 0x32, 0x46, 0x89, 0xb3, 0xda, 0xa6, 0xbc, 0xcb, 0x49, 0xd8, 0x73, - 0x9e, 0x4e, 0xfd, 0xff, 0xe0, 0x52, 0x50, 0x9d, 0x48, 0x92, 0xef, 0x0e, - 0xe6, 0xdd, 0x42, 0x9f, 0x8b, 0xf7, 0x65, 0xbe, 0x37, 0xdc, 0x3a, 0x9e, - 0x41, 0xc1, 0x99, 0x90, 0x1e, 0x0b, 0xfe, 0xde, 0x3c, 0x64, 0xd6, 0xc4, - 0x3e, 0xe3, 0x53, 0xb3, 0xb4, 0xc7, 0xd4, 0x33, 0x63, 0xef, 0x9f, 0x65, - 0x16, 0x5c, 0xfe, 0x1d, 0x46, 0x33, 0x8e, 0xe7, 0x5d, 0x37, 0xd0, 0x8e, - 0x4e, 0xdc, 0xe2, 0x70, 0x20, 0xba, 0xfe, 0x6e, 0xa5, 0xb8, 0x07, 0xc5, - 0x3c, 0x91, 0xb2, 0x6a, 0x62, 0x19, 0xe5, 0xbc, 0x70, 0x52, 0xd6, 0xf8, - 0x56, 0xeb, 0xf8, 0x49, 0xa9, 0x91, 0xc3, 0xad, 0x21, 0x43, 0xed, 0x95, - 0x9e, 0xb0, 0x9a, 0x7a, 0xfa, 0x68, 0x52, 0x6a, 0xf0, 0x14, 0x6b, 0xb0, - 0xba, 0xdc, 0xae, 0x48, 0x1d, 0x53, 0x63, 0x5e, 0xa7, 0x03, 0x57, 0x1a, - 0xd4, 0xfe, 0x1f, 0x40, 0x1d, 0xb0, 0xe7, 0x8a, 0x8f, 0xb6, 0x36, 0x16, - 0xf1, 0xf0, 0x6d, 0xf3, 0x83, 0x72, 0xee, 0xc4, 0xd2, 0x71, 0x53, 0x4e, - 0xb0, 0xb1, 0x69, 0xbe, 0x1c, 0xef, 0x21, 0x6e, 0x10, 0x6c, 0x2c, 0xd7, - 0x27, 0x5b, 0x1b, 0x66, 0x3d, 0xe4, 0x4d, 0xc1, 0x7b, 0x5a, 0x0f, 0x7d, - 0xaf, 0xc4, 0xa3, 0x8d, 0x9b, 0xb7, 0x13, 0x37, 0x3b, 0x13, 0x6a, 0xcb, - 0x56, 0xe2, 0x66, 0x8d, 0xfd, 0x84, 0x0b, 0x7d, 0x78, 0xc2, 0xb0, 0x7b, - 0x0a, 0xc1, 0xce, 0xe6, 0x49, 0x35, 0x29, 0xb8, 0xf9, 0xea, 0x06, 0x60, - 0x37, 0x71, 0xf3, 0x72, 0xc6, 0x85, 0x7e, 0xe2, 0xe6, 0x8f, 0x98, 0x82, - 0xee, 0x24, 0x6e, 0xbe, 0x42, 0x8c, 0x75, 0x3e, 0xfe, 0x73, 0x7c, 0xa3, - 0x38, 0x3b, 0xdb, 0x4b, 0xec, 0x9c, 0x0c, 0xde, 0x88, 0x9d, 0xff, 0xe2, - 0x5f, 0x60, 0xe7, 0x3d, 0xc4, 0x84, 0x3d, 0x59, 0xd9, 0x67, 0x1a, 0x6d, - 0x7d, 0xe3, 0x94, 0x9c, 0x6d, 0xb9, 0x0d, 0xef, 0x9e, 0x1c, 0x1d, 0x22, - 0x56, 0xc6, 0x58, 0xbc, 0x1f, 0x99, 0x19, 0xac, 0x22, 0x2e, 0x78, 0xd9, - 0xc9, 0x75, 0xd7, 0xc5, 0x55, 0xfd, 0x4d, 0x25, 0xda, 0xd5, 0x8f, 0x28, - 0xfb, 0x66, 0x75, 0x99, 0x26, 0x4c, 0xba, 0x12, 0xc4, 0xc6, 0xac, 0x81, - 0xab, 0x89, 0x9d, 0xab, 0x16, 0x81, 0xda, 0x45, 0x1b, 0x3b, 0xcb, 0xdc, - 0xac, 0x2a, 0x8a, 0x3f, 0x22, 0x76, 0x66, 0xaf, 0xcb, 0x50, 0x5b, 0x6c, - 0x62, 0x8c, 0x2a, 0x38, 0x1a, 0xf5, 0xa1, 0x67, 0x8a, 0xb8, 0xc7, 0x9a, - 0x9b, 0x99, 0x23, 0x3f, 0xd6, 0xfb, 0x71, 0x6c, 0xc1, 0x9e, 0x9b, 0x75, - 0x12, 0xbf, 0xb9, 0xa2, 0x41, 0x94, 0x2f, 0xba, 0xf0, 0x1c, 0xf1, 0xf3, - 0x36, 0xda, 0xf9, 0x0c, 0xf1, 0xf3, 0x9e, 0x1b, 0x66, 0x67, 0xb3, 0x8b, - 0x78, 0x95, 0x58, 0xbe, 0xae, 0x16, 0x51, 0x99, 0x8b, 0x98, 0x57, 0x36, - 0xfa, 0x70, 0xce, 0xc2, 0xcf, 0xde, 0xe5, 0xb4, 0x62, 0xcb, 0x56, 0x46, - 0x5b, 0x88, 0x5d, 0x1d, 0xb4, 0x6b, 0xdb, 0x49, 0xb5, 0xeb, 0x25, 0xea, - 0xa2, 0x31, 0x7a, 0xde, 0xb2, 0xc7, 0x60, 0x5c, 0x66, 0x2c, 0x43, 0xad, - 0x72, 0xfe, 0xaa, 0x82, 0xf6, 0xee, 0x9e, 0x8c, 0x24, 0x3f, 0x80, 0x1d, - 0x93, 0xb1, 0x5c, 0x59, 0xb1, 0x1e, 0xca, 0xbd, 0x09, 0xde, 0x4b, 0xa2, - 0x6b, 0xa3, 0xed, 0xdf, 0xb1, 0xdc, 0x71, 0x62, 0x57, 0xd9, 0x5b, 0x0d, - 0xf8, 0x3b, 0x8d, 0x2e, 0x4c, 0x1b, 0x61, 0x94, 0x9f, 0x2b, 0xee, 0xd1, - 0x9e, 0x93, 0x33, 0x7b, 0x8f, 0xb6, 0x06, 0xbe, 0x53, 0xc2, 0x84, 0x49, - 0xe2, 0xbb, 0xa0, 0xe7, 0x8e, 0xbc, 0xe0, 0xc5, 0x5e, 0x1c, 0x33, 0xd4, - 0xd0, 0x4f, 0x18, 0x13, 0xf7, 0xc9, 0xfe, 0xfc, 0x0d, 0x33, 0xaa, 0x87, - 0x79, 0xcf, 0xf8, 0xdc, 0x8c, 0x2a, 0x95, 0xc5, 0xaf, 0x9c, 0xcd, 0xe5, - 0x70, 0xac, 0x93, 0x19, 0x89, 0x1a, 0x1a, 0xc3, 0x63, 0xc4, 0x1c, 0xbf, - 0x54, 0x7c, 0x9a, 0x6b, 0xa8, 0xc9, 0xa9, 0x86, 0xe6, 0x15, 0x1f, 0xdf, - 0xbd, 0x87, 0xf9, 0xed, 0x1e, 0xfa, 0x46, 0x64, 0xb9, 0x42, 0x71, 0xe2, - 0xd2, 0x97, 0x2d, 0x3c, 0xea, 0xed, 0xe5, 0xb5, 0xe9, 0x7c, 0x09, 0xd7, - 0xf4, 0x09, 0xaf, 0xe8, 0x9c, 0xb2, 0x73, 0x88, 0x96, 0xf3, 0x2e, 0x5f, - 0x82, 0x2d, 0x5b, 0x25, 0x65, 0x7d, 0x60, 0x32, 0x60, 0x0e, 0xac, 0x94, - 0x18, 0xd6, 0xb0, 0xd3, 0x10, 0xff, 0x1a, 0x24, 0x9f, 0x7d, 0x38, 0x62, - 0xac, 0x66, 0xef, 0x26, 0xf3, 0xd2, 0x26, 0x62, 0xeb, 0x5e, 0xd6, 0x60, - 0xd3, 0x4c, 0xe9, 0x69, 0xb3, 0x69, 0x93, 0xa6, 0xe7, 0x94, 0x42, 0x4d, - 0x88, 0xf8, 0x66, 0x3d, 0x6b, 0x77, 0x5b, 0xbe, 0x09, 0x6f, 0x9e, 0xd1, - 0xe8, 0x9b, 0xed, 0xc4, 0xef, 0xbd, 0xb8, 0x97, 0xf2, 0x7c, 0x23, 0xff, - 0x4d, 0x24, 0xbf, 0xee, 0xc2, 0xc4, 0x54, 0x12, 0x5b, 0xd6, 0x8f, 0xe0, - 0xd2, 0xef, 0x78, 0x98, 0xab, 0x7c, 0x78, 0x72, 0x4a, 0xf2, 0x6b, 0x09, - 0x6f, 0xdf, 0x88, 0x45, 0x3c, 0x08, 0x5b, 0x38, 0xe4, 0x8b, 0xef, 0xd9, - 0x18, 0xc5, 0xcb, 0x5e, 0xb8, 0xf4, 0x3e, 0xf3, 0xd0, 0xfa, 0x7f, 0x81, - 0x67, 0x88, 0x5b, 0x88, 0x05, 0x2a, 0x62, 0xd6, 0xf9, 0xb8, 0x12, 0xde, - 0x75, 0xd1, 0x07, 0x24, 0xa6, 0x57, 0x33, 0xd6, 0x4d, 0x62, 0xe7, 0xe5, - 0xe2, 0xfc, 0xf2, 0xed, 0x93, 0xea, 0xd2, 0x11, 0x44, 0x88, 0xa1, 0x31, - 0x28, 0xd8, 0xcd, 0x49, 0xbc, 0x7b, 0x25, 0x1a, 0xd5, 0xcf, 0x11, 0xef, - 0x8e, 0xd2, 0xd6, 0x2e, 0x4d, 0x7c, 0x33, 0x80, 0xb2, 0xc5, 0x10, 0x7d, - 0x52, 0xe6, 0x97, 0x7f, 0xe5, 0xb5, 0xe7, 0x97, 0x32, 0x33, 0x97, 0xf3, - 0x23, 0xe8, 0x28, 0x63, 0xef, 0x56, 0xae, 0xa4, 0x99, 0x93, 0x67, 0xbd, - 0xbb, 0x99, 0xdf, 0xfb, 0x8d, 0xa0, 0x7f, 0x77, 0x3e, 0xc0, 0xdf, 0x3a, - 0x7f, 0x7f, 0x7e, 0x07, 0x9f, 0x0f, 0xf1, 0x33, 0x8c, 0x6c, 0x2e, 0x52, - 0x21, 0xcd, 0x40, 0x36, 0x67, 0xe7, 0xbc, 0x70, 0xee, 0x90, 0x57, 0xb0, - 0x66, 0xdb, 0x94, 0xfd, 0x5d, 0xbb, 0xe1, 0xfb, 0xe7, 0x31, 0xbf, 0x9b, - 0x7c, 0x9f, 0x39, 0xa9, 0xe1, 0xa3, 0x93, 0x16, 0xe6, 0x2f, 0x10, 0xf3, - 0x0f, 0xbb, 0x9d, 0x82, 0x35, 0x7f, 0x61, 0x9e, 0x8f, 0x46, 0x07, 0xe6, - 0xe8, 0x07, 0x3d, 0xa4, 0xeb, 0xd0, 0x82, 0x16, 0xbf, 0x36, 0x9f, 0xf6, - 0xcc, 0xf7, 0xf2, 0xc9, 0x18, 0xde, 0xb9, 0x3e, 0x63, 0xfd, 0xa4, 0xcc, - 0x9a, 0x15, 0xe3, 0xb1, 0x77, 0x37, 0xc1, 0xd3, 0xc2, 0x7e, 0xd3, 0xcd, - 0xe7, 0x43, 0xd6, 0xf3, 0x32, 0xf3, 0xbd, 0x8e, 0x9d, 0x3f, 0xba, 0xfe, - 0xce, 0x61, 0x76, 0x6a, 0x9e, 0xf3, 0x8c, 0x2d, 0xa7, 0xf5, 0x9c, 0xcc, - 0x65, 0xbd, 0xcb, 0xb0, 0xe2, 0x6b, 0x88, 0x32, 0x89, 0x7d, 0x0f, 0x99, - 0xb6, 0xdf, 0x06, 0xfd, 0x3b, 0x19, 0x0f, 0xdf, 0xa6, 0x7d, 0x76, 0x9e, - 0xab, 0xf3, 0xdf, 0x6d, 0xec, 0xb2, 0x64, 0xbe, 0xfb, 0x9c, 0xd4, 0x24, - 0xb9, 0xff, 0x40, 0x85, 0x60, 0xef, 0x27, 0x59, 0xb3, 0x46, 0x0d, 0xd9, - 0x03, 0x80, 0xe2, 0x4a, 0x1c, 0x41, 0xe7, 0x74, 0x18, 0x6f, 0xeb, 0xde, - 0xe2, 0x59, 0x17, 0x89, 0xc9, 0x69, 0xc6, 0x64, 0x10, 0x63, 0x46, 0x24, - 0xfc, 0x36, 0xf1, 0x69, 0x9a, 0x0c, 0x1f, 0xcb, 0x3a, 0xf1, 0x36, 0x31, - 0x23, 0x14, 0xfb, 0xac, 0xa8, 0xfd, 0x6e, 0xe9, 0xef, 0x4a, 0x84, 0x6b, - 0x22, 0x2d, 0x07, 0x50, 0x87, 0x0c, 0x73, 0xbe, 0x57, 0xfb, 0x21, 0x8e, - 0x9f, 0x70, 0xe0, 0x7e, 0xf6, 0x7d, 0xc9, 0xbb, 0x74, 0x7e, 0x6f, 0x1c, - 0x7a, 0x1f, 0xff, 0x68, 0xce, 0xca, 0x79, 0x2c, 0x45, 0xce, 0x7c, 0x7c, - 0x62, 0xd6, 0x6a, 0x5a, 0xe1, 0x07, 0xd0, 0x52, 0x57, 0xd1, 0x38, 0xbc, - 0x8c, 0x0f, 0xcc, 0x02, 0xef, 0xbd, 0xc7, 0xf8, 0x79, 0x49, 0x8f, 0x84, - 0x1c, 0x14, 0xa6, 0x10, 0x74, 0xe2, 0x3e, 0x5d, 0xe6, 0x29, 0xea, 0xf0, - 0xb3, 0x50, 0x87, 0x2e, 0x28, 0x72, 0x86, 0xe7, 0x92, 0x99, 0xae, 0x91, - 0x75, 0x15, 0xac, 0x5b, 0xd3, 0xd8, 0x55, 0x06, 0xb5, 0xc5, 0xad, 0x68, - 0xfa, 0xfb, 0xca, 0xff, 0x32, 0x0b, 0xc1, 0x4f, 0xcc, 0x77, 0xb4, 0x12, - 0x5d, 0x35, 0xec, 0x71, 0x96, 0x78, 0xab, 0xc3, 0x71, 0x43, 0xf6, 0xf1, - 0x7e, 0x88, 0xfb, 0x4f, 0xb8, 0xd0, 0x1e, 0xff, 0xb9, 0x99, 0x0e, 0x0a, - 0xcd, 0x50, 0x25, 0x2a, 0x84, 0xbe, 0x3d, 0xdb, 0x7e, 0x31, 0x0f, 0xa5, - 0xc3, 0x10, 0xbc, 0x2c, 0x7e, 0x3a, 0x0d, 0xd3, 0x90, 0x99, 0xa2, 0x89, - 0x3b, 0xe3, 0x23, 0x78, 0x2f, 0x9e, 0xfc, 0x4f, 0x1e, 0xa8, 0x4b, 0x97, - 0x9d, 0x6a, 0xa1, 0xc9, 0x19, 0x56, 0xbc, 0x0d, 0xda, 0x70, 0x83, 0x55, - 0x6f, 0x2e, 0xb2, 0x77, 0xf2, 0x31, 0xb7, 0x48, 0x8f, 0x39, 0x8d, 0xc5, - 0xc9, 0x34, 0x5c, 0xc4, 0x76, 0xa3, 0xcd, 0x6a, 0xff, 0x33, 0x8a, 0x1a, - 0x3a, 0xa8, 0x84, 0x95, 0x7b, 0xb5, 0x14, 0x9e, 0xd3, 0xa3, 0xc9, 0x36, - 0xa5, 0xce, 0xd3, 0x95, 0x2f, 0xd1, 0x6e, 0x27, 0x56, 0x51, 0x0b, 0x97, - 0x9d, 0xe5, 0xa8, 0xdd, 0xa0, 0x75, 0x95, 0x3b, 0xd5, 0xd4, 0xd7, 0x18, - 0x5f, 0xdb, 0xf3, 0x05, 0xef, 0xfb, 0x51, 0x07, 0xd6, 0x5a, 0xfb, 0x0d, - 0x99, 0xe2, 0xbc, 0x74, 0x1a, 0xdd, 0x93, 0xe6, 0x96, 0x8b, 0x71, 0x35, - 0xf4, 0x8c, 0x92, 0xde, 0xed, 0x23, 0xa6, 0x79, 0x00, 0x5a, 0x78, 0x81, - 0x75, 0xaa, 0x3d, 0xef, 0xc0, 0x2d, 0xa7, 0x84, 0x66, 0x86, 0x34, 0x8f, - 0xa0, 0xfc, 0x84, 0xb9, 0x65, 0xb7, 0xae, 0xa6, 0x2e, 0x3b, 0xd3, 0xff, - 0xbd, 0x96, 0x7a, 0xeb, 0x50, 0x64, 0xbf, 0x6d, 0x84, 0xb8, 0x62, 0x44, - 0xce, 0xcd, 0xc5, 0xfe, 0x98, 0x98, 0xe2, 0x5b, 0xf4, 0x55, 0x67, 0xc2, - 0x4f, 0x3e, 0xd5, 0xd8, 0x1c, 0x64, 0xce, 0x1e, 0xc6, 0x65, 0x3d, 0xed, - 0xed, 0x6c, 0x88, 0x11, 0x9b, 0x85, 0x58, 0x07, 0xc3, 0x38, 0x46, 0x8c, - 0x77, 0x24, 0x5f, 0x86, 0x42, 0x40, 0x23, 0x36, 0xeb, 0x85, 0x63, 0xd2, - 0xa7, 0xcc, 0x67, 0x22, 0x7a, 0x3b, 0xfe, 0x33, 0x0a, 0x21, 0x71, 0x91, - 0x23, 0xf0, 0x9d, 0xf8, 0x7b, 0xb3, 0x4a, 0xd3, 0x5a, 0x26, 0x15, 0xae, - 0xfb, 0x54, 0x88, 0x3a, 0xe6, 0x7b, 0x72, 0xbe, 0xc5, 0xe8, 0xc1, 0xbd, - 0x93, 0x41, 0xbe, 0x5f, 0x85, 0x75, 0x27, 0xc2, 0xb8, 0x12, 0xbf, 0x19, - 0x85, 0x1a, 0x1b, 0x03, 0x79, 0x35, 0xfa, 0x11, 0xfb, 0xac, 0x34, 0x7b, - 0x4a, 0xd9, 0x63, 0x3a, 0x62, 0x48, 0x7f, 0xee, 0xe2, 0x77, 0x1f, 0x7f, - 0x45, 0x9f, 0xdf, 0x2a, 0x62, 0x9d, 0xa9, 0xd6, 0xf0, 0xfc, 0xcf, 0x2b, - 0xec, 0x79, 0x5a, 0x98, 0xcf, 0x05, 0xac, 0x19, 0xe1, 0x28, 0x69, 0x9e, - 0x9d, 0x96, 0xbe, 0xad, 0x6d, 0xb3, 0xa7, 0xb8, 0x4f, 0xff, 0x53, 0xdd, - 0x81, 0x2d, 0xec, 0xed, 0x43, 0x9a, 0xd4, 0xcb, 0x51, 0xb5, 0x16, 0x9b, - 0x71, 0x3a, 0xc0, 0x26, 0x5c, 0xfb, 0x0f, 0x98, 0x08, 0xc4, 0x98, 0xf3, - 0x35, 0xbc, 0x9b, 0xf9, 0x32, 0xfb, 0x9d, 0x3a, 0x39, 0xe3, 0x83, 0x5b, - 0x4e, 0xb8, 0xb9, 0xe6, 0x16, 0xe2, 0x9a, 0x4e, 0xbc, 0x16, 0xb0, 0x7b, - 0x8d, 0xa3, 0xbc, 0x3e, 0x3e, 0xe7, 0x23, 0x16, 0xf5, 0xf0, 0xf7, 0x46, - 0xde, 0xbe, 0x88, 0x27, 0x91, 0xe5, 0xdf, 0xe2, 0xc9, 0x43, 0x3c, 0xa0, - 0xe1, 0x6a, 0xe6, 0x65, 0x5c, 0x21, 0xed, 0xf4, 0x9c, 0x4d, 0x73, 0x2a, - 0x2f, 0x74, 0x65, 0xbd, 0x48, 0xaa, 0xd6, 0x29, 0xf4, 0x7d, 0x72, 0xde, - 0xf7, 0xdf, 0xb9, 0x06, 0x91, 0xdd, 0x09, 0xf6, 0xc7, 0x7a, 0x03, 0xda, - 0x03, 0xb4, 0x97, 0x21, 0x6b, 0xa8, 0xec, 0x45, 0xe5, 0xdd, 0x10, 0xd6, - 0x4e, 0x9a, 0x23, 0xa1, 0x84, 0x5c, 0x37, 0xcd, 0xea, 0x4d, 0x5a, 0xe8, - 0x4d, 0xc5, 0xc5, 0x5a, 0xe7, 0xa2, 0x0e, 0xc6, 0x71, 0x36, 0xd3, 0xb8, - 0xf4, 0x1e, 0xb1, 0x53, 0x98, 0xbd, 0xde, 0x25, 0xe7, 0x38, 0xe6, 0x33, - 0x0b, 0x95, 0x32, 0x23, 0x18, 0xcf, 0xfb, 0x94, 0xb9, 0xcc, 0x91, 0x4a, - 0xc9, 0x45, 0x63, 0xf4, 0x85, 0xa6, 0x49, 0xe1, 0xd5, 0x1c, 0xa9, 0x22, - 0x9d, 0x63, 0xa4, 0x33, 0xb7, 0x51, 0xeb, 0x1f, 0x53, 0x44, 0x67, 0x3e, - 0xe2, 0xba, 0x8b, 0x32, 0x3f, 0xa3, 0xde, 0xfe, 0x94, 0xcf, 0x8b, 0xde, - 0x82, 0x78, 0xad, 0x48, 0xe7, 0x89, 0xfc, 0x12, 0xe6, 0x32, 0x1f, 0x58, - 0x7f, 0x8f, 0xe5, 0x63, 0xac, 0x7d, 0x83, 0xc8, 0x31, 0x9f, 0x4c, 0x66, - 0x1a, 0xfb, 0x27, 0xc9, 0x87, 0x7d, 0x36, 0x6f, 0x10, 0x4f, 0x17, 0x9f, - 0x19, 0xe5, 0xbb, 0xa3, 0xd7, 0xfe, 0x16, 0x1d, 0xd9, 0xfb, 0xff, 0xf6, - 0x1e, 0x43, 0x39, 0x6d, 0x67, 0xf7, 0xe1, 0x47, 0x0d, 0xb7, 0xcc, 0xc3, - 0xf1, 0xf2, 0xf4, 0x16, 0x8c, 0xe9, 0x7f, 0x8e, 0xbd, 0x94, 0x7b, 0x9c, - 0xfa, 0x3c, 0x61, 0x58, 0xfb, 0xfc, 0x72, 0xfe, 0x8b, 0xb9, 0xfa, 0x60, - 0xeb, 0x19, 0x62, 0xb1, 0xe3, 0x8c, 0x99, 0xfd, 0xf1, 0xc6, 0xde, 0x57, - 0xe8, 0x77, 0xc9, 0xdf, 0x96, 0xbd, 0x74, 0x60, 0x32, 0xfb, 0x0d, 0xcc, - 0xd6, 0x34, 0x2e, 0x3f, 0xcf, 0x9c, 0x70, 0x9a, 0x79, 0xca, 0xc5, 0x9c, - 0x50, 0x9d, 0x25, 0x86, 0x64, 0x9e, 0x2a, 0x30, 0x4f, 0xb9, 0xb4, 0xc6, - 0xa5, 0x79, 0xfc, 0x15, 0xf5, 0x22, 0xfc, 0x45, 0x62, 0xf3, 0x90, 0x67, - 0xed, 0xf9, 0xab, 0x36, 0x3f, 0x84, 0x4b, 0x37, 0xdb, 0x33, 0x34, 0x27, - 0x6b, 0xf6, 0xbe, 0x4c, 0x63, 0x60, 0x4c, 0x68, 0xf7, 0xa9, 0xa1, 0x34, - 0x6d, 0x35, 0x61, 0x61, 0xef, 0x61, 0xf6, 0x0b, 0x72, 0xde, 0xab, 0x0a, - 0x2e, 0xfa, 0xfe, 0x98, 0x2e, 0xe7, 0x20, 0x42, 0xfe, 0xed, 0xb4, 0xe1, - 0x98, 0xd1, 0xd8, 0x12, 0x51, 0x76, 0xe3, 0x52, 0x31, 0xc7, 0xda, 0x58, - 0x5a, 0xed, 0x3f, 0x86, 0xc6, 0xde, 0x07, 0xf0, 0x75, 0x24, 0x6b, 0x1a, - 0x07, 0xa6, 0x11, 0xd1, 0xef, 0x83, 0x9c, 0x1b, 0xb5, 0x69, 0xd5, 0xe7, - 0x9c, 0xc4, 0x23, 0x9f, 0x98, 0xab, 0xb5, 0x27, 0x30, 0x4d, 0xcc, 0xd8, - 0xb0, 0x5e, 0x5b, 0xfa, 0x6e, 0xf1, 0x9e, 0xbd, 0xa7, 0x24, 0xfe, 0xe2, - 0xa1, 0x0e, 0xca, 0xe1, 0x5a, 0x51, 0xc7, 0x35, 0xa8, 0x0b, 0xeb, 0x4c, - 0xf1, 0x45, 0x1c, 0xa2, 0xbf, 0x4d, 0xe7, 0x15, 0xe8, 0xf5, 0x17, 0x31, - 0x2c, 0xb5, 0x89, 0xef, 0xb4, 0x65, 0x7c, 0xc4, 0x29, 0x21, 0x94, 0x6b, - 0x91, 0xf0, 0x28, 0xe5, 0x6b, 0x63, 0x2e, 0x1f, 0x67, 0x0e, 0x49, 0x07, - 0x7c, 0xd6, 0x39, 0xd7, 0x72, 0x2d, 0x64, 0xfd, 0x6f, 0x82, 0xf4, 0x41, - 0x0d, 0xb3, 0xb2, 0x9f, 0x7d, 0x04, 0x17, 0xa7, 0x0b, 0x38, 0x1e, 0x4f, - 0xe2, 0x40, 0x4d, 0x00, 0x93, 0xc6, 0x4a, 0x6b, 0x6e, 0x20, 0xfd, 0x56, - 0x77, 0xf6, 0xb0, 0x35, 0x8b, 0xdc, 0x16, 0x77, 0xd4, 0xcb, 0x79, 0x8f, - 0x39, 0xf6, 0x5d, 0xd3, 0xfa, 0x08, 0x0e, 0xe9, 0xdf, 0x82, 0xbe, 0x42, - 0x72, 0xe7, 0x18, 0xce, 0xcf, 0x4a, 0x0d, 0x9b, 0x68, 0xbd, 0x75, 0x52, - 0xf4, 0xe3, 0x20, 0xe6, 0xf5, 0xa0, 0xc9, 0xc2, 0x70, 0xaf, 0xb7, 0xae, - 0x99, 0xb5, 0xb1, 0x5c, 0x53, 0x4e, 0xce, 0x66, 0x57, 0xc1, 0x4f, 0x7d, - 0x5d, 0x88, 0xbb, 0x99, 0x73, 0x44, 0x9f, 0x72, 0x16, 0xd0, 0x96, 0x33, - 0x96, 0x53, 0x30, 0xd6, 0x7c, 0xe3, 0x5e, 0x8b, 0xfc, 0x9f, 0xc2, 0xb5, - 0xf3, 0x89, 0xc5, 0xd9, 0xf8, 0x1f, 0x9b, 0x97, 0x6e, 0x12, 0xb9, 0x5b, - 0x7d, 0xcc, 0xe9, 0xe1, 0xd9, 0x6b, 0xfa, 0x15, 0x9d, 0x9e, 0x93, 0x9a, - 0x61, 0xe9, 0xdc, 0x9e, 0xb7, 0xa9, 0xc3, 0xef, 0x28, 0x8d, 0xac, 0x27, - 0xf4, 0xab, 0x1a, 0xfa, 0x5b, 0x13, 0x06, 0x56, 0x27, 0x5c, 0x7d, 0x57, - 0x8d, 0x2d, 0x68, 0xd9, 0xf0, 0xae, 0x89, 0x9b, 0xdb, 0xe0, 0xd4, 0xe4, - 0xfa, 0xac, 0x99, 0x0c, 0xc8, 0xdf, 0x4f, 0xfa, 0xa4, 0x96, 0xbf, 0x68, - 0x14, 0xcc, 0x35, 0x2b, 0x6d, 0x6c, 0xf8, 0xf7, 0x19, 0xd9, 0x07, 0x4b, - 0x9b, 0xec, 0xb5, 0x97, 0xde, 0x76, 0x1e, 0xc6, 0xdf, 0xe6, 0x8e, 0xe0, - 0xad, 0x69, 0x17, 0x71, 0xa6, 0xc8, 0xb2, 0x05, 0xd5, 0x1b, 0xa2, 0xc9, - 0x77, 0x99, 0x17, 0x97, 0x66, 0x4b, 0x7e, 0xf1, 0x7a, 0xeb, 0xda, 0x59, - 0x85, 0xb4, 0xaa, 0x50, 0x46, 0x39, 0x7f, 0xac, 0x3b, 0x11, 0x2e, 0x62, - 0x5b, 0x27, 0xf9, 0xdc, 0x97, 0xb1, 0x31, 0x6f, 0x24, 0x37, 0xed, 0xb3, - 0xe7, 0x5f, 0x3e, 0xe6, 0xd1, 0x71, 0x4c, 0x64, 0x1a, 0x63, 0xef, 0xc9, - 0x79, 0x1e, 0xf6, 0x62, 0x97, 0x30, 0x8e, 0x13, 0x99, 0x52, 0x0e, 0x0d, - 0xc9, 0x39, 0xd8, 0x58, 0xd8, 0x61, 0xe7, 0xc8, 0xb0, 0x43, 0x4d, 0xf3, - 0xd7, 0x27, 0xd8, 0x60, 0x34, 0x1f, 0x09, 0x95, 0xc3, 0x89, 0xfd, 0xba, - 0xed, 0x1f, 0xf5, 0xf3, 0x6e, 0x84, 0x57, 0x48, 0x5d, 0x96, 0x9a, 0xec, - 0x62, 0x4d, 0x5e, 0x89, 0xe4, 0x4a, 0x17, 0x5e, 0xd7, 0x44, 0x1f, 0x53, - 0x25, 0x7d, 0xe8, 0xe7, 0xf0, 0x90, 0x59, 0xe8, 0x15, 0x5f, 0x72, 0xe3, - 0x48, 0xd3, 0x9c, 0x39, 0x1b, 0x14, 0xd9, 0x9d, 0x38, 0xcd, 0xfc, 0x8a, - 0x9b, 0x23, 0xa1, 0xd3, 0xac, 0xd9, 0x63, 0x5a, 0xc9, 0xc7, 0xff, 0x63, - 0x91, 0x4f, 0xad, 0x7f, 0x01, 0x47, 0xf8, 0x77, 0x7d, 0xe8, 0x80, 0x62, - 0xaf, 0xb7, 0x66, 0xfe, 0x43, 0x5f, 0x69, 0x76, 0x2a, 0xcf, 0x86, 0x73, - 0xa7, 0xf9, 0x5d, 0x68, 0xf9, 0xe8, 0x9f, 0xe5, 0x18, 0x08, 0xca, 0x79, - 0x10, 0xd1, 0x8b, 0xec, 0x3f, 0x82, 0xfa, 0x30, 0xf1, 0x32, 0xf5, 0x71, - 0xe4, 0xda, 0xd9, 0x2b, 0x3b, 0x7f, 0x55, 0xf0, 0xfa, 0xf6, 0xf8, 0x4b, - 0x9b, 0xbd, 0xf8, 0x95, 0x79, 0x29, 0x18, 0x62, 0x4e, 0x10, 0x9b, 0xa6, - 0x2c, 0x1c, 0xe9, 0x24, 0x3e, 0xd9, 0x67, 0x9f, 0x33, 0x69, 0x95, 0xff, - 0xa1, 0x29, 0xca, 0x51, 0x18, 0x24, 0xce, 0x5e, 0xcc, 0x58, 0x67, 0xfb, - 0x06, 0xde, 0x54, 0x22, 0xcc, 0x35, 0x5f, 0xc2, 0x40, 0xad, 0xd0, 0x0b, - 0xf8, 0x77, 0xce, 0xc4, 0xa8, 0x83, 0x3a, 0xa1, 0x6b, 0x3e, 0xc3, 0x6e, - 0xee, 0xc8, 0xa4, 0xd0, 0x07, 0xc6, 0x26, 0x23, 0x43, 0x3f, 0x06, 0x36, - 0x57, 0x41, 0x4d, 0x2d, 0x14, 0xff, 0xdf, 0xe3, 0x67, 0x8a, 0xd0, 0x12, - 0x3a, 0x2e, 0x18, 0xcc, 0x71, 0x53, 0x8b, 0x15, 0xd4, 0x9d, 0xda, 0xfb, - 0x3d, 0xa5, 0x02, 0x4f, 0x3c, 0x15, 0x23, 0xef, 0x2b, 0xfc, 0xdb, 0x67, - 0x3c, 0xf0, 0x9e, 0xa9, 0x62, 0xcd, 0xf5, 0xe0, 0x72, 0x33, 0xed, 0xfa, - 0x54, 0x89, 0x77, 0x6b, 0x9f, 0x14, 0x8f, 0x67, 0xc3, 0x30, 0xe8, 0xb3, - 0x8b, 0x86, 0xec, 0x17, 0x7b, 0xac, 0xfc, 0xb9, 0xb4, 0xb1, 0xce, 0xda, - 0xaf, 0x7a, 0x3e, 0xaf, 0x85, 0xce, 0x2a, 0x55, 0xf8, 0xe0, 0x44, 0xe1, - 0xe6, 0x72, 0x98, 0x2f, 0xae, 0x4e, 0x44, 0xfb, 0xf7, 0xd2, 0xe7, 0xd7, - 0xae, 0x09, 0xb2, 0x97, 0x61, 0x4f, 0xb9, 0x49, 0xfa, 0xdf, 0x69, 0xf6, - 0xbf, 0xa5, 0xbd, 0x7f, 0x6d, 0xe8, 0x11, 0x25, 0xdd, 0xe9, 0x87, 0xf9, - 0x51, 0x79, 0xc2, 0xfc, 0xd8, 0x9d, 0x88, 0xf2, 0x7d, 0xd9, 0xdf, 0x33, - 0xcd, 0x9f, 0x36, 0x9b, 0x66, 0xae, 0x39, 0xd2, 0x1f, 0x70, 0x06, 0x70, - 0xa6, 0x41, 0xf6, 0x04, 0x1d, 0xf8, 0x20, 0xaa, 0x85, 0xf6, 0x42, 0xf6, - 0xe8, 0x99, 0xe3, 0x57, 0xca, 0xf9, 0xc4, 0x3a, 0x7f, 0x97, 0xb1, 0x02, - 0xcf, 0x2d, 0x6c, 0xc2, 0x80, 0x1b, 0xd6, 0xf9, 0x19, 0x53, 0xc7, 0x9b, - 0xab, 0x21, 0x75, 0x3b, 0xda, 0xf2, 0x08, 0x82, 0x58, 0xc8, 0x1f, 0xc1, - 0xc3, 0x27, 0x64, 0xaf, 0x71, 0xb2, 0xd5, 0x73, 0xc2, 0xfc, 0xfb, 0x50, - 0xa2, 0xc0, 0xbc, 0x68, 0x9a, 0x15, 0x9b, 0x1a, 0x43, 0x2c, 0x47, 0xc4, - 0x18, 0x69, 0xc1, 0xee, 0x43, 0x1f, 0xa0, 0x06, 0x67, 0xe7, 0x92, 0x37, - 0xb3, 0x97, 0xec, 0x7a, 0x5a, 0x09, 0xe0, 0x07, 0x94, 0xf1, 0xd9, 0xbc, - 0xe0, 0x14, 0xa3, 0xb5, 0xfb, 0xc4, 0x2a, 0xbc, 0xb8, 0x10, 0xc4, 0x59, - 0x43, 0x23, 0x4e, 0x82, 0x52, 0x99, 0x30, 0xab, 0xab, 0xc9, 0x6b, 0xa5, - 0xd3, 0x89, 0xce, 0xb8, 0xf4, 0x87, 0xda, 0x90, 0x4f, 0xc1, 0xaa, 0x72, - 0x68, 0xcb, 0x0f, 0x01, 0xc3, 0x5e, 0xf6, 0xab, 0x4f, 0x2b, 0xd1, 0xfe, - 0xf7, 0x9d, 0x41, 0xfc, 0x80, 0xf9, 0xe7, 0x7b, 0x79, 0x39, 0x5b, 0xc5, - 0x1c, 0x33, 0x17, 0xa6, 0xad, 0x3c, 0x70, 0xd4, 0x57, 0xe1, 0x28, 0xe3, - 0xe5, 0x65, 0xbd, 0x8c, 0x39, 0x4a, 0xce, 0x5a, 0x49, 0x7e, 0x7f, 0x54, - 0xce, 0x94, 0x98, 0xcf, 0x6b, 0x76, 0xbf, 0xaf, 0xcf, 0xdf, 0x78, 0x5e, - 0x39, 0xc0, 0xbc, 0xde, 0xd8, 0x1b, 0x52, 0x5e, 0x35, 0x93, 0xbf, 0xad, - 0x50, 0xce, 0x07, 0xab, 0x50, 0x61, 0xc9, 0x8a, 0xd1, 0x6c, 0xa9, 0xa6, - 0x54, 0x4b, 0x2f, 0xd7, 0x9b, 0x2e, 0xfa, 0x60, 0x25, 0x63, 0xfd, 0x18, - 0x6b, 0x74, 0xf9, 0x09, 0xa9, 0x25, 0xec, 0x5f, 0x94, 0x2d, 0xc4, 0xc2, - 0x82, 0x1b, 0x3c, 0x78, 0x20, 0xa0, 0xb6, 0xc8, 0x99, 0xed, 0x67, 0xf3, - 0x1d, 0x2e, 0x39, 0x3b, 0xf5, 0x5c, 0x5e, 0x6a, 0xb9, 0xe4, 0x82, 0xd2, - 0x7a, 0x21, 0xd4, 0x4e, 0x8a, 0x8d, 0x86, 0x5b, 0x3f, 0x9a, 0xf4, 0xc9, - 0xf9, 0xfa, 0x11, 0x07, 0x7b, 0x6d, 0xcf, 0xa4, 0x69, 0xee, 0x69, 0xd6, - 0x86, 0xb6, 0x38, 0x65, 0x6f, 0x39, 0x32, 0x70, 0x4e, 0x51, 0x5b, 0x26, - 0x94, 0x1b, 0xe9, 0xfc, 0xb7, 0x2a, 0x89, 0x91, 0x34, 0xe5, 0x7c, 0xdc, - 0x92, 0x69, 0x8a, 0x32, 0x95, 0xce, 0x16, 0x55, 0xe1, 0xf2, 0x34, 0x34, - 0x46, 0x2d, 0xce, 0xeb, 0x4c, 0x4e, 0x81, 0x68, 0xb2, 0x1d, 0xe2, 0xff, - 0xea, 0x80, 0x60, 0xa8, 0x4a, 0xe6, 0xe4, 0xb9, 0x69, 0xa9, 0x31, 0x8a, - 0xe0, 0x93, 0x34, 0xd7, 0xc6, 0x95, 0x8d, 0xc0, 0xab, 0x93, 0xf6, 0xde, - 0x7b, 0xf1, 0x2c, 0xb8, 0x75, 0xe6, 0xe1, 0x11, 0xeb, 0x2c, 0x83, 0xd0, - 0x3f, 0x8c, 0x33, 0x19, 0xc1, 0x94, 0xc3, 0xc4, 0x94, 0x91, 0x14, 0xf1, - 0x66, 0x4b, 0xde, 0x3e, 0x97, 0xa5, 0x7f, 0x44, 0x9f, 0x7f, 0x9a, 0x58, - 0xf5, 0x28, 0xec, 0xbd, 0xf7, 0x86, 0xe2, 0x59, 0x85, 0x48, 0xae, 0x4b, - 0xd9, 0x91, 0x97, 0x18, 0x9b, 0x66, 0x8c, 0xb5, 0x2b, 0xdb, 0x17, 0x3a, - 0x94, 0xee, 0x85, 0x1e, 0x65, 0x77, 0x5e, 0x7a, 0xd6, 0xc9, 0xd6, 0x07, - 0x4e, 0xec, 0x52, 0x76, 0xcc, 0xf5, 0x29, 0xc4, 0xb4, 0x01, 0x4f, 0xa2, - 0x5f, 0xe9, 0x59, 0xb0, 0xe7, 0xe7, 0x5d, 0xec, 0xbb, 0x76, 0x18, 0xa5, - 0x7e, 0x5e, 0xfe, 0xdf, 0x2b, 0x28, 0xff, 0x5b, 0x31, 0xb0, 0x4d, 0x31, - 0xcd, 0xdb, 0xe2, 0x7f, 0x27, 0xf6, 0x30, 0x9f, 0x8d, 0xb3, 0x36, 0x1a, - 0x55, 0x18, 0x64, 0xdf, 0x31, 0xaa, 0xdf, 0x5a, 0xdc, 0x2f, 0x13, 0x99, - 0xe4, 0x3c, 0x85, 0xf8, 0x2b, 0xd2, 0xe5, 0xe4, 0xe1, 0x1f, 0xc8, 0xff, - 0x81, 0xa2, 0x5c, 0x3d, 0x72, 0xa6, 0xc0, 0x7d, 0xfd, 0xbc, 0xd9, 0xf1, - 0xc9, 0xeb, 0x72, 0x31, 0xd7, 0x63, 0x9c, 0xf8, 0xf4, 0x80, 0xa2, 0xa6, - 0x9e, 0xb1, 0xe5, 0x5a, 0xba, 0xcc, 0x18, 0x1e, 0xb5, 0x62, 0xd8, 0x96, - 0x6b, 0x5d, 0x51, 0xae, 0xb5, 0xb9, 0x2e, 0xeb, 0x1c, 0x17, 0xf1, 0x7a, - 0xeb, 0xe2, 0xa4, 0x9c, 0x37, 0x93, 0xd9, 0xa5, 0xc8, 0x26, 0x72, 0x9c, - 0x30, 0x2b, 0xb4, 0x1e, 0x65, 0xa7, 0x75, 0xfe, 0x4c, 0xce, 0x7e, 0xc9, - 0x5e, 0x7f, 0x49, 0x2e, 0xa9, 0xe3, 0x2b, 0xfc, 0x1d, 0x33, 0x72, 0x1e, - 0xdb, 0x34, 0x5f, 0xd3, 0x83, 0x7e, 0x91, 0xe5, 0xac, 0x2e, 0xb2, 0xc8, - 0xb9, 0x92, 0x92, 0x3c, 0x5f, 0x2b, 0xca, 0x23, 0xb6, 0xba, 0x6e, 0xa7, - 0xd2, 0xff, 0x09, 0xbe, 0x9d, 0xb1, 0xcf, 0x9c, 0x94, 0xe4, 0xf1, 0x27, - 0x84, 0xff, 0x8b, 0xad, 0xe3, 0xd3, 0xc3, 0x78, 0x95, 0xf7, 0x7f, 0x9e, - 0x29, 0xc9, 0xe5, 0xc4, 0xfc, 0x5c, 0xe9, 0x2c, 0x1d, 0x5b, 0x4a, 0x23, - 0xa2, 0x8f, 0xd1, 0x8f, 0x6c, 0xf9, 0xe4, 0x2c, 0x5d, 0x63, 0xe1, 0xb2, - 0x35, 0xf7, 0x8a, 0x26, 0xd9, 0x2f, 0xe3, 0x6c, 0xfe, 0xd7, 0xed, 0xd7, - 0x94, 0xab, 0x60, 0x8f, 0x2c, 0xb4, 0x5f, 0x27, 0x6d, 0x39, 0x73, 0xa2, - 0xe0, 0x99, 0x39, 0x60, 0xce, 0xe0, 0xb2, 0x89, 0x11, 0x3c, 0xa9, 0x9b, - 0xe6, 0xd3, 0xcd, 0x9a, 0x9c, 0x15, 0xba, 0x50, 0x6b, 0xcd, 0x85, 0xa0, - 0x57, 0x69, 0xb2, 0x77, 0x27, 0xe7, 0x4d, 0xfa, 0xa8, 0x03, 0x91, 0x5d, - 0x7c, 0xa0, 0x64, 0x7b, 0x39, 0x07, 0x97, 0xa6, 0x7e, 0x44, 0x37, 0xa5, - 0xf3, 0x70, 0x32, 0x73, 0xb9, 0x51, 0x27, 0x5d, 0x96, 0x4e, 0x9e, 0xd5, - 0xc5, 0x5f, 0x99, 0x7d, 0xe8, 0xab, 0xf3, 0xc4, 0x0f, 0x63, 0xba, 0xdb, - 0xc2, 0x6a, 0x47, 0x89, 0x4f, 0x26, 0x18, 0x3b, 0x8f, 0x1b, 0x4b, 0x58, - 0xca, 0xbd, 0x8c, 0x57, 0xaf, 0xfd, 0xcf, 0x9c, 0xf8, 0x8b, 0xde, 0xd2, - 0x6d, 0x9d, 0x79, 0xfa, 0xa4, 0xe5, 0xd6, 0xa8, 0xe4, 0xa1, 0x1f, 0x36, - 0xc9, 0x19, 0xa8, 0xf2, 0x44, 0xe0, 0x6b, 0xb2, 0xbf, 0x55, 0x96, 0x98, - 0xfd, 0xea, 0x05, 0x4d, 0x74, 0xa3, 0x35, 0x9f, 0xd1, 0x44, 0xae, 0x1e, - 0x7d, 0xdc, 0xfa, 0x1f, 0xce, 0x96, 0x4d, 0xfb, 0x34, 0x89, 0x1d, 0xdf, - 0xc6, 0x36, 0x2b, 0x27, 0x9c, 0x4e, 0xdc, 0x66, 0xe9, 0xe0, 0x64, 0xe2, - 0x56, 0xeb, 0x73, 0x3a, 0x11, 0xb3, 0x3e, 0xff, 0x24, 0x61, 0xeb, 0x26, - 0x97, 0xa8, 0xb7, 0x3e, 0xe7, 0x13, 0xf6, 0xd9, 0xe9, 0xd9, 0x84, 0x66, - 0x7d, 0x3e, 0x9f, 0x88, 0x58, 0x9f, 0x67, 0x13, 0xb7, 0x5c, 0xe7, 0x8b, - 0x3f, 0xff, 0x0f, 0x4c, 0xd3, 0x85, 0x76, 0xdc, 0x3a, 0x00, 0x00, 0x00 }; + 0xad, 0x7b, 0x0d, 0x70, 0x94, 0xf7, 0x79, 0xe7, 0xef, 0xbf, 0x1f, 0xd2, + 0xae, 0xb4, 0x5a, 0xad, 0xf0, 0x82, 0x57, 0x89, 0x52, 0xf6, 0xf5, 0xbe, + 0x2b, 0x2d, 0x96, 0x80, 0x77, 0x41, 0x04, 0x11, 0x6d, 0xcd, 0x56, 0x08, + 0x21, 0x40, 0xd8, 0x32, 0x56, 0x92, 0x25, 0xc7, 0xd4, 0x2a, 0xc8, 0x20, + 0xdb, 0x18, 0x8b, 0x86, 0xe6, 0xe4, 0xd6, 0xad, 0xd6, 0x92, 0xc0, 0x60, + 0x56, 0xbc, 0x22, 0x82, 0x08, 0x77, 0xee, 0x26, 0xb2, 0x25, 0x2c, 0xec, + 0xac, 0x58, 0x3b, 0xbd, 0xeb, 0xc5, 0x33, 0xc9, 0x58, 0x67, 0x6c, 0x4c, + 0x72, 0xfe, 0xc8, 0x75, 0x3a, 0x3d, 0xf7, 0xe6, 0xee, 0xca, 0xf8, 0x83, + 0xd8, 0x6e, 0x8c, 0xdd, 0x4c, 0x3a, 0x27, 0x52, 0xdb, 0xef, 0xfd, 0x9e, + 0xf7, 0xdd, 0x05, 0xe2, 0xba, 0xd3, 0x99, 0xce, 0x69, 0x66, 0x67, 0xa5, + 0xf7, 0xe3, 0xf9, 0x3f, 0xdf, 0xcf, 0xef, 0x79, 0xfe, 0x7f, 0xd5, 0x03, + 0x15, 0x28, 0xfe, 0x54, 0xf1, 0xd3, 0x3c, 0x30, 0x78, 0x70, 0xd5, 0x8a, + 0xe6, 0x15, 0xf6, 0x05, 0x97, 0xc7, 0x23, 0x37, 0xbf, 0xaa, 0x80, 0xde, + 0x0f, 0xf0, 0x6f, 0xfa, 0xf9, 0xca, 0xbf, 0xed, 0x35, 0xfb, 0xc7, 0x0d, + 0x84, 0x4a, 0x7c, 0xc9, 0x07, 0x3e, 0x57, 0xea, 0xd2, 0xd7, 0xda, 0x74, + 0xf8, 0xdc, 0xa9, 0x93, 0xa9, 0xdd, 0x3a, 0x90, 0xce, 0x37, 0x46, 0x37, + 0xe0, 0x53, 0x2b, 0x1b, 0xf6, 0x40, 0xae, 0x7f, 0x25, 0xf5, 0xc9, 0xd0, + 0x4f, 0xd6, 0x6a, 0x1f, 0x4f, 0xb9, 0xe1, 0x0b, 0xa5, 0x4e, 0x23, 0x54, + 0x0f, 0x5f, 0x1d, 0xdf, 0xf9, 0x0f, 0x0d, 0xd5, 0x6e, 0x04, 0x4b, 0xb4, + 0x5a, 0x30, 0x62, 0x22, 0xeb, 0x4b, 0x0d, 0xa0, 0x7c, 0x0d, 0xf0, 0x6e, + 0x2e, 0x6e, 0x8c, 0x00, 0xe3, 0xae, 0x54, 0x3c, 0xfa, 0x22, 0x0c, 0x1c, + 0x2a, 0x44, 0xd1, 0xce, 0xcf, 0x66, 0xf3, 0x33, 0x2b, 0xea, 0x45, 0xd6, + 0xcd, 0xe7, 0x76, 0x35, 0x03, 0x1b, 0x73, 0x06, 0x0e, 0x9b, 0xf0, 0xd5, + 0xa6, 0x1e, 0xc6, 0x3a, 0x7e, 0x07, 0x53, 0x83, 0x78, 0x7d, 0x2c, 0x16, + 0x7d, 0x0a, 0x5a, 0x46, 0x77, 0x6b, 0x83, 0x40, 0x63, 0x7f, 0x9f, 0xd2, + 0x7a, 0xdf, 0x50, 0x5a, 0xf7, 0x98, 0x82, 0x4f, 0xf1, 0xb9, 0xc6, 0xbc, + 0x7c, 0x0f, 0xe2, 0xd6, 0xbc, 0x0f, 0x97, 0xdc, 0xb2, 0xfe, 0xef, 0x52, + 0xdf, 0x0a, 0x1e, 0xbd, 0x05, 0xa3, 0xe4, 0xc1, 0x9b, 0x52, 0x78, 0xb2, + 0x39, 0x1e, 0x19, 0x86, 0xdc, 0x8f, 0x62, 0x43, 0x41, 0xbe, 0x35, 0x4a, + 0x6d, 0x59, 0xa3, 0x86, 0x65, 0x9d, 0x31, 0xca, 0x91, 0x0d, 0x69, 0x11, + 0x40, 0x61, 0xd8, 0x70, 0x21, 0x1d, 0x6a, 0x8b, 0x7a, 0xa0, 0x45, 0xee, + 0xc1, 0x3f, 0x51, 0xe6, 0x74, 0xc2, 0x0b, 0xe7, 0xf9, 0x5e, 0x94, 0x63, + 0x3e, 0xe4, 0x68, 0xed, 0xc9, 0x9c, 0x65, 0x5d, 0xd0, 0x3d, 0x38, 0x43, + 0xfd, 0x0c, 0xe7, 0xff, 0xc9, 0x9a, 0xa7, 0x6e, 0x46, 0xf5, 0xd2, 0xfa, + 0x3e, 0x4c, 0x85, 0x2c, 0x6b, 0x9a, 0xf7, 0x0e, 0xe7, 0x4b, 0x7a, 0xb6, + 0x2c, 0x97, 0x6e, 0x59, 0xbb, 0xf5, 0xdf, 0x58, 0xbb, 0x7e, 0xeb, 0x59, + 0xcb, 0x7a, 0xcc, 0xb8, 0x09, 0x67, 0x27, 0xda, 0xd5, 0x96, 0xd9, 0x25, + 0xc1, 0xcd, 0x93, 0x16, 0x2e, 0x18, 0x08, 0xb9, 0x52, 0x1d, 0x6a, 0xf3, + 0x6c, 0xa7, 0xda, 0x58, 0xd8, 0xae, 0x3a, 0xa6, 0xbf, 0xa5, 0x3a, 0x67, + 0x7b, 0xd5, 0xa6, 0x42, 0x04, 0x33, 0x66, 0x18, 0xd3, 0x66, 0x46, 0xb5, + 0xcf, 0xf6, 0x28, 0x47, 0x8e, 0x41, 0xd5, 0x56, 0x28, 0xd1, 0xba, 0xae, + 0xc7, 0xcd, 0xb9, 0x14, 0x8e, 0x98, 0xe5, 0x5c, 0x67, 0xc1, 0xfa, 0x49, + 0xc3, 0x02, 0xe5, 0x34, 0x70, 0xb4, 0xf0, 0x18, 0xb6, 0x4d, 0x5a, 0x56, + 0x3e, 0x09, 0xe4, 0x0b, 0xc0, 0x0f, 0xcc, 0x58, 0x77, 0xbf, 0xb2, 0xac, + 0x4d, 0x71, 0x6b, 0xe9, 0x65, 0xa3, 0x31, 0xf1, 0x12, 0xfe, 0xaf, 0x35, + 0x15, 0x46, 0x36, 0x40, 0x1a, 0xc7, 0x68, 0xb3, 0xfb, 0xc6, 0xe0, 0x2b, + 0x4f, 0x8d, 0xe2, 0x17, 0x39, 0xf8, 0xca, 0x52, 0x59, 0x5c, 0xc8, 0x0d, + 0x87, 0x7c, 0x88, 0x45, 0x36, 0xab, 0xec, 0xa0, 0x0b, 0xda, 0xc0, 0xdb, + 0xd0, 0xa2, 0xb4, 0xc7, 0xc5, 0xf3, 0x4a, 0x9b, 0x7f, 0x09, 0x5a, 0xfa, + 0x37, 0x4a, 0xeb, 0xac, 0x75, 0x23, 0xed, 0x8a, 0xfb, 0xf0, 0x93, 0x06, + 0xb1, 0xc9, 0x28, 0x56, 0xd8, 0xb6, 0xc9, 0x62, 0xd9, 0x35, 0xdb, 0xa4, + 0x30, 0x4c, 0xbe, 0x0e, 0x93, 0xaf, 0x97, 0x0d, 0x2d, 0xf2, 0x24, 0xac, + 0xa5, 0x7d, 0x86, 0xdc, 0x4b, 0x61, 0xb4, 0x60, 0x45, 0x83, 0xa9, 0x4b, + 0xe4, 0x17, 0xd9, 0x2f, 0xa5, 0x7c, 0xd9, 0xea, 0xd4, 0xa7, 0xd6, 0x6b, + 0x6b, 0x22, 0x78, 0xa1, 0x10, 0xc6, 0x73, 0x85, 0x10, 0x9e, 0x2d, 0xb4, + 0xc3, 0x2c, 0x20, 0xb8, 0xad, 0xf0, 0x45, 0x7e, 0x6c, 0x21, 0xc0, 0xe7, + 0xc9, 0x77, 0x70, 0x6b, 0xc1, 0xd3, 0x5b, 0x96, 0x42, 0xf7, 0x4f, 0x73, + 0x43, 0x56, 0x85, 0x8e, 0xde, 0x9a, 0x94, 0x9e, 0xbe, 0x55, 0x05, 0x5a, + 0xe8, 0x87, 0xdd, 0xaf, 0xe4, 0x5b, 0x3c, 0xfa, 0x71, 0x3f, 0xbc, 0xd4, + 0xff, 0xc6, 0x82, 0x65, 0x8d, 0x18, 0x07, 0x56, 0xee, 0x6a, 0xf9, 0x8b, + 0xf9, 0x6e, 0xbd, 0x0b, 0xd9, 0x42, 0x1f, 0x10, 0x4c, 0xf1, 0x9b, 0xa1, + 0xb8, 0xbd, 0xa9, 0x3d, 0x7a, 0xee, 0x01, 0x8f, 0xe3, 0xcf, 0xe4, 0x81, + 0x7a, 0x7f, 0xce, 0x24, 0x0f, 0xe6, 0xe1, 0x20, 0x2a, 0xa2, 0x94, 0xef, + 0xe7, 0xe4, 0x33, 0x81, 0x1f, 0x16, 0x74, 0xf2, 0xd6, 0x44, 0x1e, 0xa3, + 0xe4, 0xcf, 0x87, 0x5d, 0x13, 0xda, 0x78, 0x16, 0xda, 0x91, 0x29, 0x2c, + 0x47, 0x3a, 0x1c, 0xa2, 0x0f, 0xfe, 0x39, 0x1c, 0x1a, 0x5d, 0x38, 0x6e, + 0x62, 0x55, 0x28, 0x45, 0xfb, 0x26, 0xf1, 0x70, 0x19, 0xe2, 0xbd, 0x1f, + 0x2b, 0x85, 0xd7, 0xe2, 0x5d, 0x18, 0xa3, 0x3c, 0x5d, 0x79, 0x3f, 0xee, + 0x9f, 0xa8, 0xc0, 0xbd, 0x13, 0x16, 0xee, 0x4b, 0x22, 0x55, 0x41, 0x79, + 0x12, 0xc9, 0x78, 0xf4, 0x3d, 0x78, 0xd0, 0x9e, 0xef, 0x62, 0x2c, 0x6d, + 0x40, 0xba, 0xcc, 0x87, 0x0d, 0xf9, 0x00, 0xe3, 0x31, 0x8d, 0xd3, 0x93, + 0x3e, 0x78, 0x57, 0xbb, 0x30, 0x15, 0x2e, 0x43, 0xa2, 0xde, 0xc5, 0x4f, + 0x38, 0xd8, 0x36, 0x59, 0x17, 0xdc, 0x68, 0x7a, 0xb0, 0xd7, 0x74, 0x61, + 0x68, 0xc2, 0xb2, 0xda, 0x0d, 0x0b, 0x57, 0x57, 0x87, 0xf0, 0x3c, 0xf5, + 0x77, 0xc0, 0x8c, 0xe0, 0x6c, 0xe1, 0x51, 0xf2, 0x12, 0x76, 0xf8, 0x35, + 0xc9, 0xbb, 0x49, 0xde, 0x4d, 0xf2, 0x6d, 0x0a, 0x9f, 0xe7, 0x19, 0x33, + 0x06, 0xe5, 0xf2, 0x93, 0x87, 0x4a, 0xf4, 0x93, 0x8f, 0x58, 0xd2, 0x82, + 0x2b, 0xa9, 0x65, 0x77, 0x31, 0x79, 0x2d, 0xad, 0xb7, 0xac, 0x8f, 0x57, + 0x8b, 0x2c, 0xb4, 0xb9, 0xab, 0x4b, 0x62, 0xf4, 0xf7, 0xaa, 0x18, 0x57, + 0x7f, 0x4b, 0xbd, 0x3d, 0x5e, 0xf0, 0x63, 0x70, 0xc2, 0xf6, 0xdb, 0x83, + 0x65, 0xe4, 0x5b, 0xf8, 0x2a, 0xe8, 0x71, 0xc6, 0x68, 0x3c, 0xc3, 0x18, + 0xc5, 0x56, 0xf2, 0x7c, 0x9f, 0x19, 0x6f, 0xd9, 0xae, 0x3c, 0xd8, 0x94, + 0x0f, 0x07, 0xdb, 0x6f, 0xe0, 0x93, 0xf2, 0x4a, 0x0c, 0x52, 0xd6, 0x10, + 0xf9, 0x0b, 0x63, 0x37, 0xf9, 0x7c, 0xae, 0xc8, 0xe7, 0x74, 0x41, 0xd6, + 0xfa, 0x3c, 0xaf, 0x25, 0x3e, 0x91, 0x5d, 0x94, 0x0a, 0x2b, 0x54, 0x04, + 0xb0, 0x3d, 0xff, 0x26, 0x6d, 0x51, 0x87, 0xbf, 0xa0, 0x0d, 0x5e, 0x60, + 0x8c, 0xfc, 0xf0, 0x9a, 0xbf, 0x88, 0x3d, 0x1e, 0xa1, 0x1d, 0xb4, 0xd3, + 0x59, 0x04, 0xd0, 0x5b, 0x48, 0xe3, 0xd0, 0x24, 0xd2, 0x33, 0xc6, 0x31, + 0xc6, 0xfb, 0x12, 0xb8, 0xf5, 0xf2, 0x74, 0x48, 0xaf, 0xc0, 0xee, 0xe9, + 0x30, 0x06, 0x0a, 0x6d, 0x30, 0x27, 0xc2, 0xd8, 0x47, 0xdf, 0xbc, 0x92, + 0x4c, 0xdf, 0x17, 0x84, 0xf0, 0x1e, 0xc6, 0xfd, 0x7c, 0xe7, 0xb1, 0xc9, + 0x30, 0xfa, 0xa9, 0xa3, 0xcd, 0xc9, 0x78, 0x8b, 0x9f, 0xd7, 0xf6, 0xf2, + 0xda, 0x61, 0xea, 0xff, 0xbc, 0x31, 0x86, 0xde, 0x6e, 0x2d, 0x01, 0x84, + 0xb1, 0xc7, 0x44, 0x88, 0x2e, 0xfc, 0x08, 0xf3, 0x5b, 0xe2, 0x3c, 0xff, + 0xbe, 0xa7, 0x50, 0x41, 0x39, 0x83, 0x88, 0xe8, 0x9f, 0x58, 0xde, 0x66, + 0xcb, 0xfa, 0xbe, 0x11, 0xbf, 0xf8, 0x96, 0xdb, 0x83, 0x87, 0x0a, 0x2e, + 0x0c, 0x4e, 0x57, 0xe0, 0x0f, 0x27, 0x3c, 0xb8, 0xb3, 0xbe, 0x02, 0x07, + 0xa6, 0xd3, 0x18, 0x99, 0xac, 0x40, 0xdf, 0x04, 0x96, 0xee, 0x31, 0x46, + 0x6a, 0xca, 0xa0, 0x2d, 0xb4, 0x23, 0x81, 0xab, 0xb4, 0xc3, 0x43, 0xd3, + 0x81, 0x60, 0x66, 0x32, 0x84, 0xc1, 0x59, 0x3f, 0x9f, 0x77, 0xf1, 0xf9, + 0x72, 0x18, 0xab, 0x62, 0x83, 0x21, 0x08, 0x8f, 0x95, 0xd8, 0x3f, 0xed, + 0xc7, 0x03, 0x13, 0x21, 0xec, 0x9b, 0x6c, 0xc6, 0xb8, 0x99, 0xc6, 0x51, + 0xe6, 0x8e, 0x1f, 0x24, 0xb5, 0xee, 0x7d, 0x4a, 0x4b, 0x6f, 0x54, 0x69, + 0x34, 0x24, 0xbd, 0xb8, 0xc4, 0x3c, 0xe4, 0x4d, 0x36, 0xb6, 0x3c, 0xcb, + 0xdc, 0x50, 0x96, 0x0a, 0xf3, 0x6f, 0xed, 0x08, 0x63, 0x36, 0xed, 0x75, + 0xad, 0x06, 0x16, 0x4b, 0xfc, 0x86, 0x83, 0x5b, 0xcc, 0x50, 0x70, 0x4b, + 0xa1, 0x2e, 0xb8, 0xd9, 0x8c, 0x04, 0x37, 0x33, 0xbe, 0x36, 0x8a, 0x3f, + 0x9a, 0x3e, 0x1c, 0x4b, 0x7e, 0x6a, 0xf5, 0xd6, 0xd8, 0xf9, 0x2c, 0xb8, + 0x6d, 0x52, 0xcb, 0x4e, 0x41, 0x33, 0x58, 0x0d, 0x30, 0x36, 0xeb, 0xa1, + 0xfd, 0x14, 0x6a, 0xf4, 0x66, 0xe6, 0xf1, 0x10, 0xf6, 0x33, 0xa7, 0xfc, + 0x15, 0x73, 0x4a, 0xdf, 0xf1, 0x58, 0x68, 0x1c, 0x7e, 0xea, 0x1b, 0xd8, + 0x75, 0x2e, 0x4c, 0x9b, 0x77, 0xe2, 0x51, 0xf2, 0xb5, 0x79, 0x4d, 0x18, + 0xf7, 0x16, 0x42, 0xc1, 0x4e, 0xda, 0xef, 0xbd, 0x7c, 0x24, 0xb8, 0x81, + 0xb6, 0x7c, 0x3b, 0xaf, 0x45, 0xe7, 0xf1, 0x8f, 0xe2, 0x4f, 0x09, 0xb8, + 0x80, 0x3d, 0xc7, 0xbd, 0x98, 0x0f, 0xcb, 0x5a, 0xd4, 0xb9, 0xf9, 0x82, + 0x15, 0xd0, 0xf5, 0xd3, 0xfb, 0xa8, 0xeb, 0x6f, 0x17, 0x02, 0x78, 0xc0, + 0xd4, 0x12, 0x3f, 0x54, 0x01, 0xea, 0xd4, 0x47, 0x3d, 0x30, 0xc1, 0x2c, + 0x91, 0xe7, 0x92, 0x88, 0x2e, 0x71, 0x72, 0xed, 0x81, 0x69, 0xf1, 0x13, + 0xda, 0xde, 0xa4, 0x0f, 0xd0, 0x7f, 0x7e, 0x78, 0x2d, 0x56, 0xb5, 0x50, + 0xd6, 0xce, 0xdd, 0x09, 0xfa, 0x8b, 0xa3, 0xa3, 0x13, 0x93, 0xa2, 0x07, + 0x6d, 0x1c, 0xae, 0x34, 0x56, 0xae, 0xfa, 0x2b, 0xeb, 0xd2, 0x62, 0xd1, + 0x47, 0x08, 0x43, 0xd4, 0xe1, 0x69, 0xd3, 0xb2, 0xae, 0xae, 0xfe, 0xd0, + 0x6a, 0xb9, 0x59, 0xf4, 0x22, 0xb2, 0x3e, 0xaf, 0xa4, 0x8e, 0xd4, 0xe8, + 0xc1, 0xff, 0x0f, 0xbe, 0xf2, 0x1d, 0xab, 0xd7, 0x96, 0x4f, 0xfc, 0xc5, + 0x43, 0x5f, 0x7c, 0x94, 0xb4, 0x5d, 0xe8, 0x25, 0xbd, 0x07, 0x4d, 0xeb, + 0xa3, 0xda, 0xd4, 0x67, 0x56, 0xcb, 0x5a, 0x7d, 0x60, 0x41, 0xfd, 0x0f, + 0x5e, 0x0f, 0x63, 0x7f, 0xa1, 0x85, 0xba, 0x6b, 0xc7, 0x63, 0xd4, 0xe1, + 0x61, 0x53, 0x72, 0x62, 0x84, 0xfe, 0x5c, 0x47, 0xff, 0xf6, 0xa8, 0x8d, + 0x66, 0x1e, 0x9b, 0xc7, 0xb2, 0xd8, 0x44, 0x7f, 0xbf, 0x98, 0x8b, 0xb5, + 0x3c, 0x0d, 0x2d, 0x4b, 0x19, 0x82, 0x9d, 0xd4, 0x71, 0xbb, 0xa9, 0x75, + 0x8a, 0x4d, 0xdb, 0x99, 0x97, 0x5e, 0xcc, 0x45, 0x82, 0x6d, 0x05, 0xd1, + 0x77, 0x5d, 0x70, 0x43, 0xe1, 0xab, 0xb4, 0xbd, 0xc2, 0xba, 0xe5, 0x3e, + 0xe6, 0x99, 0x3b, 0xe1, 0xd8, 0xd5, 0xb1, 0xdd, 0x6b, 0xc9, 0xc6, 0xde, + 0x0f, 0x99, 0x9f, 0xb2, 0x8b, 0x9d, 0x6b, 0x83, 0xbc, 0x56, 0xbd, 0x1a, + 0xc1, 0x3b, 0xe8, 0x07, 0x77, 0xd3, 0x0f, 0xae, 0xae, 0xfe, 0xd4, 0x8a, + 0xde, 0xe4, 0xf8, 0x41, 0xdb, 0xa4, 0x27, 0xd8, 0x41, 0x3d, 0x6d, 0x34, + 0x14, 0xa6, 0x8d, 0x1c, 0x7a, 0xaf, 0x61, 0x87, 0xf4, 0xd4, 0x59, 0x23, + 0xcd, 0x3c, 0xf2, 0xbb, 0xf0, 0xd4, 0x60, 0xea, 0x69, 0xe3, 0x51, 0x44, + 0x1d, 0xdf, 0xc1, 0xbe, 0x09, 0x3f, 0xb2, 0x77, 0x86, 0x30, 0xd3, 0x10, + 0xc2, 0x83, 0xa4, 0x7d, 0x25, 0xd9, 0xd8, 0xff, 0x3a, 0x75, 0x30, 0x55, + 0x23, 0xd7, 0xd2, 0xf8, 0x91, 0xf1, 0x30, 0x70, 0x93, 0xb3, 0xf6, 0xac, + 0xc4, 0xe8, 0x6c, 0x33, 0x0e, 0x17, 0x32, 0xca, 0xc9, 0x9b, 0x5a, 0x67, + 0x1a, 0x3f, 0xb7, 0x24, 0x97, 0xce, 0x9a, 0xcc, 0x71, 0xd4, 0xc7, 0x28, + 0xfd, 0x68, 0x38, 0x5f, 0x17, 0xdc, 0x44, 0x3f, 0x7a, 0x34, 0x2f, 0x32, + 0xc5, 0x0d, 0xc3, 0x5d, 0xcb, 0xda, 0x4c, 0xfd, 0x98, 0x76, 0xcd, 0xaf, + 0x0e, 0xe9, 0x47, 0x31, 0x6e, 0xf3, 0x36, 0xa8, 0x32, 0xc4, 0x18, 0x0c, + 0x99, 0xea, 0x72, 0xfd, 0x00, 0x1e, 0xb5, 0xaf, 0x85, 0x83, 0x3b, 0x26, + 0xd3, 0x2e, 0x97, 0x8e, 0x50, 0x65, 0xaa, 0x5d, 0xed, 0x60, 0xdd, 0xed, + 0x98, 0xec, 0x50, 0x1d, 0xb3, 0x12, 0x03, 0x9d, 0x6a, 0x33, 0x6b, 0x6e, + 0x9a, 0x35, 0x37, 0xcd, 0x9a, 0x9b, 0x26, 0x1f, 0x69, 0xd6, 0xda, 0xb6, + 0xc2, 0xa0, 0xda, 0x2a, 0xfa, 0xa7, 0x7f, 0x3d, 0x6b, 0x3a, 0x38, 0x82, + 0x39, 0x28, 0xb8, 0xa9, 0xb0, 0xc2, 0xe5, 0x60, 0xbb, 0x41, 0x55, 0xc4, + 0x32, 0xbe, 0x0a, 0x9d, 0xb5, 0xcc, 0x1c, 0x54, 0x5b, 0x58, 0x6f, 0x33, + 0xb6, 0x2e, 0x63, 0x03, 0xef, 0xb0, 0xce, 0xbe, 0xc6, 0x3a, 0x9b, 0x4f, + 0x32, 0xae, 0x96, 0x5f, 0xb5, 0x7a, 0x17, 0x3b, 0x35, 0x61, 0x84, 0xfc, + 0x7e, 0x9f, 0x36, 0x9b, 0x67, 0x2d, 0x6d, 0x77, 0x2b, 0xec, 0xd1, 0x51, + 0x5d, 0xcb, 0x9c, 0x7a, 0xb8, 0xc0, 0x3a, 0x60, 0xc4, 0x5a, 0xde, 0xa7, + 0x62, 0x0f, 0xeb, 0x5e, 0x5c, 0xbd, 0x89, 0x60, 0x47, 0x6f, 0xc3, 0xb1, + 0x89, 0x72, 0xf4, 0x27, 0xd3, 0x8b, 0x7c, 0xc4, 0x2a, 0x9d, 0xcd, 0x78, + 0x98, 0x4b, 0xab, 0x48, 0x2a, 0x4e, 0xbf, 0x41, 0xfa, 0x38, 0xeb, 0xc4, + 0x98, 0xf9, 0x55, 0xe4, 0x59, 0x4f, 0x67, 0x0c, 0x0f, 0x5e, 0xcb, 0xaf, + 0x60, 0x9e, 0x8b, 0x1b, 0x01, 0x55, 0xc1, 0xf8, 0x4d, 0x21, 0x67, 0x4a, + 0x7e, 0xb2, 0xac, 0x19, 0xe1, 0x21, 0x1e, 0x4f, 0x0f, 0x43, 0x72, 0x96, + 0xb5, 0xf4, 0x9e, 0x64, 0x19, 0xd6, 0xc5, 0x83, 0x58, 0xaa, 0xf7, 0xaa, + 0xce, 0x42, 0xdc, 0x38, 0x8f, 0x6f, 0xa9, 0xbb, 0x67, 0x53, 0x8c, 0xed, + 0x0c, 0x75, 0x53, 0x81, 0x4b, 0x61, 0xe1, 0x11, 0xd5, 0x5e, 0xdd, 0x85, + 0x77, 0xef, 0x52, 0x08, 0xe9, 0x69, 0x5c, 0x68, 0x0e, 0xd1, 0xaf, 0x3a, + 0x89, 0x31, 0xa2, 0x70, 0xcf, 0x45, 0x82, 0x5b, 0x69, 0x8b, 0xca, 0xb9, + 0x3a, 0xda, 0x87, 0xbe, 0x47, 0x1d, 0xb6, 0x51, 0x87, 0x5b, 0xa6, 0x11, + 0xaa, 0x48, 0xf5, 0xa8, 0x8e, 0x42, 0xbb, 0x6a, 0x2f, 0x68, 0xd4, 0x93, + 0xe8, 0xe4, 0x3b, 0xc4, 0x4a, 0xe2, 0x2b, 0x25, 0x5b, 0x8a, 0xbf, 0xde, + 0x68, 0xcf, 0x8c, 0x4b, 0x62, 0x6e, 0xdd, 0xf2, 0x14, 0xe3, 0xd1, 0x45, + 0xbe, 0x84, 0x07, 0x1f, 0xaa, 0x1b, 0xac, 0xa5, 0x57, 0x92, 0x4c, 0x9e, + 0x15, 0x29, 0x1c, 0x2f, 0x74, 0xd1, 0x2e, 0xab, 0x8b, 0xfe, 0x15, 0x0a, + 0x6e, 0x9c, 0x6c, 0x57, 0x1b, 0x67, 0x17, 0x05, 0xbb, 0x69, 0xc3, 0xee, + 0xd9, 0x88, 0xd0, 0xe5, 0xfa, 0x62, 0xdb, 0x34, 0x5c, 0xfa, 0xbf, 0x64, + 0xcb, 0x6f, 0x93, 0x96, 0xd8, 0xd3, 0x5f, 0xf2, 0xd3, 0xe0, 0xdd, 0x93, + 0x69, 0xbc, 0xbb, 0xda, 0xcb, 0x9a, 0x5a, 0xc2, 0x14, 0x55, 0xc5, 0xef, + 0xd3, 0x2e, 0xe8, 0x83, 0xaa, 0x53, 0xfc, 0xc8, 0xeb, 0xac, 0x79, 0xc7, + 0x24, 0xbc, 0x84, 0x0a, 0x51, 0x37, 0x31, 0xdd, 0x87, 0xc9, 0x78, 0xef, + 0x39, 0xd5, 0xa5, 0xba, 0x0a, 0x52, 0x83, 0x1d, 0x9f, 0x6a, 0xa3, 0x4f, + 0xb5, 0x93, 0x9f, 0x76, 0xfa, 0xd4, 0x16, 0xf2, 0xb3, 0xc5, 0xf6, 0x29, + 0xf1, 0xcd, 0xdf, 0xe6, 0x65, 0x43, 0xe1, 0x6e, 0x5b, 0x2f, 0x5b, 0xf9, + 0x6e, 0x27, 0xe5, 0xe8, 0xe4, 0x7b, 0x77, 0xf3, 0xbd, 0xbb, 0x67, 0xff, + 0x97, 0xf0, 0x47, 0x59, 0x9c, 0xd8, 0xbf, 0x5e, 0xd3, 0x24, 0x07, 0xfc, + 0xac, 0x88, 0x29, 0x90, 0x75, 0xa5, 0x24, 0x47, 0x0c, 0xa0, 0xbb, 0x19, + 0xbe, 0x45, 0xa9, 0x67, 0x5b, 0xb7, 0xd7, 0x33, 0x9f, 0x31, 0x9f, 0xfa, + 0x8e, 0x13, 0x4b, 0x33, 0x47, 0xcf, 0xb4, 0x28, 0x8c, 0x18, 0x37, 0x33, + 0x4e, 0x0d, 0x1c, 0x29, 0x68, 0x9d, 0x51, 0xde, 0x6b, 0x1a, 0x13, 0x8c, + 0xbf, 0x0f, 0x6d, 0xc4, 0x75, 0x91, 0x54, 0x3f, 0x22, 0x66, 0x2c, 0x72, + 0x44, 0x69, 0xfd, 0x1b, 0xa0, 0x5d, 0x64, 0x6d, 0x18, 0x9c, 0x56, 0xda, + 0x40, 0xad, 0x5b, 0x4b, 0xbf, 0x61, 0xe3, 0xeb, 0x7d, 0x58, 0x6e, 0x63, + 0xb8, 0x7e, 0x24, 0x88, 0x65, 0xb7, 0x92, 0xe6, 0xde, 0x75, 0x0a, 0x97, + 0x8d, 0x0f, 0x69, 0x47, 0x2d, 0x9d, 0x55, 0x06, 0x72, 0xcc, 0x13, 0x91, + 0xe3, 0x82, 0xd5, 0xf7, 0x11, 0xab, 0xc3, 0x17, 0xe0, 0xb3, 0xb9, 0xb1, + 0xd8, 0xa0, 0xcf, 0xad, 0x25, 0x88, 0xd3, 0xd3, 0xa4, 0x69, 0x14, 0x88, + 0xdf, 0xb9, 0x46, 0x74, 0x4f, 0x91, 0x66, 0xbc, 0x48, 0x53, 0xcf, 0x83, + 0x71, 0x73, 0x04, 0x9b, 0xe2, 0xac, 0x15, 0xcc, 0x79, 0x47, 0xa5, 0x27, + 0x20, 0xbd, 0xf2, 0xe3, 0x06, 0xff, 0x1e, 0x54, 0x3b, 0x24, 0xa6, 0xca, + 0x1d, 0x2b, 0x54, 0x73, 0x8d, 0xaa, 0xd4, 0x41, 0xcc, 0xd9, 0x6b, 0x0c, + 0xc8, 0x1a, 0x03, 0xbf, 0x50, 0x5a, 0xe2, 0x9c, 0x92, 0x5c, 0xdd, 0x98, + 0x39, 0xc7, 0x18, 0x3a, 0xac, 0xb4, 0x96, 0x63, 0x14, 0xdf, 0xaf, 0x0b, + 0xfd, 0x83, 0xc5, 0x75, 0x06, 0xd0, 0x90, 0x67, 0x7c, 0x16, 0x7c, 0x6a, + 0xc3, 0x44, 0x1b, 0x46, 0xa6, 0xdb, 0x30, 0x3c, 0xa1, 0x70, 0xb7, 0xb1, + 0x18, 0x97, 0x6e, 0xb6, 0xfb, 0x94, 0xaa, 0xa5, 0x7a, 0x2d, 0x86, 0x42, + 0xa8, 0x76, 0xe9, 0x5f, 0xc1, 0xae, 0x22, 0xc6, 0xdf, 0x74, 0xa2, 0x9b, + 0x79, 0xdf, 0xc2, 0xfb, 0x8c, 0xa5, 0x58, 0x0d, 0xd2, 0xde, 0x54, 0x0b, + 0xf1, 0x78, 0x9d, 0xdb, 0x89, 0xf7, 0x0f, 0x7d, 0x8e, 0x0d, 0x44, 0xff, + 0x9f, 0xbf, 0xd7, 0x86, 0xc7, 0x27, 0xca, 0xd0, 0xb2, 0x1a, 0x77, 0x46, + 0x50, 0xe5, 0x62, 0x8d, 0x7b, 0x73, 0xbb, 0x1a, 0xe4, 0x3d, 0xfb, 0x59, + 0xdf, 0x97, 0x53, 0x46, 0xea, 0x4f, 0x1a, 0xe4, 0xba, 0x9d, 0x37, 0x6e, + 0xb8, 0xde, 0xfd, 0x05, 0xd7, 0x15, 0x9e, 0x61, 0x22, 0xfb, 0x01, 0x6b, + 0x4a, 0x3e, 0x67, 0xc1, 0x9d, 0xf2, 0xa0, 0x7f, 0x2c, 0x8a, 0x7d, 0x73, + 0x61, 0xcc, 0xe5, 0xb4, 0xde, 0x4b, 0xec, 0x1f, 0x76, 0x35, 0xeb, 0x78, + 0x60, 0x2e, 0x82, 0xd9, 0x1c, 0x2c, 0x7f, 0x4a, 0x9f, 0xf7, 0xab, 0x04, + 0xf6, 0xce, 0xd5, 0xe1, 0x5c, 0x4e, 0xbf, 0x38, 0xac, 0xe2, 0x83, 0xb5, + 0xc4, 0x1d, 0x0f, 0xce, 0x35, 0x61, 0xff, 0x9c, 0x8f, 0xef, 0x58, 0xd8, + 0x92, 0xac, 0xe3, 0xf3, 0x2e, 0x3c, 0x7d, 0xd2, 0xb2, 0x04, 0x77, 0xf5, + 0xcf, 0x01, 0xb3, 0xe3, 0xac, 0x45, 0x67, 0x58, 0x97, 0x9e, 0x00, 0xf6, + 0x3e, 0xe1, 0xc2, 0xf4, 0xb8, 0x85, 0x5d, 0xc6, 0x70, 0xad, 0x8b, 0x0e, + 0xdf, 0xcb, 0xba, 0xe1, 0x65, 0x0d, 0xbc, 0x27, 0xe4, 0xe4, 0xf3, 0x4b, + 0xcc, 0x53, 0xf7, 0x3d, 0x91, 0xc0, 0x9b, 0xb9, 0x2c, 0xb6, 0x10, 0x9f, + 0x0f, 0x92, 0x97, 0x37, 0x72, 0xac, 0x63, 0x73, 0x06, 0x5e, 0xcf, 0xf9, + 0xb8, 0x4e, 0x13, 0x5e, 0xca, 0xc9, 0x33, 0xf2, 0x6c, 0x00, 0x7d, 0xe4, + 0xe5, 0xb5, 0x5c, 0x84, 0x6b, 0x86, 0xf1, 0x53, 0x3e, 0x77, 0xef, 0x9c, + 0xce, 0xba, 0xe5, 0xe3, 0xba, 0x51, 0xbc, 0x92, 0x0b, 0x90, 0xd7, 0x30, + 0x6b, 0x55, 0x1f, 0x46, 0x72, 0x8d, 0x17, 0x37, 0x30, 0x51, 0x3b, 0xb5, + 0x46, 0xae, 0xbd, 0x63, 0x75, 0xd9, 0xb1, 0x28, 0xeb, 0x94, 0xd6, 0xed, + 0xc3, 0x70, 0xee, 0x75, 0x77, 0xa9, 0x9f, 0x7e, 0x66, 0x7c, 0xc1, 0xc6, + 0x7e, 0x4f, 0x9b, 0xfc, 0x7d, 0x1a, 0x38, 0x67, 0x66, 0xad, 0xea, 0x14, + 0xb1, 0x2e, 0x6b, 0xd4, 0x5b, 0x6b, 0x9a, 0xb8, 0xae, 0xde, 0xfb, 0xa2, + 0x92, 0x7e, 0xc7, 0x83, 0xe8, 0x13, 0xa2, 0x2f, 0x62, 0xe6, 0x59, 0xe0, + 0x47, 0xc4, 0x9f, 0x0d, 0x63, 0x9a, 0xf8, 0x7d, 0x86, 0xb8, 0xa6, 0x7b, + 0x1e, 0xf5, 0x89, 0x07, 0x30, 0x64, 0x95, 0x11, 0x9f, 0x57, 0x13, 0xd7, + 0xce, 0x35, 0xb1, 0x4e, 0xad, 0xb1, 0xac, 0xbf, 0x6d, 0x86, 0xe5, 0x4a, + 0xe9, 0x46, 0xad, 0x7b, 0xfe, 0x2b, 0x55, 0xd0, 0x2f, 0x06, 0x95, 0x3e, + 0xff, 0x16, 0xe2, 0x03, 0xe7, 0x21, 0x7a, 0x05, 0x56, 0xcc, 0x79, 0xb0, + 0x92, 0xf2, 0x6c, 0x1c, 0xe3, 0xda, 0xc4, 0x27, 0x71, 0xca, 0xb4, 0x6d, + 0x8c, 0x98, 0x4b, 0x0f, 0x60, 0x39, 0x75, 0xdc, 0x7f, 0xca, 0xb2, 0xca, + 0xa9, 0xe3, 0x06, 0xda, 0x67, 0xcf, 0x09, 0x0b, 0x2f, 0x1a, 0x2f, 0x52, + 0xa7, 0x8a, 0xb8, 0xb1, 0x99, 0xef, 0x84, 0xf9, 0xbc, 0x0f, 0x7b, 0xc7, + 0xa4, 0x5f, 0xaa, 0xe3, 0x33, 0xaf, 0xe2, 0x58, 0x2e, 0x81, 0x26, 0xea, + 0x2f, 0x4a, 0x9a, 0x8d, 0x7c, 0x27, 0x4a, 0x7a, 0xd1, 0xb9, 0xaf, 0x61, + 0xf3, 0x29, 0x05, 0x3d, 0x2e, 0x3a, 0xf8, 0x1a, 0xda, 0xcf, 0x7c, 0x51, + 0x4e, 0x60, 0x96, 0x1a, 0xd7, 0x8e, 0xcc, 0x13, 0x7f, 0x57, 0xa5, 0x86, + 0xc0, 0xfa, 0x8d, 0x37, 0xa6, 0x14, 0x8e, 0x8f, 0xb3, 0xdf, 0x5b, 0x03, + 0xab, 0x82, 0x32, 0xbd, 0x3e, 0xf5, 0x3b, 0x78, 0xea, 0x24, 0xf5, 0xf0, + 0x64, 0x18, 0x3f, 0xc8, 0x79, 0xb0, 0xec, 0xb8, 0x60, 0x3a, 0x3d, 0xb1, + 0x4f, 0x49, 0x7f, 0x24, 0x7d, 0x4b, 0x3c, 0xea, 0x55, 0x2e, 0xd4, 0x3f, + 0xe5, 0x81, 0x7e, 0x2e, 0x0a, 0x6f, 0xbd, 0x0f, 0x7a, 0xfd, 0x1f, 0x32, + 0xd7, 0xb8, 0x50, 0xc6, 0x5e, 0x76, 0xd3, 0x77, 0x13, 0xbc, 0x16, 0xe6, + 0x35, 0xfc, 0x4e, 0x39, 0xdc, 0x4b, 0xdc, 0xac, 0xe1, 0x65, 0x3a, 0xf1, + 0x98, 0xc7, 0xb2, 0xdc, 0xac, 0x0d, 0x3b, 0xbe, 0x67, 0x59, 0xb1, 0xd5, + 0xf2, 0x7c, 0x08, 0xb1, 0x73, 0x3a, 0x9f, 0x73, 0xea, 0xe5, 0x75, 0x3c, + 0xe6, 0xa6, 0x1f, 0x49, 0xac, 0xb2, 0xde, 0xdb, 0x3d, 0x94, 0x83, 0xdb, + 0x9f, 0x2b, 0x08, 0xb6, 0x89, 0xda, 0x32, 0x9c, 0x1d, 0x57, 0xcc, 0xd9, + 0x29, 0x3e, 0xbb, 0x1e, 0xee, 0xa4, 0x76, 0x24, 0x4b, 0x3f, 0xd8, 0x15, + 0x6a, 0xc1, 0x33, 0xa6, 0x17, 0x95, 0xfa, 0x12, 0xdc, 0xdf, 0x1d, 0xc2, + 0x33, 0xec, 0x0b, 0x68, 0xb3, 0xc4, 0x3c, 0xd8, 0x48, 0x07, 0x49, 0xcf, + 0xf5, 0x63, 0xe8, 0xdf, 0x75, 0x31, 0xcf, 0xb9, 0xed, 0x3c, 0x57, 0x56, + 0x0f, 0xcc, 0xe7, 0x3d, 0xb8, 0xa0, 0x3b, 0x98, 0xf0, 0x39, 0xbb, 0x66, + 0x6b, 0xa1, 0xf9, 0x6b, 0x58, 0x50, 0x6b, 0x49, 0x2b, 0x32, 0x13, 0x14, + 0xdd, 0x65, 0x3c, 0x8e, 0x2f, 0xfd, 0x8d, 0x5b, 0x7a, 0x8e, 0xeb, 0x7f, + 0x57, 0xc0, 0x95, 0xd2, 0x22, 0x6d, 0x6e, 0xf8, 0x3c, 0xa9, 0xce, 0xd6, + 0x51, 0xfd, 0x4b, 0x37, 0xf0, 0xde, 0x84, 0x91, 0xc2, 0xf5, 0x5e, 0xbb, + 0x33, 0x67, 0xfb, 0x50, 0xa7, 0xe8, 0xfe, 0x31, 0x43, 0xf2, 0xec, 0xa0, + 0x6a, 0x67, 0xde, 0xca, 0x7a, 0x90, 0xad, 0xe2, 0x33, 0xd4, 0x3f, 0x0e, + 0x8f, 0x09, 0x9d, 0x83, 0x18, 0xcd, 0xc9, 0x6c, 0x63, 0x00, 0xeb, 0xcc, + 0x58, 0xe2, 0x22, 0x7b, 0xe8, 0x43, 0x90, 0x39, 0x44, 0xe3, 0xfc, 0xcb, + 0x4a, 0x1b, 0xbc, 0xc5, 0xad, 0xf5, 0x2f, 0x28, 0x27, 0x6f, 0xad, 0x28, + 0xe6, 0xad, 0xe5, 0xf9, 0x25, 0xc1, 0x2e, 0xd6, 0x83, 0xae, 0xd9, 0x52, + 0x7d, 0xe8, 0x52, 0x9b, 0xec, 0xda, 0x9a, 0x51, 0x5b, 0x67, 0x7d, 0xaa, + 0x63, 0xc2, 0x87, 0x97, 0x89, 0xc5, 0xa6, 0x7a, 0x10, 0x5a, 0xb6, 0x06, + 0xfe, 0xad, 0x13, 0xdd, 0x28, 0xd7, 0xa5, 0x87, 0x2c, 0xc7, 0x26, 0xbb, + 0xae, 0xd5, 0x05, 0xbb, 0x58, 0x7f, 0xba, 0x0a, 0x3d, 0xcc, 0x7f, 0x08, + 0xf9, 0x53, 0xce, 0xcc, 0x40, 0x72, 0xe1, 0xed, 0x7c, 0xf7, 0x62, 0x72, + 0x11, 0xe0, 0xd4, 0x3f, 0x95, 0x61, 0x2f, 0x51, 0xbd, 0x5a, 0xe1, 0xd2, + 0x9d, 0x3e, 0x90, 0x16, 0x7b, 0xfe, 0x7c, 0xeb, 0x85, 0xf1, 0x6e, 0xd5, + 0x31, 0x3d, 0xe3, 0xdf, 0x68, 0xca, 0x2c, 0x62, 0xca, 0xdf, 0x4e, 0x1e, + 0xda, 0x67, 0x9f, 0xf4, 0x6f, 0x20, 0x4f, 0x1b, 0x66, 0x3f, 0x4f, 0x53, + 0xea, 0x4a, 0x7f, 0x6b, 0x1b, 0x63, 0x7b, 0x87, 0xf1, 0x91, 0x15, 0xfd, + 0xa6, 0xd0, 0x99, 0x2b, 0xea, 0x33, 0x4d, 0xbe, 0xc2, 0xbe, 0x4d, 0x85, + 0x90, 0x2f, 0x5d, 0x68, 0xf7, 0xb7, 0x99, 0xdd, 0xfe, 0x0d, 0x66, 0x8f, + 0xbf, 0xdd, 0xdc, 0x49, 0xda, 0x5d, 0xfe, 0x0e, 0x93, 0x71, 0x5d, 0xe8, + 0xa1, 0x5e, 0xbb, 0x31, 0x5a, 0xd8, 0x49, 0xec, 0x21, 0x34, 0x7b, 0x89, + 0x83, 0xfc, 0x94, 0x71, 0x88, 0x32, 0xce, 0x47, 0xbc, 0x48, 0x6b, 0x5e, + 0xea, 0x6b, 0xc4, 0xb6, 0xe3, 0x11, 0x7b, 0x16, 0x55, 0x91, 0x7a, 0xa0, + 0x75, 0xcb, 0x09, 0xe6, 0xfb, 0xd4, 0x9e, 0xd6, 0x65, 0xa7, 0x50, 0xe3, + 0x4d, 0x49, 0xef, 0xcc, 0x7e, 0x38, 0x1e, 0x37, 0xde, 0x43, 0x3c, 0xf2, + 0x32, 0x9f, 0x1d, 0xa6, 0xef, 0x8e, 0xd8, 0xf3, 0x07, 0x1a, 0x24, 0xdf, + 0x84, 0x2d, 0xa6, 0xcf, 0xbf, 0x8d, 0xbd, 0x59, 0x30, 0xa5, 0xb5, 0xdc, + 0xee, 0x96, 0x79, 0xc8, 0xfc, 0xef, 0x05, 0xd0, 0x84, 0xce, 0x82, 0x8f, + 0x72, 0x7d, 0x09, 0x7f, 0x7f, 0x92, 0x75, 0x0d, 0xe2, 0x87, 0x96, 0x75, + 0x2f, 0xfb, 0x9a, 0xa3, 0xf9, 0x3a, 0x5c, 0xb6, 0x6d, 0xec, 0xc1, 0xe1, + 0x7c, 0x14, 0xef, 0x50, 0x3e, 0xcf, 0x5c, 0x2d, 0xde, 0x1e, 0x77, 0x63, + 0xb7, 0x71, 0x5b, 0xb1, 0x5e, 0xb8, 0x70, 0x4f, 0xe2, 0x00, 0xb1, 0x83, + 0x0b, 0xd5, 0xc4, 0x6f, 0x0f, 0xda, 0xd7, 0xdc, 0xec, 0xff, 0xbe, 0x8e, + 0x41, 0xa7, 0x9e, 0x90, 0xc7, 0x9d, 0xe4, 0xb1, 0xd9, 0xbf, 0x61, 0x42, + 0xf3, 0xdf, 0x31, 0x01, 0x9f, 0x37, 0xb5, 0xab, 0xf5, 0xcc, 0x49, 0x0b, + 0x7d, 0xc6, 0xad, 0xb8, 0x72, 0x72, 0xb8, 0xdf, 0x43, 0xff, 0xf9, 0x65, + 0x32, 0x03, 0x73, 0x12, 0x17, 0x88, 0x3c, 0x5e, 0x0d, 0x30, 0xb7, 0x37, + 0x24, 0xe3, 0x21, 0xd6, 0x62, 0x63, 0x96, 0xb1, 0xd9, 0x01, 0xad, 0x9f, + 0x35, 0x39, 0xed, 0x4e, 0xc5, 0x7b, 0x47, 0x08, 0x1e, 0xab, 0xc8, 0x8f, + 0x9f, 0xb9, 0x3b, 0x30, 0x17, 0xf5, 0xef, 0x60, 0xbd, 0x89, 0xb0, 0xbf, + 0xf3, 0xc7, 0x71, 0x5b, 0x2d, 0xe2, 0x89, 0x05, 0xca, 0xed, 0x9d, 0x6b, + 0xf2, 0xdf, 0xce, 0xfa, 0x71, 0x39, 0x6e, 0x0d, 0xbd, 0x68, 0x04, 0x10, + 0x9c, 0x33, 0xa8, 0xef, 0x0c, 0x86, 0x67, 0xd9, 0x72, 0xc5, 0xd9, 0xf3, + 0xcf, 0xb5, 0xf8, 0xb7, 0x31, 0x36, 0xab, 0x68, 0xa2, 0xc6, 0xb9, 0xb4, + 0x5f, 0x7a, 0xbe, 0xa6, 0xb9, 0xb5, 0xe4, 0x4f, 0x7c, 0x74, 0x5f, 0xeb, + 0x3a, 0xfa, 0x43, 0x74, 0x0e, 0x9b, 0x98, 0xe6, 0x5e, 0x22, 0xcd, 0x4c, + 0x84, 0x18, 0x76, 0xef, 0x9a, 0x00, 0xf3, 0x94, 0xe8, 0x92, 0x7a, 0x2c, + 0x94, 0x64, 0x92, 0xba, 0xbc, 0xa7, 0x75, 0xee, 0x94, 0xd4, 0xe5, 0x4c, + 0x6b, 0xee, 0x94, 0x8e, 0x77, 0x58, 0x5b, 0x56, 0x24, 0x35, 0xe3, 0x9c, + 0x8a, 0x45, 0x5e, 0xa5, 0x2c, 0x1e, 0xfc, 0xca, 0xda, 0xa5, 0xc7, 0xe7, + 0x6f, 0x61, 0x3c, 0x55, 0x33, 0x37, 0x46, 0x98, 0xf3, 0xab, 0xe7, 0xa8, + 0x98, 0x39, 0xb7, 0x17, 0x15, 0x11, 0xf8, 0xe2, 0x3a, 0xde, 0x3d, 0x99, + 0xa0, 0x1e, 0xae, 0xd1, 0xdc, 0x47, 0xa8, 0xd5, 0xc7, 0x52, 0xf8, 0xc8, + 0x53, 0xf4, 0xc5, 0x51, 0xae, 0x5b, 0x36, 0x27, 0x3c, 0xcb, 0xf3, 0x61, + 0x3e, 0x7f, 0x7d, 0xed, 0x6a, 0xae, 0xfd, 0xd1, 0x29, 0xf1, 0xd7, 0x4c, + 0xeb, 0x85, 0x93, 0xce, 0xda, 0xf1, 0x64, 0x02, 0x1f, 0x9e, 0xd4, 0x06, + 0xde, 0x55, 0xb1, 0xde, 0x0b, 0x4a, 0xd6, 0x47, 0x5d, 0x15, 0xae, 0x58, + 0xc3, 0xf1, 0xf8, 0xe0, 0x2e, 0xd2, 0x6c, 0x59, 0x4b, 0xfd, 0xdb, 0x7c, + 0xd0, 0xe7, 0x99, 0x67, 0xbd, 0xe4, 0xc7, 0xe1, 0xa5, 0x8e, 0xb4, 0x4f, + 0x16, 0x7b, 0x35, 0xf6, 0xa9, 0xd7, 0xf9, 0x09, 0x53, 0x0f, 0xbe, 0x1d, + 0xcd, 0x01, 0xd4, 0xda, 0xcf, 0x85, 0xf8, 0x9c, 0xe8, 0xe1, 0xd7, 0xca, + 0xa5, 0xbf, 0xc7, 0x3c, 0x26, 0xb9, 0x24, 0xcc, 0x1c, 0xb6, 0x53, 0x7a, + 0xda, 0x6c, 0x96, 0xfe, 0xee, 0xa5, 0xbf, 0x6f, 0x14, 0x9f, 0x36, 0xe9, + 0xd3, 0x26, 0x7d, 0xda, 0xd4, 0x22, 0x03, 0x88, 0x85, 0xfa, 0x68, 0xb7, + 0x74, 0x44, 0x7c, 0xbd, 0x07, 0xbb, 0xf9, 0xd9, 0xc3, 0xfb, 0x87, 0xd9, + 0xe7, 0x62, 0x91, 0xac, 0x79, 0x10, 0xed, 0xe6, 0x23, 0xe8, 0x9f, 0xc0, + 0x6f, 0xfc, 0xcd, 0xe5, 0x28, 0x5f, 0x2e, 0x3d, 0xbc, 0x16, 0x3a, 0x8a, + 0x47, 0xd8, 0x47, 0xfd, 0x5a, 0x55, 0xea, 0x9e, 0xee, 0x63, 0x4a, 0x0b, + 0xb5, 0xb3, 0x1f, 0xde, 0x55, 0xd8, 0x49, 0xfb, 0xc6, 0xfa, 0x5f, 0x56, + 0xec, 0xa5, 0x6a, 0xb9, 0x36, 0x63, 0xe9, 0x0e, 0xae, 0x63, 0x0a, 0x1f, + 0x76, 0xbe, 0xfd, 0x7d, 0x88, 0x6e, 0x7f, 0xd2, 0xd0, 0xc7, 0xf5, 0x1d, + 0x3e, 0x86, 0xd9, 0x53, 0xf6, 0x31, 0xc6, 0x76, 0xdb, 0xf1, 0xd5, 0x43, + 0x1a, 0xd7, 0xf3, 0xd8, 0x86, 0x9c, 0xd4, 0x52, 0x0b, 0x8f, 0x1a, 0x16, + 0x9e, 0xe6, 0xe7, 0x22, 0x73, 0xd9, 0xc8, 0x0d, 0xb9, 0xcc, 0xc5, 0xe7, + 0x76, 0xf0, 0xb9, 0x16, 0xa6, 0xce, 0xd9, 0x69, 0x99, 0x0d, 0x1e, 0x94, + 0xd9, 0x20, 0xf2, 0xa6, 0xe8, 0x7e, 0x00, 0x17, 0x72, 0xb1, 0x41, 0xb7, + 0xdb, 0x1a, 0x62, 0x5c, 0x5d, 0xfc, 0x88, 0xbe, 0xfb, 0xda, 0x1a, 0xad, + 0x9b, 0x3a, 0x4c, 0x8c, 0x29, 0x2d, 0xf2, 0x33, 0xcc, 0x6f, 0xf2, 0xa1, + 0x31, 0xba, 0xd2, 0x1d, 0x0f, 0x9d, 0x85, 0x36, 0xdf, 0x47, 0x49, 0x9f, + 0x2c, 0x38, 0xb9, 0x6e, 0x5d, 0x31, 0xd7, 0xb5, 0xe4, 0x2b, 0xd4, 0x1d, + 0x13, 0xac, 0xcf, 0xd3, 0x56, 0x36, 0xc8, 0x7a, 0x55, 0x98, 0x16, 0xda, + 0x43, 0x68, 0x4c, 0x0a, 0x2d, 0xbd, 0x73, 0x4c, 0xe1, 0x1b, 0x95, 0x88, + 0xb3, 0x56, 0xc1, 0x28, 0xd7, 0xb3, 0x16, 0x6b, 0x52, 0xc8, 0x9b, 0x92, + 0xda, 0xd9, 0xc5, 0xbe, 0xa5, 0x87, 0x79, 0x51, 0x30, 0xb5, 0xcc, 0x4b, + 0x9d, 0x7c, 0xb4, 0xb1, 0x20, 0x76, 0x11, 0x9b, 0x88, 0x6d, 0x0e, 0xe2, + 0x1e, 0x53, 0x7a, 0x7f, 0x0b, 0xe3, 0x46, 0x3c, 0xfa, 0x14, 0xc4, 0x4e, + 0x07, 0xa9, 0x0b, 0x2f, 0x76, 0x33, 0x0f, 0xee, 0x6a, 0xa6, 0xae, 0x82, + 0x5e, 0xec, 0xb2, 0x67, 0x09, 0x25, 0xfd, 0x79, 0x69, 0x43, 0xc5, 0x1a, + 0x37, 0xeb, 0x75, 0xf4, 0xe8, 0xcc, 0x26, 0xdd, 0x29, 0xa1, 0x57, 0x9a, + 0x4b, 0x3a, 0xba, 0xdb, 0x94, 0x13, 0xba, 0x16, 0xce, 0x1a, 0x0e, 0x6e, + 0x2d, 0xe9, 0x2c, 0x42, 0xb9, 0x6a, 0xd6, 0x02, 0x2b, 0x6f, 0xc0, 0xae, + 0x15, 0xbc, 0xb6, 0xe5, 0x3a, 0x76, 0xcd, 0x08, 0x3e, 0x26, 0x76, 0xed, + 0xdc, 0x4a, 0xec, 0x5a, 0xaf, 0x4a, 0xb8, 0x55, 0xe6, 0x12, 0x25, 0xec, + 0x5a, 0x5d, 0xcc, 0xd1, 0x07, 0xb1, 0x8b, 0xb8, 0xa6, 0xb6, 0x7e, 0x08, + 0xbe, 0x55, 0xae, 0xcf, 0x5c, 0x18, 0x62, 0xbf, 0x52, 0x06, 0x2c, 0xb6, + 0x70, 0xcb, 0xea, 0xac, 0x55, 0xae, 0xd7, 0x47, 0xcb, 0x5d, 0x32, 0x77, + 0x8e, 0x67, 0x47, 0x98, 0x4b, 0x5c, 0xab, 0xb4, 0x6c, 0x1a, 0xbe, 0x50, + 0x8d, 0xbe, 0xb3, 0xd8, 0x2f, 0x44, 0x7c, 0x9b, 0x89, 0x7b, 0xe2, 0xc9, + 0x4f, 0xad, 0xa9, 0xb0, 0xd0, 0x98, 0x9f, 0xf7, 0x21, 0xfd, 0x90, 0x8f, + 0x75, 0x68, 0x41, 0x1d, 0xc1, 0x6b, 0xf1, 0x88, 0x6f, 0x5b, 0x21, 0xeb, + 0xdf, 0xd2, 0x70, 0x0b, 0xba, 0x4e, 0x49, 0xcd, 0x89, 0x62, 0xeb, 0xa9, + 0x76, 0xd6, 0x19, 0x1d, 0x1d, 0x63, 0x9d, 0xec, 0xe3, 0xba, 0x55, 0xf7, + 0xb4, 0xe8, 0x49, 0xf4, 0xac, 0x85, 0xa2, 0xae, 0x1b, 0xe7, 0xa2, 0xa5, + 0x9e, 0xf8, 0x3d, 0xdb, 0x87, 0x46, 0x8d, 0x10, 0xf5, 0xf3, 0x2b, 0x2f, + 0x82, 0x16, 0xce, 0x18, 0xe2, 0x7b, 0xfc, 0xdb, 0x4c, 0x63, 0x63, 0xf3, + 0xb8, 0xe5, 0xd1, 0x65, 0xbe, 0x1d, 0xb1, 0xed, 0xb6, 0x81, 0xb5, 0xac, + 0x7d, 0xba, 0x87, 0xb6, 0x2a, 0xcd, 0xb2, 0x6f, 0xb4, 0xd9, 0x7a, 0xff, + 0x46, 0xe6, 0x35, 0xf6, 0xe9, 0x3e, 0x1f, 0x73, 0xa5, 0xef, 0x94, 0x85, + 0x69, 0xe3, 0x4d, 0xeb, 0x51, 0xdd, 0x43, 0xbb, 0x7c, 0x95, 0x79, 0x57, + 0x70, 0x49, 0xca, 0x7f, 0xfb, 0xa4, 0xc7, 0x55, 0x95, 0x42, 0x73, 0x19, + 0x7d, 0xee, 0xd5, 0xa4, 0x33, 0x73, 0x3c, 0x96, 0xbf, 0xcd, 0xbf, 0x65, + 0x82, 0xbd, 0x04, 0x7b, 0x5d, 0xa7, 0xbf, 0xfb, 0xaa, 0xff, 0xee, 0x09, + 0xb7, 0xaa, 0x4d, 0xc1, 0xdd, 0xb2, 0xd6, 0xc2, 0xc7, 0xab, 0xe3, 0x83, + 0x11, 0x17, 0x73, 0x24, 0x69, 0x99, 0xf9, 0x66, 0x7f, 0x86, 0x39, 0x79, + 0xdb, 0x04, 0xd2, 0x32, 0x9f, 0x0d, 0xae, 0x1e, 0xee, 0x0d, 0x42, 0x66, + 0x69, 0xf8, 0x06, 0xa3, 0x32, 0x4c, 0x9f, 0x8b, 0xb4, 0xa9, 0xf8, 0x42, + 0x3f, 0xe2, 0x17, 0x3f, 0x76, 0xbf, 0x69, 0x3d, 0x9e, 0x5f, 0xcb, 0xe7, + 0x3b, 0x99, 0x2f, 0xd3, 0xcc, 0x9f, 0xc3, 0x83, 0x5e, 0xc8, 0x3b, 0x5a, + 0xe6, 0x0d, 0x15, 0xa3, 0xaf, 0xe3, 0x9b, 0x7c, 0x3e, 0xd4, 0xc1, 0x5c, + 0x39, 0x6d, 0xc4, 0xd3, 0x1b, 0x90, 0xed, 0xac, 0x86, 0x66, 0x34, 0x28, + 0x99, 0x7d, 0x89, 0x1d, 0x12, 0xf8, 0x39, 0xd7, 0xf4, 0xe8, 0xa2, 0xc7, + 0xf5, 0xe8, 0x9b, 0x66, 0xfd, 0xbf, 0xe6, 0x6f, 0xa2, 0x03, 0xd1, 0xcb, + 0x37, 0xcb, 0x50, 0xb1, 0x88, 0xb2, 0xfd, 0xdc, 0xce, 0x2b, 0x7e, 0x5d, + 0xc7, 0x7f, 0x26, 0x3e, 0xfa, 0x4f, 0x05, 0x99, 0x71, 0x96, 0x30, 0x9f, + 0xdd, 0x47, 0xb5, 0x2e, 0x9b, 0x4a, 0x14, 0x67, 0x9e, 0x3e, 0x7f, 0xe7, + 0xa4, 0x85, 0x93, 0x46, 0x10, 0xd2, 0xe3, 0x97, 0x27, 0xe7, 0x89, 0x00, + 0x9a, 0xd0, 0xc1, 0xeb, 0xed, 0x93, 0x95, 0xaa, 0x7d, 0xc2, 0xc2, 0x5f, + 0x18, 0x5a, 0xb6, 0xcd, 0xcd, 0x98, 0x36, 0xb4, 0xb3, 0xc0, 0x3b, 0xc4, + 0x4a, 0xe2, 0x63, 0x1e, 0x04, 0x74, 0x87, 0x56, 0xd3, 0xd4, 0x6d, 0xc4, + 0x0f, 0x12, 0x63, 0xee, 0x15, 0x15, 0x48, 0xaa, 0x29, 0x8f, 0xe8, 0xad, + 0x13, 0xe9, 0x42, 0xa5, 0xda, 0x4e, 0x5d, 0xde, 0xb1, 0xaa, 0x0c, 0x97, + 0x6c, 0x5d, 0xde, 0x46, 0x5d, 0xe2, 0xf5, 0xa5, 0x70, 0x5f, 0xa8, 0x45, + 0xa7, 0x82, 0xdd, 0x9f, 0x55, 0xb2, 0x4e, 0xa7, 0x89, 0x6f, 0x89, 0x07, + 0x43, 0x3d, 0xf8, 0x2e, 0xf3, 0xcd, 0xa3, 0xf4, 0xd5, 0x5f, 0xe9, 0x4d, + 0xa8, 0xf8, 0x5e, 0x33, 0xed, 0xb8, 0xd6, 0xbf, 0x79, 0x22, 0x83, 0xc7, + 0x66, 0x2d, 0x3c, 0xc5, 0x38, 0x69, 0x48, 0x66, 0x43, 0xe5, 0xec, 0xd7, + 0x58, 0xd3, 0x16, 0x4e, 0xd8, 0x7e, 0xbe, 0xab, 0x75, 0xfd, 0x4c, 0x04, + 0xee, 0xef, 0xca, 0xef, 0x3b, 0x5b, 0xa3, 0x33, 0xf2, 0x9d, 0xe1, 0xb7, + 0x85, 0x01, 0x43, 0x4b, 0x7f, 0xec, 0xae, 0x40, 0x65, 0xdc, 0xb2, 0x06, + 0x92, 0x72, 0xbd, 0xaf, 0x35, 0x61, 0xdf, 0xdf, 0xc3, 0xef, 0xd2, 0x4c, + 0xfa, 0x6f, 0x04, 0x0b, 0x46, 0xd3, 0x94, 0x79, 0x2b, 0xeb, 0x7b, 0x86, + 0xf5, 0xbd, 0x36, 0xa5, 0xa5, 0x77, 0xb8, 0x65, 0xfe, 0x32, 0x7f, 0xa0, + 0x9a, 0xd7, 0x6f, 0x2f, 0xd6, 0xf7, 0xaa, 0x53, 0x32, 0xd3, 0x23, 0x06, + 0x84, 0xb3, 0x17, 0xd2, 0xc5, 0xfa, 0x5e, 0x31, 0xe6, 0xc1, 0x16, 0xd6, + 0x76, 0x2f, 0xb1, 0xf8, 0xc6, 0x7c, 0x2d, 0xfc, 0x27, 0xdc, 0x88, 0x25, + 0x7f, 0x82, 0x03, 0xf4, 0xb1, 0x03, 0x09, 0xb7, 0x8a, 0x2e, 0x71, 0x51, + 0x4f, 0xff, 0x88, 0x7d, 0x21, 0x37, 0xaa, 0xf4, 0x9f, 0xe1, 0x81, 0x2f, + 0xa8, 0xe9, 0x99, 0x09, 0x89, 0xed, 0x5d, 0xad, 0x5b, 0x4e, 0x39, 0x35, + 0x3d, 0x70, 0x6a, 0x78, 0x41, 0x6a, 0x7a, 0xed, 0xea, 0x0c, 0x4e, 0x4f, + 0xe2, 0x3b, 0x4b, 0x09, 0x1e, 0x6b, 0xb9, 0x66, 0x7d, 0x32, 0xce, 0xde, + 0x5a, 0xeb, 0xef, 0x50, 0xf1, 0x23, 0x55, 0xcc, 0x01, 0xa7, 0x59, 0xd3, + 0x7d, 0xa9, 0x78, 0x28, 0xe1, 0x42, 0x97, 0x97, 0xf6, 0x78, 0x9f, 0x7d, + 0xf6, 0x5b, 0xf9, 0x28, 0x69, 0x96, 0xc1, 0xc3, 0x9a, 0xfe, 0xbe, 0x8e, + 0xcf, 0xdc, 0xf4, 0xbd, 0x77, 0xdc, 0x3e, 0x5c, 0xcd, 0x3b, 0x35, 0xbd, + 0xba, 0xc1, 0x1a, 0xba, 0x9c, 0x0c, 0xe0, 0x4a, 0xde, 0xa0, 0x0f, 0x66, + 0x70, 0x98, 0x35, 0xfd, 0xb2, 0x1e, 0xc2, 0x87, 0xf9, 0x16, 0xfa, 0x65, + 0x18, 0xbf, 0x24, 0xfe, 0x5d, 0xc5, 0x9a, 0x7e, 0x27, 0x7d, 0x2a, 0xc9, + 0x9a, 0xde, 0x66, 0xe3, 0x8d, 0x7d, 0xad, 0x67, 0xc6, 0xed, 0x9a, 0xde, + 0xe0, 0x62, 0x3d, 0xf4, 0x22, 0xbe, 0xc0, 0x3c, 0x61, 0xfd, 0x6a, 0x6d, + 0x80, 0xcf, 0x52, 0x6f, 0x85, 0xd5, 0x98, 0xb2, 0x6b, 0xd0, 0x7a, 0xff, + 0x76, 0xae, 0xbd, 0xd8, 0x8e, 0x33, 0x0b, 0x5b, 0x57, 0xbd, 0x86, 0x3f, + 0xaa, 0x71, 0xd1, 0x0f, 0x53, 0xfe, 0x3b, 0x18, 0x6b, 0xc1, 0x54, 0x69, + 0xe6, 0x91, 0xe0, 0x3a, 0xb7, 0xf9, 0xef, 0xa4, 0x6f, 0xdc, 0xb2, 0x8a, + 0x99, 0x24, 0xe4, 0xc4, 0x59, 0x3b, 0xe3, 0x2c, 0xc2, 0x38, 0x5b, 0xca, + 0x38, 0x7b, 0xdc, 0x88, 0x27, 0xd6, 0x13, 0x77, 0xbd, 0x9c, 0x97, 0x58, + 0x6b, 0x26, 0x5d, 0x8d, 0x72, 0x0d, 0xf7, 0x4a, 0xcc, 0x6c, 0x5d, 0x35, + 0x7c, 0xb6, 0x12, 0xa2, 0x2b, 0x7c, 0xb6, 0x98, 0x18, 0x83, 0x99, 0xe9, + 0xe2, 0x82, 0x3b, 0x3e, 0x78, 0xab, 0x3b, 0x3e, 0xf0, 0x9e, 0x7a, 0xd3, + 0x7a, 0x9d, 0x71, 0xb6, 0x8d, 0x71, 0xb6, 0x9d, 0x71, 0xd6, 0x66, 0x5a, + 0x78, 0x2e, 0xa9, 0x65, 0x9a, 0x5c, 0x31, 0xa3, 0xcd, 0x85, 0xa5, 0x95, + 0x2c, 0x0d, 0x7e, 0xc4, 0x3b, 0xff, 0x88, 0xfc, 0x5f, 0x34, 0xe2, 0xdd, + 0x09, 0x25, 0xb1, 0x15, 0xc5, 0x07, 0x94, 0xbb, 0xbc, 0x18, 0x5b, 0x7b, + 0xa7, 0xcf, 0x17, 0x7d, 0xa3, 0x24, 0xbb, 0x1b, 0xcf, 0x1a, 0xcc, 0xa5, + 0x8b, 0xb4, 0x68, 0xd6, 0xd5, 0x83, 0x23, 0xd4, 0xa3, 0x3f, 0xde, 0x83, + 0xa3, 0xac, 0x87, 0xf7, 0xb2, 0x0e, 0xdf, 0x67, 0xc6, 0x5a, 0x36, 0xb3, + 0xff, 0xb9, 0x14, 0xd1, 0xa2, 0x51, 0xd5, 0x83, 0x3e, 0xfa, 0x70, 0x1f, + 0xeb, 0x46, 0x9b, 0xf9, 0x6b, 0xd5, 0x41, 0xac, 0xb0, 0xa7, 0x20, 0xef, + 0x69, 0x89, 0x5e, 0x57, 0x3f, 0x7a, 0x67, 0x25, 0xb7, 0x21, 0x74, 0x53, + 0xaa, 0x07, 0xc7, 0xcd, 0x32, 0xf4, 0x34, 0x77, 0xa9, 0xdb, 0x0b, 0x32, + 0x7f, 0x63, 0x3c, 0x9a, 0x8c, 0x57, 0x9b, 0x5f, 0x85, 0x7c, 0xbc, 0x0b, + 0x39, 0x89, 0x4f, 0x73, 0xbb, 0xba, 0x73, 0x5a, 0x62, 0xbc, 0x47, 0xf5, + 0x48, 0x0c, 0x9b, 0x83, 0xea, 0x2e, 0x89, 0x69, 0x7b, 0x66, 0x2d, 0x71, + 0x2f, 0x7b, 0x1a, 0xb7, 0x11, 0xc7, 0x81, 0x31, 0xe5, 0xfe, 0x5e, 0x84, + 0x71, 0xd7, 0x56, 0xe6, 0xa2, 0x9f, 0xc6, 0x68, 0x3b, 0x17, 0xda, 0x8d, + 0xdf, 0xb1, 0xb2, 0xa1, 0x5e, 0xc6, 0x54, 0x0f, 0x0e, 0x9b, 0x5f, 0xb6, + 0x2e, 0xdb, 0xf8, 0xa4, 0x94, 0xd7, 0xd7, 0xe3, 0x9e, 0x89, 0x25, 0xf0, + 0xe9, 0x52, 0xb7, 0x03, 0x48, 0xd4, 0xf8, 0x50, 0xa1, 0x4b, 0xbd, 0xd9, + 0xd7, 0x3a, 0x77, 0x42, 0x49, 0xff, 0x51, 0x8c, 0xef, 0xf5, 0xb8, 0x9f, + 0x79, 0x60, 0x77, 0xf2, 0x1e, 0xdc, 0x17, 0xaa, 0x40, 0x90, 0x7a, 0xda, + 0x1f, 0x0a, 0x30, 0xbf, 0xfe, 0x7e, 0x91, 0xce, 0xb3, 0x65, 0xc5, 0xbe, + 0xfa, 0x1a, 0xb6, 0xaa, 0x65, 0x8c, 0xad, 0x9b, 0x94, 0x39, 0x51, 0xa6, + 0x35, 0x32, 0xa9, 0x23, 0xc8, 0x7e, 0x76, 0x7d, 0x52, 0x1b, 0x5c, 0xef, + 0x8e, 0x49, 0xaf, 0x92, 0x0b, 0x12, 0xd7, 0xe5, 0xe3, 0xf1, 0xee, 0x26, + 0xd1, 0xb1, 0x1e, 0xc1, 0x26, 0xea, 0x69, 0x4b, 0x3e, 0xcc, 0x18, 0x5a, + 0x28, 0x13, 0x8c, 0x94, 0xce, 0x5f, 0xa7, 0x15, 0x21, 0xad, 0xc8, 0xa4, + 0xe0, 0xb5, 0x0c, 0xf1, 0x9a, 0xce, 0x38, 0xb4, 0xac, 0x75, 0xc4, 0x69, + 0x81, 0x53, 0x32, 0x6f, 0x8a, 0x1d, 0x21, 0xb6, 0x6d, 0x22, 0xee, 0xed, + 0xa1, 0x57, 0x5b, 0xb7, 0xd4, 0xc7, 0x8d, 0x36, 0x85, 0x47, 0x66, 0x9a, + 0xe1, 0x73, 0x93, 0xe6, 0x3b, 0xf9, 0x10, 0x2e, 0xe7, 0x23, 0x78, 0x9b, + 0xb4, 0x2f, 0xd9, 0xb4, 0xeb, 0xf0, 0x8b, 0x62, 0xde, 0x4a, 0x32, 0x6f, + 0x6d, 0x98, 0x50, 0xf4, 0xd7, 0x28, 0x86, 0x8c, 0xbf, 0xfe, 0xec, 0xd2, + 0xcd, 0x3e, 0xea, 0x4d, 0x64, 0xf1, 0xf0, 0x7b, 0x14, 0xfb, 0xed, 0x3c, + 0xfd, 0xda, 0x67, 0x53, 0x35, 0xb4, 0x15, 0x75, 0x5f, 0x5d, 0x7c, 0x6f, + 0xe5, 0x54, 0xa1, 0x28, 0xaf, 0x0e, 0xd7, 0xa9, 0x04, 0xca, 0x4e, 0x5d, + 0xe3, 0x55, 0x97, 0xf8, 0x60, 0x65, 0x7d, 0xe4, 0xfb, 0x5c, 0xff, 0x21, + 0x62, 0x3e, 0x8b, 0xeb, 0x5f, 0xb5, 0xd7, 0x0d, 0x73, 0x5d, 0x75, 0x0d, + 0x1f, 0x46, 0xae, 0xbd, 0x13, 0xa2, 0xec, 0x78, 0x38, 0x42, 0xdd, 0x5d, + 0x59, 0x23, 0xcf, 0x05, 0x70, 0x7b, 0x7e, 0x55, 0xb9, 0xe4, 0x71, 0x3f, + 0xfb, 0x01, 0xc7, 0x97, 0x88, 0xf7, 0xcc, 0xe7, 0x79, 0x4f, 0xf0, 0xd7, + 0x7a, 0x62, 0x8d, 0xcf, 0xeb, 0x3d, 0x4c, 0x5b, 0x94, 0xd1, 0x78, 0x72, + 0xef, 0x8b, 0xea, 0xe8, 0x9f, 0x61, 0x90, 0xbd, 0xd0, 0x43, 0x13, 0x59, + 0xec, 0x9f, 0xf8, 0x63, 0x7b, 0x8f, 0x6e, 0xe5, 0x6a, 0xec, 0xe1, 0x9a, + 0xfb, 0xaa, 0x19, 0x47, 0xff, 0x2d, 0x19, 0x17, 0x8c, 0xb4, 0xbd, 0x12, + 0x52, 0x6b, 0xe3, 0x2d, 0xb7, 0x2a, 0x0b, 0x65, 0x49, 0x0c, 0xb4, 0x37, + 0xc7, 0x13, 0x97, 0xf1, 0x88, 0x25, 0xf3, 0x6e, 0x77, 0xb1, 0xee, 0x12, + 0x97, 0xaa, 0x76, 0xd6, 0xde, 0xb6, 0x22, 0x56, 0xda, 0x50, 0x78, 0xf3, + 0x73, 0x33, 0x05, 0xe9, 0xc7, 0xa5, 0xde, 0xf8, 0x55, 0x1b, 0xd7, 0x39, + 0xcc, 0x9c, 0xfd, 0xac, 0xf1, 0x62, 0x84, 0xd5, 0x18, 0x9e, 0x55, 0x0a, + 0x07, 0x0c, 0x2f, 0xb2, 0x61, 0x0b, 0xdb, 0xf9, 0xbd, 0x97, 0xf8, 0xe9, + 0x5d, 0xa3, 0x0a, 0x53, 0xa1, 0x10, 0x31, 0x23, 0x73, 0xb0, 0xeb, 0xff, + 0x78, 0x65, 0x5f, 0x27, 0xea, 0x92, 0x3d, 0xf8, 0x7f, 0x6d, 0x5f, 0x66, + 0x15, 0xf1, 0x8b, 0xc8, 0xee, 0x57, 0xcc, 0xa1, 0x09, 0x10, 0xd3, 0xec, + 0x32, 0xe6, 0xa3, 0x2e, 0xa4, 0xaf, 0xba, 0xa0, 0x9d, 0x7e, 0x87, 0x7d, + 0xde, 0x43, 0xf5, 0xda, 0xe9, 0x56, 0xb7, 0x8e, 0xc1, 0xe3, 0x3e, 0x3c, + 0x78, 0xbc, 0x03, 0xd5, 0xf6, 0x7c, 0x68, 0x94, 0x3a, 0x75, 0xb1, 0xbf, + 0x1a, 0xfe, 0xd4, 0xc3, 0x3e, 0xeb, 0xea, 0xea, 0x87, 0xd1, 0x62, 0x5f, + 0x1f, 0xc1, 0x9e, 0x09, 0xbf, 0xda, 0x32, 0xe1, 0x41, 0xc7, 0x9d, 0x0f, + 0xc3, 0xbb, 0xaa, 0x97, 0x7c, 0xc9, 0x75, 0xf9, 0xfd, 0x2e, 0xf6, 0x67, + 0xc2, 0x5f, 0x19, 0xa2, 0x4b, 0xc8, 0xdb, 0x2a, 0x1d, 0x43, 0xc7, 0x3d, + 0x6a, 0x87, 0xf9, 0x37, 0xd6, 0x55, 0x7b, 0xcf, 0x47, 0xae, 0x55, 0xc8, + 0x59, 0x00, 0x3e, 0x23, 0x39, 0xa7, 0x0f, 0x13, 0x8c, 0xed, 0xbb, 0xec, + 0xf7, 0x8f, 0x97, 0x39, 0x32, 0xa5, 0xd9, 0xb7, 0xb6, 0xd3, 0x7e, 0xf2, + 0x4c, 0x6b, 0xf1, 0xda, 0x7a, 0x9f, 0x73, 0xde, 0x40, 0x7c, 0xa1, 0x0f, + 0xcb, 0x68, 0x84, 0xfa, 0xb8, 0x5d, 0xa7, 0x50, 0x9f, 0x67, 0x42, 0x5d, + 0xe2, 0xf0, 0xfb, 0x80, 0x39, 0xcf, 0x9e, 0x53, 0x67, 0xde, 0xa4, 0xee, + 0x16, 0xcb, 0xfb, 0x55, 0xbe, 0xdf, 0x7e, 0x5f, 0xf2, 0x2d, 0xb1, 0x66, + 0x50, 0x30, 0xe7, 0x17, 0xdd, 0xff, 0x5d, 0xc8, 0x3d, 0x8f, 0xfe, 0xa7, + 0x8c, 0xe3, 0x78, 0x77, 0xa5, 0x4b, 0xfc, 0xe7, 0x4f, 0x71, 0xdf, 0xf4, + 0x30, 0xef, 0x0b, 0xfd, 0x83, 0xec, 0x25, 0x3c, 0xaa, 0x93, 0xf9, 0x67, + 0xef, 0x71, 0xd7, 0xed, 0x65, 0xf8, 0x4b, 0xab, 0x7c, 0xf1, 0x10, 0xea, + 0x93, 0x23, 0x7c, 0x5e, 0xa1, 0x9d, 0xb8, 0xf1, 0x31, 0x63, 0x03, 0x3a, + 0x6a, 0x24, 0x07, 0x3c, 0x6b, 0xf5, 0xf5, 0x88, 0x0e, 0x15, 0x36, 0xf2, + 0xfa, 0x73, 0xb4, 0xef, 0x93, 0x86, 0x07, 0xf5, 0x8b, 0x64, 0xd6, 0xa7, + 0x8d, 0xa7, 0xf1, 0x75, 0x9f, 0xb3, 0xf7, 0x95, 0xb5, 0xaa, 0x75, 0x7d, + 0xe0, 0x0e, 0x57, 0xfd, 0xf8, 0x1b, 0xf4, 0xa7, 0xb6, 0x55, 0x37, 0xde, + 0x2b, 0xe9, 0xc4, 0x40, 0x64, 0xd5, 0x33, 0x16, 0x6e, 0x1a, 0x46, 0x68, + 0xd5, 0x8d, 0xf6, 0x2f, 0xf1, 0x7d, 0x90, 0x31, 0x88, 0x6c, 0x75, 0x4a, + 0xe6, 0x3f, 0x71, 0xd2, 0x39, 0x88, 0x3f, 0x2c, 0x8c, 0xe0, 0xc0, 0x44, + 0x11, 0x5b, 0xd3, 0xb7, 0xf5, 0x55, 0xd7, 0x65, 0x7b, 0x60, 0x22, 0xde, + 0x5b, 0x55, 0x94, 0x6d, 0x1f, 0xfb, 0x8c, 0x4a, 0xe6, 0xd8, 0xfb, 0xa9, + 0xd3, 0x01, 0x5b, 0xa7, 0x3d, 0x30, 0xf2, 0xd7, 0xe9, 0xf6, 0x93, 0xae, + 0x3f, 0x25, 0x7a, 0x93, 0xfd, 0xb6, 0x83, 0xd8, 0x4b, 0xba, 0xbb, 0x6f, + 0xa0, 0xdb, 0x67, 0x5c, 0xa7, 0xbb, 0x6b, 0x22, 0x7e, 0xda, 0x55, 0xa4, + 0xfb, 0xed, 0xe9, 0x12, 0x8d, 0x2c, 0xb6, 0xad, 0xca, 0x22, 0xbf, 0x6e, + 0x9f, 0xb5, 0xcf, 0xd6, 0xc7, 0x59, 0xfb, 0xfa, 0xc6, 0x7a, 0x89, 0x07, + 0xfe, 0x9a, 0xd2, 0xed, 0xbd, 0x7d, 0x07, 0x7b, 0xdd, 0x18, 0x1f, 0xda, + 0x9b, 0x5b, 0xdc, 0x69, 0xc6, 0x76, 0xd8, 0xb7, 0xf9, 0x73, 0x33, 0x8d, + 0x0e, 0xf6, 0x61, 0x9b, 0xcc, 0x2e, 0x7f, 0xa7, 0xe9, 0x23, 0xee, 0xaa, + 0x54, 0x1b, 0x27, 0x64, 0xb6, 0x21, 0xb1, 0x5c, 0xc4, 0xc2, 0x05, 0xe9, + 0xf7, 0x76, 0xb2, 0x4f, 0x58, 0x46, 0xfb, 0xf6, 0xe2, 0x48, 0xa1, 0x57, + 0xa5, 0xc3, 0x5c, 0xc7, 0x94, 0xba, 0x02, 0xd6, 0xbc, 0x6e, 0x54, 0xd2, + 0x97, 0xc2, 0xa9, 0x81, 0xd4, 0xc9, 0x7a, 0x0b, 0xc4, 0x28, 0xbe, 0x45, + 0xa9, 0x6c, 0x6a, 0x7b, 0xbd, 0x1b, 0xc7, 0x6c, 0xfc, 0xa5, 0x4d, 0xf1, + 0x33, 0x2e, 0x31, 0x73, 0xc7, 0x84, 0xd4, 0x31, 0x42, 0x48, 0x7d, 0x08, + 0xff, 0x90, 0x9c, 0x1f, 0xa8, 0x41, 0xfa, 0xde, 0x1a, 0x48, 0x5f, 0x71, + 0x04, 0x3f, 0xd2, 0x23, 0xbe, 0x4c, 0xc1, 0xa3, 0xb6, 0x98, 0x33, 0xfe, + 0xad, 0x66, 0x10, 0x01, 0xf6, 0x65, 0x5d, 0xee, 0x18, 0xfb, 0x0c, 0xd1, + 0x63, 0x67, 0xeb, 0xb2, 0x7c, 0xc6, 0xdf, 0x6e, 0x3a, 0xb9, 0xf0, 0x96, + 0x29, 0x9f, 0xbf, 0x63, 0x32, 0x16, 0x39, 0x62, 0x63, 0xb1, 0xae, 0xd6, + 0x58, 0xde, 0xb2, 0x5e, 0x31, 0xe6, 0xaf, 0x96, 0x3b, 0x3d, 0x48, 0x6b, + 0x22, 0xdf, 0x84, 0xbb, 0x89, 0x9f, 0xda, 0x26, 0x9b, 0x60, 0x4c, 0x02, + 0x27, 0x8e, 0x47, 0xb0, 0x72, 0x42, 0x3b, 0x3d, 0xe8, 0xce, 0x60, 0x7c, + 0xb6, 0x13, 0x13, 0x05, 0xff, 0x42, 0xd4, 0x45, 0x5c, 0x9d, 0x74, 0xe1, + 0x76, 0x63, 0xb5, 0x9a, 0xb7, 0x63, 0x5a, 0xe1, 0x2e, 0x63, 0xbb, 0xea, + 0xb5, 0x31, 0xc5, 0x0c, 0xb1, 0x88, 0xc2, 0x4d, 0xce, 0x5c, 0xbe, 0x35, + 0x49, 0xcc, 0x7d, 0xfb, 0x84, 0xd4, 0x77, 0x0b, 0xaf, 0x26, 0xa9, 0x97, + 0x64, 0x36, 0xe3, 0x65, 0x0f, 0xb4, 0x4f, 0x69, 0xdd, 0x86, 0x72, 0x30, + 0xde, 0xad, 0x33, 0x0e, 0x2e, 0x5c, 0x36, 0xd3, 0xec, 0x97, 0x1c, 0xd4, + 0x6e, 0x68, 0x11, 0x8f, 0x2b, 0x84, 0x01, 0x9b, 0x46, 0x6f, 0xab, 0x31, + 0x53, 0x86, 0xa5, 0x7a, 0x0f, 0x4e, 0xdb, 0x32, 0xf4, 0xb7, 0xae, 0x27, + 0xbe, 0x7e, 0xdc, 0xcc, 0xb0, 0x07, 0x96, 0xfd, 0xd0, 0x58, 0xa2, 0xc5, + 0xdd, 0x46, 0x0c, 0x1b, 0x8b, 0x2e, 0xa8, 0xb4, 0xca, 0x7a, 0x1a, 0xd3, + 0x33, 0x60, 0x45, 0xa9, 0x71, 0xea, 0x9b, 0xc8, 0x18, 0x27, 0xce, 0x6a, + 0x3b, 0xee, 0x5f, 0x48, 0xc3, 0x99, 0xdf, 0x6c, 0x32, 0xfe, 0x37, 0x2e, + 0x85, 0xb5, 0x23, 0x69, 0xf2, 0xdd, 0xc1, 0xbc, 0x3b, 0xdf, 0xe3, 0xe1, + 0x7d, 0x99, 0xdb, 0x75, 0xb7, 0x8e, 0xe6, 0x30, 0xef, 0x4e, 0x49, 0x5f, + 0x85, 0x60, 0x77, 0x01, 0x32, 0x43, 0x62, 0x6f, 0xf1, 0xa9, 0x55, 0xda, + 0x3b, 0xea, 0x9a, 0x74, 0xf6, 0xc5, 0x72, 0xb3, 0x9e, 0xe0, 0x56, 0xb3, + 0x19, 0xc7, 0x0a, 0x9e, 0x1b, 0x68, 0xc7, 0x8f, 0xdc, 0xe2, 0x72, 0x21, + 0xbe, 0xea, 0x2e, 0x55, 0xdc, 0x5b, 0x62, 0x9e, 0xc8, 0xd8, 0x35, 0xb1, + 0x8c, 0x72, 0x5e, 0x38, 0x29, 0x6b, 0x7c, 0xab, 0x75, 0xf4, 0xa4, 0xd4, + 0xc8, 0xee, 0xd6, 0x88, 0xa9, 0x75, 0x4b, 0x1f, 0x58, 0x4d, 0x3d, 0x7d, + 0x34, 0x26, 0x35, 0x78, 0x3f, 0x6b, 0xb0, 0xb6, 0xd0, 0xae, 0xa4, 0x8e, + 0x69, 0x09, 0xbf, 0xdb, 0x85, 0x2b, 0x0d, 0x5a, 0xe6, 0x79, 0x68, 0xbd, + 0xce, 0xbc, 0x70, 0x67, 0x6b, 0x63, 0x11, 0x0f, 0xdf, 0x3a, 0xd3, 0x27, + 0xe7, 0x49, 0x6c, 0x1d, 0x37, 0xe5, 0x05, 0x1b, 0x5b, 0xd6, 0x4b, 0xc9, + 0x2e, 0xe2, 0x06, 0xc1, 0xc6, 0x72, 0xfd, 0x81, 0xd6, 0x86, 0x29, 0x1f, + 0x79, 0x53, 0x78, 0x8f, 0x75, 0xe9, 0x48, 0xa1, 0xc4, 0xa3, 0x83, 0x9b, + 0x37, 0x13, 0x37, 0xbb, 0x53, 0x5a, 0xcb, 0x06, 0xe2, 0x66, 0x9d, 0x3d, + 0x84, 0x07, 0x3d, 0x78, 0xcc, 0x74, 0xfa, 0x08, 0xc1, 0xce, 0xd6, 0x49, + 0x2d, 0x2d, 0xb8, 0xf9, 0xea, 0x6a, 0x60, 0x07, 0x71, 0xf3, 0x42, 0xce, + 0x83, 0x0c, 0x71, 0xf3, 0x47, 0x39, 0x1f, 0xee, 0x20, 0x6e, 0xbe, 0x42, + 0x8c, 0x75, 0x3e, 0xf9, 0x4b, 0x7c, 0xbb, 0x38, 0x13, 0xdb, 0x95, 0xf0, + 0xd1, 0xb7, 0x05, 0x3b, 0xff, 0xa6, 0x88, 0x9d, 0xff, 0xcb, 0x3f, 0xc3, + 0xce, 0x77, 0x13, 0x13, 0x76, 0x4d, 0xc8, 0xfe, 0xd1, 0xae, 0xd6, 0xd7, + 0x4f, 0xc9, 0x99, 0x95, 0x5b, 0xf1, 0xee, 0xc9, 0xe1, 0x7e, 0x62, 0x65, + 0x8c, 0x24, 0x33, 0xc8, 0x4d, 0x62, 0x09, 0x71, 0xc1, 0x4b, 0x6e, 0xae, + 0xbb, 0x32, 0xa9, 0x19, 0x6f, 0xa8, 0x78, 0x67, 0x06, 0x71, 0xf6, 0xca, + 0xda, 0x02, 0x4d, 0x98, 0xf6, 0xa4, 0x88, 0x8d, 0x59, 0x03, 0x97, 0x12, + 0x3b, 0x57, 0xcd, 0x01, 0xb5, 0x73, 0x0e, 0x76, 0x96, 0x79, 0x58, 0x55, + 0x1c, 0x7f, 0x46, 0xec, 0xcc, 0xfe, 0x96, 0xa1, 0x36, 0xd7, 0xc4, 0x18, + 0x55, 0x38, 0x1c, 0x0f, 0xa0, 0xeb, 0x38, 0x71, 0x8f, 0x3d, 0x0f, 0xb3, + 0x86, 0x7e, 0x6a, 0x64, 0x70, 0x74, 0xd6, 0x99, 0x87, 0x6d, 0x22, 0x7e, + 0xf3, 0xc4, 0xc3, 0x28, 0x9f, 0xf3, 0xe0, 0x19, 0xe2, 0xe7, 0x8d, 0xb4, + 0xf3, 0x19, 0xe2, 0xe7, 0xbb, 0x6f, 0x98, 0x89, 0x4d, 0xcd, 0xe1, 0x15, + 0x62, 0xf9, 0xba, 0x5a, 0xc4, 0x65, 0xde, 0x61, 0x5d, 0x59, 0x13, 0xc0, + 0x39, 0x1b, 0x3f, 0xfb, 0x17, 0xb2, 0xca, 0x91, 0xad, 0x8c, 0xb6, 0x10, + 0xbb, 0xba, 0x68, 0xd7, 0xb6, 0x93, 0x5a, 0xe7, 0x8b, 0xd4, 0x45, 0x63, + 0xfc, 0xbc, 0x6d, 0x8f, 0xbe, 0xa4, 0xcc, 0x4e, 0x3a, 0x5b, 0xe5, 0x5c, + 0x55, 0x05, 0xed, 0xbd, 0x65, 0x2c, 0x96, 0xfe, 0x00, 0x4e, 0x4c, 0x26, + 0xf2, 0x65, 0xc5, 0x7a, 0x28, 0xf7, 0xfa, 0x79, 0x2f, 0x8d, 0xce, 0x35, + 0x8e, 0x7f, 0x27, 0xf2, 0xc7, 0x88, 0x5d, 0x65, 0xcf, 0x34, 0x14, 0xdc, + 0x64, 0x76, 0x62, 0xdc, 0x8c, 0xa2, 0xfc, 0x5c, 0x71, 0xef, 0xf5, 0x9c, + 0x9c, 0xc5, 0xdb, 0xd9, 0x1a, 0xfa, 0x5e, 0x09, 0x13, 0xa6, 0x89, 0xef, + 0xc2, 0xbe, 0xdb, 0x0b, 0x82, 0x17, 0xbb, 0x71, 0xd4, 0xd4, 0x22, 0x3f, + 0x67, 0x4c, 0xdc, 0x2b, 0xfb, 0xee, 0x37, 0xcc, 0x9e, 0x1e, 0xe4, 0x3d, + 0xf3, 0x73, 0xb3, 0xa7, 0xc1, 0x09, 0xfc, 0xc6, 0xdd, 0x5c, 0x0e, 0xd7, + 0x4a, 0x2f, 0x31, 0xbd, 0x16, 0x19, 0xc1, 0x23, 0xc4, 0x1c, 0xbf, 0x56, + 0x01, 0xdd, 0xd3, 0xdf, 0xe4, 0xd6, 0x22, 0x33, 0x2a, 0xc0, 0x77, 0x77, + 0x32, 0xbf, 0xed, 0xa4, 0x6f, 0xc4, 0x16, 0x2a, 0x94, 0x1b, 0x97, 0xbe, + 0x6c, 0xe3, 0x51, 0x7f, 0x37, 0xaf, 0x8d, 0x17, 0x4a, 0xb8, 0xa6, 0x47, + 0x78, 0xc5, 0xa6, 0xe3, 0x4e, 0x0e, 0xd1, 0xf3, 0xfe, 0x85, 0x4b, 0x70, + 0x64, 0xab, 0xa4, 0xac, 0xf7, 0x8f, 0x85, 0xac, 0xde, 0xc5, 0x12, 0xc3, + 0x3a, 0xb6, 0x99, 0xe2, 0x5f, 0x7d, 0xe4, 0xb3, 0x07, 0x87, 0xcc, 0xa5, + 0xec, 0xdd, 0x64, 0x0e, 0xda, 0x44, 0x6c, 0xdd, 0xcd, 0x1a, 0x6c, 0x59, + 0x83, 0x46, 0xd6, 0x6a, 0x5a, 0xab, 0x1b, 0x79, 0x35, 0x5f, 0x13, 0x21, + 0xbe, 0x59, 0xc5, 0xda, 0xdd, 0x56, 0x68, 0xc2, 0x1b, 0x67, 0x74, 0xfa, + 0x66, 0x3b, 0xf1, 0x7b, 0x37, 0xee, 0xa1, 0x3c, 0xdf, 0x2e, 0x7c, 0x07, + 0xe9, 0x6f, 0x78, 0x70, 0xe4, 0x78, 0x1a, 0xeb, 0x57, 0x0d, 0xe1, 0xd2, + 0x37, 0x7d, 0xcc, 0x55, 0x01, 0x3c, 0x7e, 0x5c, 0xf2, 0x6b, 0x09, 0x6f, + 0xdf, 0x88, 0x45, 0x7c, 0x88, 0xda, 0x38, 0xe4, 0x8b, 0xef, 0x39, 0x18, + 0xc5, 0xcf, 0xfe, 0xb7, 0xf4, 0x3e, 0xf3, 0xd0, 0xaa, 0x7f, 0x86, 0x67, + 0x88, 0x5b, 0x88, 0x05, 0x2a, 0x12, 0xf6, 0xb9, 0xb7, 0x12, 0xde, 0xf5, + 0xd0, 0x07, 0x24, 0xa6, 0x97, 0x32, 0xd6, 0x2d, 0x62, 0xe7, 0x85, 0xe2, + 0x5c, 0xf2, 0xed, 0x93, 0xda, 0xc5, 0x43, 0x88, 0x11, 0x43, 0xa3, 0x4f, + 0xb0, 0x9b, 0x9b, 0x78, 0xf7, 0x4a, 0x3c, 0x6e, 0x9c, 0x23, 0xde, 0x1d, + 0xa6, 0xad, 0x3d, 0xba, 0xf8, 0x66, 0x08, 0x65, 0x73, 0x11, 0xfa, 0xa4, + 0xcc, 0x25, 0x5f, 0xf1, 0x3b, 0x73, 0x49, 0x99, 0x85, 0xcb, 0xb9, 0x10, + 0x74, 0x94, 0xb1, 0x77, 0x2b, 0x57, 0x59, 0xe6, 0xe4, 0x29, 0xff, 0x0e, + 0xe6, 0xf7, 0x8c, 0x19, 0x0e, 0xee, 0x28, 0x84, 0xf8, 0xa9, 0x0b, 0x66, + 0x0a, 0xbf, 0xc7, 0xe7, 0x23, 0xfc, 0x8e, 0x62, 0x22, 0x5f, 0x5b, 0x21, + 0xcd, 0xc0, 0x44, 0xde, 0xc9, 0x79, 0xd1, 0xfc, 0x5e, 0xbf, 0x60, 0xcd, + 0xb6, 0xe3, 0xce, 0xdf, 0xfa, 0x0d, 0x7f, 0x7f, 0x1e, 0xf3, 0x7b, 0xc9, + 0xf7, 0x99, 0x93, 0x3a, 0x3e, 0x3a, 0x69, 0x63, 0xfe, 0x79, 0x62, 0xfe, + 0x01, 0xaf, 0x5b, 0xb0, 0xe6, 0xaf, 0xac, 0xf3, 0xf1, 0x78, 0xef, 0x34, + 0xfd, 0xa0, 0x8b, 0x74, 0x5d, 0x7a, 0xd8, 0xe6, 0xd7, 0xe1, 0xd3, 0x99, + 0xe5, 0x5e, 0x3e, 0x99, 0xc0, 0x3b, 0xd7, 0x67, 0xa7, 0x9f, 0x94, 0xd9, + 0x33, 0x60, 0x3c, 0xf2, 0xee, 0x5a, 0xf8, 0x5a, 0xd8, 0x6f, 0x7a, 0xf9, + 0x7c, 0xc4, 0x7e, 0x5e, 0x66, 0xb9, 0x9f, 0x7c, 0x56, 0xc2, 0xd3, 0x1f, + 0x5d, 0x7f, 0xe7, 0x20, 0x3b, 0x35, 0xdf, 0x79, 0xc6, 0x96, 0xdb, 0x7e, + 0x4e, 0xe6, 0xad, 0xfe, 0x05, 0xd8, 0xf1, 0xf5, 0xfb, 0x94, 0x49, 0xec, + 0x7b, 0xc0, 0x72, 0xfc, 0x36, 0x1c, 0xdc, 0xc6, 0x78, 0xf8, 0x2e, 0xed, + 0xb3, 0xed, 0x5c, 0x5d, 0xf0, 0x2e, 0xb3, 0xd3, 0x96, 0xf9, 0xae, 0x73, + 0x52, 0x93, 0xe4, 0xfe, 0x1f, 0x54, 0x08, 0x1e, 0x7f, 0x9c, 0x35, 0x6b, + 0xd8, 0x94, 0xd9, 0x3e, 0x94, 0x27, 0x75, 0x08, 0x9b, 0xc6, 0xa3, 0x78, + 0xdb, 0xf0, 0x17, 0xcf, 0xb0, 0x48, 0x4c, 0x0e, 0x30, 0x26, 0xc3, 0x18, + 0x31, 0x63, 0xd1, 0xb7, 0x89, 0x4f, 0xb3, 0x64, 0xf8, 0xe8, 0x84, 0x1b, + 0x6f, 0x13, 0x33, 0x42, 0x39, 0x67, 0x40, 0x9d, 0x77, 0x4b, 0xbf, 0x57, + 0x22, 0x5a, 0x13, 0x6b, 0xd9, 0x8b, 0x3a, 0xe4, 0x98, 0xf3, 0xfd, 0xfa, + 0x8f, 0x71, 0xec, 0x84, 0x0b, 0xf7, 0xb1, 0xef, 0x4b, 0xdf, 0x69, 0xf0, + 0xef, 0xc6, 0xfe, 0xf7, 0xf1, 0x0f, 0xd6, 0x94, 0x9c, 0xb3, 0x52, 0x72, + 0x96, 0xe3, 0x13, 0xab, 0x56, 0xd7, 0xe7, 0x9f, 0x87, 0x3e, 0x78, 0x15, + 0x8d, 0x03, 0x0b, 0xf8, 0xc0, 0x9a, 0xe7, 0xbd, 0xf7, 0x18, 0x3f, 0x2f, + 0x1a, 0xb1, 0x88, 0x8b, 0xc2, 0xcc, 0x87, 0xdd, 0xb8, 0xd7, 0x90, 0x7d, + 0x26, 0x6d, 0xe0, 0x69, 0x68, 0xfd, 0x17, 0x94, 0x9c, 0xcd, 0xb9, 0x64, + 0x65, 0x6b, 0x64, 0x5d, 0x85, 0x95, 0xcb, 0x1b, 0x3b, 0xcb, 0xa0, 0xb5, + 0x78, 0x95, 0x6e, 0xbc, 0xaf, 0xfe, 0xa7, 0x35, 0x1f, 0xfe, 0xc4, 0x7a, + 0x47, 0x2f, 0xd1, 0xd5, 0xa2, 0x3e, 0x77, 0x89, 0xb7, 0x3a, 0x1c, 0x33, + 0x65, 0x7f, 0xee, 0xc7, 0xb8, 0xef, 0x84, 0x07, 0xed, 0xc9, 0x5f, 0x5a, + 0xd9, 0xb0, 0xd0, 0x0c, 0x56, 0xa2, 0x42, 0xe8, 0x3b, 0x33, 0xeb, 0x17, + 0x0a, 0x50, 0x1d, 0xa6, 0xe0, 0x65, 0xf1, 0xd3, 0x71, 0x58, 0xa6, 0xcc, + 0x11, 0x2d, 0xdc, 0x91, 0x1c, 0xc2, 0x7b, 0xc9, 0xf4, 0x1f, 0xf8, 0xa0, + 0x5d, 0xbc, 0xec, 0xd6, 0xe6, 0x9b, 0xdc, 0x51, 0xe5, 0x6f, 0xd0, 0x07, + 0x1a, 0xec, 0x7a, 0x93, 0x67, 0xef, 0x14, 0x60, 0x6e, 0x91, 0x1e, 0x73, + 0x1c, 0x73, 0x63, 0x59, 0x78, 0x88, 0xed, 0x86, 0x9b, 0xb5, 0xcc, 0x53, + 0x4a, 0x8b, 0xec, 0x53, 0x51, 0x75, 0x8f, 0x3e, 0x88, 0x67, 0x8c, 0x78, + 0xba, 0x4d, 0xd5, 0xf9, 0x3a, 0x0b, 0x25, 0xda, 0xed, 0xc4, 0x2a, 0xda, + 0xfc, 0x65, 0x77, 0x39, 0x6a, 0x57, 0xeb, 0x9d, 0xe5, 0x6e, 0x6d, 0xf0, + 0x6b, 0x8c, 0xaf, 0xcd, 0x85, 0x79, 0xff, 0xfb, 0x71, 0x17, 0x56, 0xd8, + 0xfb, 0x08, 0xb9, 0xe2, 0x8c, 0x74, 0x1c, 0x5b, 0xc6, 0xac, 0xf5, 0xaf, + 0x26, 0xb5, 0xc8, 0x53, 0x2a, 0xbb, 0x23, 0x40, 0x4c, 0x73, 0x3f, 0xf4, + 0xe8, 0x2c, 0xeb, 0x54, 0x7b, 0xc1, 0x85, 0x5b, 0x4e, 0x09, 0xcd, 0x1c, + 0x69, 0x1e, 0x42, 0xf9, 0x09, 0x6b, 0xfd, 0x0e, 0x43, 0x1b, 0xbc, 0xec, + 0xce, 0xfe, 0xd7, 0x5a, 0xea, 0xad, 0x43, 0xc9, 0x3e, 0xda, 0x10, 0x71, + 0xc5, 0x90, 0x9c, 0x87, 0x4b, 0xfc, 0x39, 0x31, 0xc5, 0x1f, 0xd3, 0x57, + 0xdd, 0xa9, 0x20, 0xf9, 0xd4, 0x12, 0xd3, 0x90, 0xf9, 0x79, 0x14, 0x97, + 0x8d, 0xac, 0x7f, 0x53, 0x43, 0x82, 0xd8, 0x2c, 0xc2, 0x3a, 0x18, 0xc5, + 0x51, 0x62, 0xbc, 0x43, 0x6c, 0x09, 0xe7, 0x43, 0x3a, 0xb1, 0x59, 0x37, + 0x5c, 0x63, 0x01, 0x35, 0x93, 0x8b, 0x19, 0xed, 0xf8, 0xf7, 0x98, 0x8f, + 0x88, 0x8b, 0x1c, 0x42, 0xe0, 0xc4, 0xdf, 0x59, 0x55, 0xba, 0xde, 0x32, + 0xa6, 0xb8, 0xee, 0x13, 0x11, 0xea, 0x98, 0xef, 0xc9, 0xb9, 0x15, 0xb3, + 0x0b, 0xf7, 0x8c, 0x85, 0xf9, 0x7e, 0x15, 0x56, 0x9e, 0x88, 0xe2, 0x4a, + 0xf2, 0x66, 0xcc, 0xd7, 0x38, 0x18, 0xc8, 0xaf, 0xd3, 0x8f, 0xd8, 0x67, + 0x65, 0x0b, 0xba, 0xbd, 0x77, 0x74, 0xc8, 0x94, 0xfe, 0xdc, 0xc3, 0xbf, + 0x03, 0xfc, 0x88, 0x3e, 0xbf, 0x55, 0xc4, 0x3a, 0xfb, 0x5b, 0xa3, 0x33, + 0x6f, 0x55, 0xd8, 0x7b, 0x9a, 0x88, 0xf2, 0xb9, 0x90, 0x3d, 0x17, 0x1c, + 0x26, 0xcd, 0xb3, 0xe3, 0xd2, 0xb7, 0xb5, 0xad, 0xf3, 0x15, 0xf7, 0xdf, + 0xdf, 0x32, 0x5c, 0x58, 0xcf, 0xde, 0x3e, 0xa2, 0x4b, 0xbd, 0x1c, 0xd6, + 0x6a, 0xb1, 0x0e, 0xa7, 0x43, 0x6c, 0xc2, 0xf5, 0x7f, 0x87, 0x23, 0xa1, + 0x04, 0x73, 0xbe, 0x8e, 0x77, 0x73, 0x5f, 0x66, 0xbf, 0x53, 0x27, 0x67, + 0x77, 0x70, 0xcb, 0x09, 0x2f, 0xd7, 0x5c, 0x4f, 0x5c, 0xb3, 0x09, 0x3f, + 0x0b, 0x39, 0xbd, 0xc6, 0x61, 0x5e, 0x1f, 0x9d, 0x0e, 0x10, 0x8b, 0xfa, + 0xf8, 0xb9, 0x91, 0xb7, 0x2f, 0xe2, 0x49, 0x64, 0xf9, 0xd7, 0x78, 0xf2, + 0x11, 0x0f, 0xe8, 0xb8, 0x9a, 0x7b, 0x09, 0x57, 0x48, 0x3b, 0x3b, 0xed, + 0xd0, 0x3c, 0x5e, 0x10, 0xba, 0xb2, 0x5e, 0x6c, 0xb0, 0xd6, 0x2d, 0xf4, + 0x03, 0x72, 0x8e, 0xf7, 0xdf, 0xb8, 0x06, 0x91, 0xdd, 0x09, 0xf6, 0xc7, + 0x46, 0x03, 0xda, 0x43, 0xb4, 0x97, 0x29, 0x6b, 0x68, 0xec, 0x45, 0xe5, + 0xdd, 0x08, 0x56, 0x8c, 0x59, 0x43, 0x91, 0x94, 0x5c, 0xb7, 0xac, 0xea, + 0xb5, 0x7a, 0xe4, 0x0d, 0xe5, 0x61, 0xad, 0xf3, 0x50, 0x07, 0xa3, 0x38, + 0x9b, 0x6b, 0xbc, 0xf8, 0x1e, 0xb1, 0x53, 0x94, 0xbd, 0xde, 0x25, 0xf7, + 0x28, 0x66, 0x72, 0xff, 0xb1, 0x52, 0x66, 0x04, 0xa3, 0x85, 0x80, 0x9a, + 0xce, 0xfd, 0x49, 0xa5, 0xe4, 0xa2, 0x11, 0xfa, 0x42, 0xd3, 0x98, 0xf0, + 0x6a, 0x0d, 0x55, 0x91, 0xce, 0x51, 0xd2, 0x99, 0x5e, 0xa3, 0x67, 0x46, + 0x94, 0xe8, 0x2c, 0x40, 0x5c, 0xf7, 0xaa, 0xcc, 0xcf, 0xa8, 0xb7, 0xa7, + 0xf9, 0xbc, 0xe8, 0x2d, 0x8c, 0x9f, 0x15, 0xe9, 0x3c, 0x56, 0xb8, 0x88, + 0xe9, 0xdc, 0x25, 0xfb, 0xf7, 0x91, 0x42, 0x82, 0xb5, 0xaf, 0x0f, 0x79, + 0xe6, 0x93, 0xb1, 0x5c, 0x63, 0x66, 0x8c, 0x7c, 0x38, 0x67, 0xee, 0xfa, + 0xf0, 0x64, 0xf1, 0x99, 0x61, 0xbe, 0x3b, 0x7c, 0xed, 0x77, 0xd1, 0x91, + 0xb3, 0xaf, 0xef, 0xec, 0x2b, 0x94, 0xd3, 0x76, 0x4e, 0x1f, 0x7e, 0xd8, + 0xf4, 0xca, 0x0c, 0x1c, 0x2f, 0x8d, 0xaf, 0xc7, 0x88, 0xf1, 0x97, 0xd8, + 0x45, 0xb9, 0x47, 0xa9, 0xcf, 0x13, 0xa6, 0xbd, 0x7f, 0x2f, 0xe7, 0xba, + 0x98, 0xab, 0xbb, 0x5a, 0xcf, 0x10, 0x8b, 0x1d, 0x63, 0xcc, 0xec, 0x49, + 0x36, 0x76, 0xbf, 0x4c, 0xbf, 0x4b, 0x7f, 0x5d, 0xf6, 0xc8, 0x81, 0xb1, + 0x89, 0x6f, 0x63, 0xaa, 0xa6, 0x71, 0xe1, 0x59, 0xe6, 0x84, 0xd3, 0xcc, + 0x53, 0x1e, 0xe6, 0x84, 0xea, 0x09, 0x62, 0x48, 0xe6, 0xa9, 0x79, 0xe6, + 0x29, 0x8f, 0xde, 0x78, 0x71, 0x06, 0xff, 0x9d, 0x7a, 0x11, 0xfe, 0x62, + 0x89, 0x19, 0xc8, 0xb3, 0xce, 0xfc, 0x55, 0x9f, 0xe9, 0xc7, 0xa5, 0x9b, + 0x9d, 0x19, 0x9a, 0x9b, 0x35, 0x7b, 0x77, 0xae, 0x31, 0x34, 0x22, 0xb4, + 0x7b, 0xb4, 0x48, 0x96, 0xb6, 0x3a, 0x62, 0x63, 0xef, 0x6e, 0xf6, 0x0b, + 0x72, 0x8e, 0xab, 0x0a, 0x1e, 0xfa, 0xfe, 0x88, 0x21, 0xe7, 0x1b, 0x22, + 0xc1, 0xcd, 0xb4, 0xe1, 0x88, 0xd9, 0xd8, 0x12, 0x53, 0x3b, 0x70, 0xa9, + 0x98, 0x63, 0x1d, 0x2c, 0xad, 0x65, 0x8e, 0xa2, 0xb1, 0xfb, 0x7e, 0x7c, + 0x03, 0xe9, 0x9a, 0xc6, 0xde, 0x71, 0xc4, 0x8c, 0x7b, 0x21, 0xe7, 0x41, + 0x1d, 0x5a, 0xf5, 0x79, 0x37, 0xf1, 0xc8, 0x27, 0xd6, 0x52, 0xfd, 0x31, + 0x8c, 0x13, 0x33, 0x36, 0xac, 0xd2, 0x2f, 0x7e, 0xbf, 0x78, 0xcf, 0xd9, + 0x2b, 0x12, 0x7f, 0xf1, 0x51, 0x07, 0xe5, 0xf0, 0x2c, 0xaa, 0xe3, 0x1a, + 0xd4, 0x85, 0x7d, 0x56, 0xf8, 0x55, 0x1c, 0xa0, 0xbf, 0x8d, 0x17, 0x14, + 0x8c, 0xfa, 0x57, 0x31, 0x20, 0xb5, 0x89, 0xef, 0xb4, 0xe5, 0x02, 0xc4, + 0x29, 0x11, 0x94, 0xeb, 0xb1, 0xe8, 0x30, 0xe5, 0x6b, 0x63, 0x2e, 0x1f, + 0x65, 0x0e, 0xc9, 0x86, 0x02, 0xf6, 0xf9, 0xd5, 0x72, 0x3d, 0x62, 0xff, + 0xcf, 0x81, 0xf4, 0x41, 0x0d, 0x53, 0xb2, 0x4f, 0x7d, 0x08, 0xaf, 0x8e, + 0xcf, 0xe3, 0x58, 0x32, 0x8d, 0xbd, 0x35, 0x21, 0x8c, 0x99, 0x8b, 0xed, + 0xb9, 0x81, 0xf4, 0x5b, 0x5b, 0x26, 0x0e, 0xda, 0xb3, 0xc8, 0x8d, 0x49, + 0x57, 0xbd, 0x9c, 0xe3, 0x98, 0x66, 0xdf, 0x35, 0x6e, 0x0c, 0xe1, 0x80, + 0xf1, 0xc7, 0x30, 0x16, 0x49, 0xee, 0x1c, 0xc1, 0xf9, 0x29, 0xa9, 0x61, + 0xfd, 0xad, 0xcb, 0xc6, 0x44, 0x3f, 0x2e, 0x62, 0x5e, 0x1f, 0x9a, 0x6c, + 0x0c, 0x37, 0xd7, 0xba, 0x7c, 0xca, 0xc1, 0x72, 0x4d, 0x79, 0x39, 0x73, + 0x5d, 0x85, 0x20, 0xf5, 0x75, 0x21, 0xe9, 0x65, 0xce, 0x11, 0x7d, 0xca, + 0x19, 0x3f, 0x47, 0xce, 0x44, 0x5e, 0x61, 0xa4, 0xf9, 0xc6, 0xfd, 0x15, + 0xf9, 0xff, 0x83, 0x6b, 0xe7, 0x0e, 0x8b, 0xb3, 0xf1, 0x3f, 0xb7, 0x2e, + 0xdd, 0x24, 0x72, 0x27, 0x03, 0xcc, 0xe9, 0xd1, 0xa9, 0x6b, 0xfa, 0x15, + 0x9d, 0x9e, 0x93, 0x9a, 0x61, 0xeb, 0xdc, 0x99, 0xb7, 0x69, 0x03, 0xef, + 0xa8, 0x46, 0xd6, 0x13, 0xfa, 0x55, 0x0d, 0xfd, 0xad, 0x09, 0xbd, 0x4b, + 0x53, 0x9e, 0x9e, 0xab, 0xe6, 0x7a, 0xb4, 0xac, 0x7e, 0xd7, 0xc2, 0xcd, + 0x6d, 0x70, 0xeb, 0x72, 0x7d, 0xca, 0x4a, 0x87, 0xe4, 0x77, 0x33, 0x20, + 0xb5, 0xfc, 0x05, 0x73, 0xde, 0x5a, 0xbe, 0xd8, 0xc1, 0x86, 0x7f, 0x97, + 0x93, 0xbd, 0xaf, 0xac, 0xc5, 0x5e, 0xfb, 0xe2, 0xdb, 0xee, 0x83, 0xf8, + 0xdb, 0xfc, 0x21, 0xbc, 0x39, 0xee, 0x21, 0xce, 0x14, 0x59, 0xd6, 0xa3, + 0x7a, 0x75, 0x3c, 0xfd, 0x2e, 0xf3, 0xe2, 0xc5, 0xa9, 0x92, 0x5f, 0xcc, + 0xb5, 0xae, 0x98, 0x52, 0xa4, 0x55, 0x85, 0x32, 0xca, 0xf9, 0x53, 0xc3, + 0x8d, 0x68, 0x11, 0xdb, 0xba, 0xc9, 0xe7, 0xee, 0x9c, 0x83, 0x79, 0x63, + 0xf9, 0xc3, 0x01, 0x67, 0xfe, 0x15, 0x60, 0x1e, 0x1d, 0xc5, 0x91, 0x5c, + 0x63, 0xe2, 0x3d, 0x39, 0xa7, 0xc3, 0x5e, 0xec, 0x12, 0x46, 0x71, 0x22, + 0x57, 0xca, 0xa1, 0x11, 0x39, 0xdf, 0x9a, 0x88, 0xba, 0x9c, 0x1c, 0x19, + 0x75, 0x69, 0xd9, 0xa8, 0xeb, 0xe6, 0x80, 0x60, 0x83, 0xe1, 0x42, 0x2c, + 0x52, 0x0e, 0x37, 0xf6, 0x18, 0x8e, 0x7f, 0xd4, 0xcf, 0x78, 0x11, 0x5d, + 0x24, 0x75, 0x59, 0x6a, 0xb2, 0x87, 0x35, 0x79, 0x31, 0xd2, 0x8b, 0x3d, + 0x78, 0x4d, 0x17, 0x7d, 0xec, 0x2f, 0xe9, 0xc3, 0x38, 0x87, 0xfd, 0xd6, + 0x7c, 0xb7, 0xf8, 0x92, 0x17, 0x87, 0x9a, 0xa6, 0xad, 0xa9, 0xb0, 0xc8, + 0xee, 0xc6, 0x69, 0xe6, 0x57, 0xdc, 0x1c, 0x8b, 0x9c, 0x66, 0xcd, 0x1e, + 0xd1, 0x4b, 0x3e, 0x7e, 0x57, 0x91, 0x4f, 0x3d, 0x33, 0x8b, 0x3f, 0xe1, + 0xef, 0xf5, 0x91, 0xbd, 0xca, 0x59, 0x6f, 0xf9, 0xcc, 0xdb, 0x81, 0xd2, + 0xec, 0x54, 0x9e, 0x8d, 0xe6, 0x09, 0x3a, 0x2b, 0x84, 0x56, 0x80, 0xfe, + 0x59, 0x8e, 0xde, 0xb0, 0x9c, 0xf3, 0x10, 0xbd, 0xc8, 0x9e, 0x22, 0xa8, + 0x0f, 0x0b, 0x2f, 0x51, 0x1f, 0x87, 0xae, 0x9d, 0xa9, 0x72, 0xf2, 0x57, + 0x05, 0xaf, 0x6f, 0x4e, 0xbe, 0xb8, 0xce, 0x8f, 0xdf, 0x58, 0x97, 0xc2, + 0x11, 0xe6, 0x04, 0xb1, 0x69, 0xc6, 0xc6, 0x91, 0x6e, 0xe2, 0x93, 0xdd, + 0xf6, 0xf9, 0x11, 0xc6, 0x81, 0x79, 0x4d, 0x8e, 0xf9, 0x3e, 0xe2, 0xec, + 0xb9, 0x9c, 0x7d, 0x66, 0xaf, 0xf7, 0x0d, 0x15, 0x63, 0xae, 0xf9, 0x12, + 0x7a, 0x6b, 0x85, 0x5e, 0x28, 0xb8, 0x6d, 0x32, 0x41, 0x1d, 0xd4, 0x09, + 0x5d, 0xeb, 0x29, 0x76, 0x73, 0x87, 0xc6, 0x84, 0x3e, 0x30, 0x32, 0x16, + 0xeb, 0xff, 0x29, 0xb0, 0xae, 0x0a, 0xda, 0xe0, 0x6c, 0xf1, 0xff, 0x38, + 0x7e, 0xa1, 0x84, 0x96, 0xd0, 0xf1, 0xc0, 0x64, 0x8e, 0x3b, 0x3e, 0x57, + 0x41, 0xdd, 0x69, 0xdd, 0x3f, 0x50, 0x15, 0x78, 0xec, 0x89, 0x04, 0x79, + 0x5f, 0x14, 0xdc, 0x3c, 0xe9, 0x83, 0xff, 0x4c, 0x15, 0x6b, 0xae, 0x0f, + 0x97, 0x9b, 0x69, 0xd7, 0x27, 0x4a, 0xbc, 0xdb, 0x7b, 0xa3, 0x78, 0x74, + 0x22, 0x0a, 0x93, 0x3e, 0x3b, 0x67, 0xca, 0x3e, 0xb0, 0xcf, 0xce, 0x9f, + 0x17, 0xd7, 0xd4, 0xd9, 0x7b, 0x54, 0xcf, 0x16, 0xf4, 0xc8, 0x59, 0x55, + 0x85, 0x0f, 0x4e, 0xcc, 0xdf, 0x5c, 0x0e, 0xeb, 0x85, 0xa5, 0xa9, 0x78, + 0x66, 0x17, 0x7d, 0x7e, 0xc5, 0xf2, 0x30, 0x7b, 0x19, 0xf6, 0x94, 0x6b, + 0xa5, 0xff, 0x1d, 0x60, 0xff, 0x5b, 0xda, 0xd3, 0xd7, 0xfb, 0x1f, 0x52, + 0xd9, 0x4d, 0x41, 0x58, 0x1f, 0x95, 0xa7, 0xac, 0x8f, 0xbd, 0xa9, 0x38, + 0xdf, 0x97, 0x3d, 0x3d, 0xcb, 0x7a, 0xab, 0xd9, 0xb2, 0xf2, 0xcd, 0xb1, + 0x4c, 0xc8, 0x1d, 0xc2, 0x99, 0x06, 0xd9, 0x07, 0x74, 0xe1, 0x83, 0xb8, + 0x1e, 0xd9, 0x05, 0xd9, 0x7b, 0x67, 0x8e, 0x5f, 0x2c, 0xe7, 0x0e, 0xeb, + 0x82, 0x9d, 0xe6, 0x22, 0x3c, 0x33, 0xbb, 0x16, 0xbd, 0x5e, 0xd8, 0xe7, + 0x62, 0x2c, 0x03, 0x6f, 0x2c, 0x85, 0xd4, 0xed, 0x78, 0xcb, 0x43, 0x08, + 0x63, 0xb6, 0x70, 0x08, 0x0f, 0x9e, 0x90, 0xfd, 0xc5, 0x07, 0x5a, 0x7d, + 0x27, 0xac, 0xbf, 0x8b, 0xa4, 0xe6, 0x99, 0x17, 0x2d, 0xab, 0x62, 0x6d, + 0x63, 0x84, 0xe5, 0x88, 0x18, 0xa3, 0x57, 0xb0, 0x7b, 0xff, 0x07, 0xa8, + 0xc1, 0xd9, 0xe9, 0xf4, 0xcd, 0xec, 0x25, 0x3b, 0x9f, 0x54, 0x21, 0x3c, + 0x4f, 0x19, 0x9f, 0x2e, 0x08, 0x4e, 0x79, 0xb0, 0x75, 0xcb, 0x89, 0x25, + 0x78, 0x61, 0x36, 0x8c, 0xb3, 0xa6, 0x4e, 0x9c, 0x04, 0x55, 0x99, 0xb2, + 0xaa, 0xab, 0xc9, 0x6b, 0xa5, 0xdb, 0x8d, 0x4d, 0x49, 0xe9, 0x0f, 0xf5, + 0xfe, 0x80, 0xc2, 0x92, 0x72, 0xe8, 0x0b, 0xfb, 0x81, 0x01, 0x3f, 0xfb, + 0xd5, 0x27, 0x55, 0x3c, 0xf3, 0xbe, 0x3b, 0x8c, 0xe7, 0x99, 0x7f, 0x7e, + 0x50, 0x90, 0x33, 0x53, 0xcc, 0x31, 0xd3, 0x51, 0xda, 0xca, 0x07, 0x57, + 0x7d, 0x15, 0x0e, 0x33, 0x5e, 0x5e, 0x32, 0xca, 0x98, 0xa3, 0xe4, 0x0c, + 0x95, 0xe4, 0xf7, 0x9d, 0x72, 0x56, 0xc4, 0x7a, 0x56, 0x77, 0xfa, 0x7d, + 0x63, 0xe6, 0xc6, 0x73, 0xc8, 0x21, 0xe6, 0xf5, 0xc6, 0xee, 0x88, 0x7a, + 0xc5, 0x4a, 0x7f, 0x5d, 0x51, 0xce, 0xdd, 0x55, 0xa8, 0xb0, 0x65, 0xc5, + 0xf0, 0x44, 0xa9, 0xa6, 0x54, 0x4b, 0x2f, 0xd7, 0x9d, 0x2d, 0xfa, 0x60, + 0x25, 0x63, 0xfd, 0x28, 0x6b, 0x74, 0xf9, 0x09, 0xa9, 0x25, 0xec, 0x5f, + 0xd4, 0x7a, 0x62, 0x61, 0xc1, 0x0d, 0x3e, 0xdc, 0x1f, 0xd2, 0x5a, 0xe4, + 0x2c, 0xf6, 0xd3, 0x85, 0x0e, 0x8f, 0x9c, 0x89, 0x7a, 0xa6, 0x20, 0xb5, + 0x5c, 0x72, 0x41, 0x69, 0xbd, 0x08, 0x6a, 0xc7, 0xc4, 0x46, 0xdd, 0xad, + 0x1f, 0x8d, 0x05, 0xe4, 0xdc, 0xfc, 0x90, 0x8b, 0xbd, 0xb6, 0x6f, 0xcc, + 0xb2, 0xee, 0x6e, 0xd6, 0xfb, 0xd7, 0xbb, 0x65, 0x3f, 0x39, 0xd6, 0x7b, + 0x4e, 0x69, 0x2d, 0x47, 0xd4, 0x8d, 0x74, 0x9e, 0xab, 0x92, 0x18, 0xc9, + 0x52, 0xce, 0x47, 0x6d, 0x99, 0xf6, 0x53, 0xa6, 0xd2, 0x99, 0xa1, 0x2a, + 0x5c, 0x1e, 0x87, 0xce, 0xa8, 0xc5, 0x79, 0x83, 0xc9, 0x29, 0x14, 0x4f, + 0xb7, 0x43, 0xfc, 0x5f, 0xeb, 0x15, 0x0c, 0x55, 0xc9, 0x9c, 0x3c, 0x3d, + 0x2e, 0x35, 0x46, 0x09, 0x3e, 0xc9, 0x56, 0xa7, 0x06, 0x70, 0x65, 0x0d, + 0xf0, 0xca, 0x98, 0xb3, 0xdf, 0x5e, 0x3c, 0xe3, 0x6d, 0x9f, 0x65, 0x78, + 0xc8, 0x3e, 0xa3, 0x20, 0xf4, 0x0f, 0xe2, 0x4c, 0x4e, 0x30, 0xe5, 0x00, + 0x31, 0x65, 0x6c, 0x90, 0x78, 0xb3, 0xa5, 0xe0, 0x9c, 0xb7, 0x32, 0x3e, + 0xa2, 0xcf, 0x3f, 0x49, 0xac, 0x7a, 0x18, 0xce, 0x7e, 0x7b, 0x43, 0xf1, + 0x0c, 0x42, 0x2c, 0xdf, 0xa9, 0xb6, 0x16, 0xec, 0x33, 0x5a, 0x8c, 0xb1, + 0x76, 0xb5, 0x79, 0xb6, 0x43, 0x6d, 0x99, 0xed, 0x52, 0x3b, 0x0a, 0xd2, + 0xb3, 0x3e, 0xd0, 0x7a, 0xff, 0x89, 0xed, 0x6a, 0xeb, 0x74, 0x8f, 0x22, + 0xa6, 0x0d, 0xf9, 0x52, 0x19, 0xd5, 0x35, 0xeb, 0xcc, 0xcf, 0x3b, 0xd9, + 0x77, 0x6d, 0x35, 0x4b, 0xfd, 0xbc, 0xfc, 0x1f, 0x57, 0x58, 0xfe, 0x67, + 0xa2, 0x77, 0xa3, 0xb2, 0xac, 0x5b, 0x93, 0x7f, 0x2d, 0xf6, 0xb0, 0x9e, + 0x4e, 0xb2, 0x36, 0x9a, 0x55, 0xe8, 0x63, 0xdf, 0x31, 0x6c, 0x2c, 0x2b, + 0xee, 0x97, 0x89, 0x4c, 0x72, 0x4e, 0x42, 0xfc, 0x15, 0x59, 0xf6, 0x20, + 0xf8, 0x7b, 0xf2, 0xbf, 0xb7, 0x28, 0x57, 0x97, 0x9c, 0x23, 0xf0, 0x5e, + 0x3f, 0x47, 0x76, 0x6c, 0xec, 0xba, 0x5c, 0x1e, 0x5e, 0x1b, 0x25, 0x3e, + 0xdd, 0xab, 0xb4, 0xc1, 0xa7, 0x1c, 0xb9, 0x2e, 0x5e, 0x66, 0x0c, 0x0f, + 0xdb, 0x31, 0xec, 0xc8, 0xb5, 0xb2, 0x28, 0xd7, 0x8a, 0x7c, 0xa7, 0x7d, + 0x3e, 0x8b, 0x74, 0x5a, 0xe7, 0xc6, 0xe4, 0x1c, 0x99, 0xcc, 0x2e, 0x45, + 0x36, 0x91, 0xe3, 0x84, 0x55, 0xa1, 0x77, 0xa9, 0x6d, 0xf6, 0xb9, 0x32, + 0x39, 0xd3, 0x25, 0xfb, 0xfb, 0x25, 0xb9, 0xa4, 0x8e, 0x2f, 0x0a, 0x76, + 0x4c, 0xca, 0x39, 0x6b, 0xcb, 0xfa, 0x99, 0x51, 0x11, 0x14, 0x59, 0xce, + 0x1a, 0x22, 0x8b, 0x9c, 0x17, 0x29, 0xc9, 0xf3, 0xb5, 0xa2, 0x3c, 0x62, + 0xab, 0xeb, 0x76, 0x2a, 0xfd, 0xff, 0xdf, 0xdb, 0x39, 0xe7, 0x2c, 0x49, + 0x49, 0x9e, 0x60, 0x4a, 0xf8, 0xcf, 0xb7, 0x8e, 0x8e, 0x0f, 0xe0, 0x15, + 0xde, 0xff, 0x65, 0xae, 0x24, 0x97, 0x1b, 0x33, 0xd3, 0xa5, 0x33, 0x72, + 0x6c, 0x29, 0xcd, 0x98, 0x31, 0x42, 0x3f, 0x72, 0xe4, 0x93, 0x33, 0x72, + 0x8d, 0xf3, 0x97, 0xed, 0xb9, 0x57, 0x3c, 0xcd, 0x7e, 0x19, 0x67, 0x0b, + 0xbf, 0x6d, 0xbf, 0xa6, 0x7c, 0x05, 0x7b, 0x64, 0xa1, 0x3d, 0x47, 0xda, + 0x72, 0x96, 0x44, 0xe1, 0xa9, 0x69, 0x60, 0xda, 0xe4, 0xb2, 0xa9, 0x21, + 0x3c, 0x6e, 0x58, 0xd6, 0x93, 0xcd, 0xba, 0x9c, 0x01, 0xba, 0x50, 0x6b, + 0xcf, 0x85, 0x60, 0x54, 0xe9, 0xb2, 0x77, 0x27, 0xe7, 0x48, 0x7a, 0xa8, + 0x03, 0x91, 0x5d, 0x7c, 0xa0, 0x64, 0x7b, 0x39, 0xdf, 0x96, 0xa5, 0x7e, + 0x44, 0x37, 0xa5, 0x73, 0x6e, 0x32, 0x73, 0xb9, 0x51, 0x27, 0xb7, 0xd9, + 0x3a, 0x79, 0xda, 0x10, 0x7f, 0x65, 0xf6, 0xa1, 0xaf, 0xce, 0x10, 0x3f, + 0x8c, 0x18, 0x5e, 0x1b, 0xab, 0x1d, 0x26, 0x3e, 0x39, 0xc2, 0xd8, 0x79, + 0xd4, 0xbc, 0x88, 0x8b, 0xf9, 0x97, 0xf0, 0xca, 0xb5, 0xff, 0x85, 0x13, + 0x7f, 0xf1, 0xb5, 0x6c, 0xb1, 0xcf, 0x32, 0xfd, 0x75, 0xcb, 0xb2, 0xb8, + 0xe4, 0xa1, 0x93, 0x4d, 0x72, 0xb6, 0xa9, 0x3c, 0xf5, 0xde, 0x3a, 0xd9, + 0xdf, 0x2a, 0x4b, 0x0d, 0x7e, 0xf5, 0x82, 0x2e, 0xba, 0xf9, 0x64, 0xf5, + 0x19, 0x5d, 0xe4, 0xd2, 0x8d, 0x51, 0xfb, 0x7f, 0x33, 0x43, 0x6b, 0x77, + 0xeb, 0x12, 0x3b, 0xef, 0x34, 0xb7, 0xd9, 0x39, 0x61, 0x30, 0x75, 0xab, + 0xad, 0x83, 0x83, 0xa9, 0x65, 0x8e, 0x2e, 0x52, 0x09, 0xfb, 0xfb, 0xe1, + 0x94, 0xa3, 0x9b, 0x5c, 0xaa, 0xde, 0xfe, 0x1e, 0x4d, 0x39, 0x67, 0xa2, + 0xb3, 0x29, 0xdd, 0xfe, 0x1e, 0x4f, 0xc5, 0xec, 0xef, 0x23, 0xa9, 0x5b, + 0xae, 0xf3, 0xc5, 0x9f, 0xff, 0x07, 0xd8, 0xc4, 0xd3, 0xb4, 0xb4, 0x3a, + 0x00, 0x00, 0x00 }; static const u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 }; static const u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 }; static struct fw_info bnx2_txp_fw_06 = { - /* Firmware version: 4.0.5 */ + /* Firmware version: 4.4.2 */ .ver_major = 0x4, - .ver_minor = 0x0, - .ver_fix = 0x5, + .ver_minor = 0x4, + .ver_fix = 0x2, .start_addr = 0x08000098, .text_addr = 0x08000000, - .text_len = 0x3ad8, + .text_len = 0x3ab0, .text_index = 0x0, .gz_text = bnx2_TXP_b06FwText, .gz_text_len = sizeof(bnx2_TXP_b06FwText), @@ -4582,11 +4535,11 @@ static struct fw_info bnx2_txp_fw_06 = { .data_index = 0x0, .data = bnx2_TXP_b06FwData, - .sbss_addr = 0x08003b00, + .sbss_addr = 0x08003ae0, .sbss_len = 0x68, .sbss_index = 0x0, - .bss_addr = 0x08003b68, + .bss_addr = 0x08003b48, .bss_len = 0x14c, .bss_index = 0x0, @@ -4611,3 +4564,4 @@ static const struct cpu_reg cpu_reg_txp = { .spad_base = BNX2_TXP_SCRATCH, .mips_view_base = 0x8000000, }; + diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index a8eb3c4a47c..fce745148ff 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -59,8 +59,8 @@ #include "bnx2x.h" #include "bnx2x_init.h" -#define DRV_MODULE_VERSION "1.45.21" -#define DRV_MODULE_RELDATE "2008/09/03" +#define DRV_MODULE_VERSION "1.45.22" +#define DRV_MODULE_RELDATE "2008/09/09" #define BNX2X_BC_VER 0x040200 /* Time in jiffies before concluding the transmitter is hung */ @@ -649,15 +649,16 @@ static void bnx2x_int_disable(struct bnx2x *bp) BNX2X_ERR("BUG! proper val not read from IGU!\n"); } -static void bnx2x_int_disable_sync(struct bnx2x *bp) +static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) { int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; int i; /* disable interrupt handling */ atomic_inc(&bp->intr_sem); - /* prevent the HW from sending interrupts */ - bnx2x_int_disable(bp); + if (disable_hw) + /* prevent the HW from sending interrupts */ + bnx2x_int_disable(bp); /* make sure all ISRs are done */ if (msix) { @@ -6086,9 +6087,9 @@ static void bnx2x_netif_start(struct bnx2x *bp) } } -static void bnx2x_netif_stop(struct bnx2x *bp) +static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw) { - bnx2x_int_disable_sync(bp); + bnx2x_int_disable_sync(bp, disable_hw); if (netif_running(bp->dev)) { bnx2x_napi_disable(bp); netif_tx_disable(bp->dev); @@ -6475,7 +6476,7 @@ load_rings_free: for_each_queue(bp, i) bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); load_int_disable: - bnx2x_int_disable_sync(bp); + bnx2x_int_disable_sync(bp, 1); /* Release IRQs */ bnx2x_free_irq(bp); load_error: @@ -6650,7 +6651,7 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) bp->rx_mode = BNX2X_RX_MODE_NONE; bnx2x_set_storm_rx_mode(bp); - bnx2x_netif_stop(bp); + bnx2x_netif_stop(bp, 1); if (!netif_running(bp->dev)) bnx2x_napi_disable(bp); del_timer_sync(&bp->timer); @@ -8791,7 +8792,7 @@ static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up) if (!netif_running(bp->dev)) return BNX2X_LOOPBACK_FAILED; - bnx2x_netif_stop(bp); + bnx2x_netif_stop(bp, 1); if (bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up)) { DP(NETIF_MSG_PROBE, "MAC loopback failed\n"); @@ -10346,6 +10347,74 @@ static int bnx2x_resume(struct pci_dev *pdev) return rc; } +static int bnx2x_eeh_nic_unload(struct bnx2x *bp) +{ + int i; + + bp->state = BNX2X_STATE_ERROR; + + bp->rx_mode = BNX2X_RX_MODE_NONE; + + bnx2x_netif_stop(bp, 0); + + del_timer_sync(&bp->timer); + bp->stats_state = STATS_STATE_DISABLED; + DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n"); + + /* Release IRQs */ + bnx2x_free_irq(bp); + + if (CHIP_IS_E1(bp)) { + struct mac_configuration_cmd *config = + bnx2x_sp(bp, mcast_config); + + for (i = 0; i < config->hdr.length_6b; i++) + CAM_INVALIDATE(config->config_table[i]); + } + + /* Free SKBs, SGEs, TPA pool and driver internals */ + bnx2x_free_skbs(bp); + for_each_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); + bnx2x_free_mem(bp); + + bp->state = BNX2X_STATE_CLOSED; + + netif_carrier_off(bp->dev); + + return 0; +} + +static void bnx2x_eeh_recover(struct bnx2x *bp) +{ + u32 val; + + mutex_init(&bp->port.phy_mutex); + + bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + bp->link_params.shmem_base = bp->common.shmem_base; + BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base); + + if (!bp->common.shmem_base || + (bp->common.shmem_base < 0xA0000) || + (bp->common.shmem_base >= 0xC0000)) { + BNX2X_DEV_INFO("MCP not active\n"); + bp->flags |= NO_MCP_FLAG; + return; + } + + val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]); + if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + BNX2X_ERR("BAD MCP validity signature\n"); + + if (!BP_NOMCP(bp)) { + bp->fw_seq = (SHMEM_RD(bp, func_mb[BP_FUNC(bp)].drv_mb_header) + & DRV_MSG_SEQ_NUMBER_MASK); + BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); + } +} + /** * bnx2x_io_error_detected - called when PCI error is detected * @pdev: Pointer to PCI device @@ -10365,7 +10434,7 @@ static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev, netif_device_detach(dev); if (netif_running(dev)) - bnx2x_nic_unload(bp, UNLOAD_CLOSE); + bnx2x_eeh_nic_unload(bp); pci_disable_device(pdev); @@ -10420,8 +10489,10 @@ static void bnx2x_io_resume(struct pci_dev *pdev) rtnl_lock(); + bnx2x_eeh_recover(bp); + if (netif_running(dev)) - bnx2x_nic_load(bp, LOAD_OPEN); + bnx2x_nic_load(bp, LOAD_NORMAL); netif_device_attach(dev); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index b211486a0ca..ade5f3f6693 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -38,6 +38,7 @@ #include <linux/in.h> #include <net/ipx.h> #include <net/arp.h> +#include <net/ipv6.h> #include <asm/byteorder.h> #include "bonding.h" #include "bond_alb.h" @@ -81,6 +82,7 @@ #define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; +static const u8 mac_v6_allmcast[ETH_ALEN] = {0x33,0x33,0x00,0x00,0x00,0x01}; static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; #pragma pack(1) @@ -710,7 +712,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) struct arp_pkt *arp = arp_pkt(skb); struct slave *tx_slave = NULL; - if (arp->op_code == __constant_htons(ARPOP_REPLY)) { + if (arp->op_code == htons(ARPOP_REPLY)) { /* the arp must be sent on the selected * rx channel */ @@ -719,7 +721,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN); } dprintk("Server sent ARP Reply packet\n"); - } else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) { + } else if (arp->op_code == htons(ARPOP_REQUEST)) { /* Create an entry in the rx_hashtbl for this client as a * place holder. * When the arp reply is received the entry will be updated @@ -1290,6 +1292,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) u32 hash_index = 0; const u8 *hash_start = NULL; int res = 1; + struct ipv6hdr *ip6hdr; skb_reset_mac_header(skb); eth_data = eth_hdr(skb); @@ -1319,11 +1322,32 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) } break; case ETH_P_IPV6: + /* IPv6 doesn't really use broadcast mac address, but leave + * that here just in case. + */ if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { do_tx_balance = 0; break; } + /* IPv6 uses all-nodes multicast as an equivalent to + * broadcasts in IPv4. + */ + if (memcmp(eth_data->h_dest, mac_v6_allmcast, ETH_ALEN) == 0) { + do_tx_balance = 0; + break; + } + + /* Additianally, DAD probes should not be tx-balanced as that + * will lead to false positives for duplicate addresses and + * prevent address configuration from working. + */ + ip6hdr = ipv6_hdr(skb); + if (ipv6_addr_any(&ip6hdr->saddr)) { + do_tx_balance = 0; + break; + } + hash_start = (char *)&(ipv6_hdr(skb)->daddr); hash_size = sizeof(ipv6_hdr(skb)->daddr); break; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index c792138511e..8e2be24f3fe 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3702,7 +3702,7 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb, struct ethhdr *data = (struct ethhdr *)skb->data; struct iphdr *iph = ip_hdr(skb); - if (skb->protocol == __constant_htons(ETH_P_IP)) { + if (skb->protocol == htons(ETH_P_IP)) { return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^ (data->h_dest[5] ^ bond_dev->dev_addr[5])) % count; } @@ -3723,8 +3723,8 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); int layer4_xor = 0; - if (skb->protocol == __constant_htons(ETH_P_IP)) { - if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) && + if (skb->protocol == htons(ETH_P_IP)) { + if (!(iph->frag_off & htons(IP_MF|IP_OFFSET)) && (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP)) { layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1))); @@ -4493,6 +4493,12 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev, static const struct ethtool_ops bond_ethtool_ops = { .get_drvinfo = bond_ethtool_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, + .get_tso = ethtool_op_get_tso, + .get_ufo = ethtool_op_get_ufo, + .get_flags = ethtool_op_get_flags, }; /* diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index fb730ec0396..ffb668dd6d3 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -32,7 +32,7 @@ #ifdef BONDING_DEBUG #define dprintk(fmt, args...) \ printk(KERN_DEBUG \ - DRV_NAME ": %s() %d: " fmt, __FUNCTION__, __LINE__ , ## args ) + DRV_NAME ": %s() %d: " fmt, __func__, __LINE__ , ## args ) #else #define dprintk(fmt, args...) #endif /* BONDING_DEBUG */ @@ -333,5 +333,13 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active); void bond_register_arp(struct bonding *); void bond_unregister_arp(struct bonding *); +/* exported from bond_main.c */ +extern struct list_head bond_dev_list; +extern struct bond_parm_tbl bond_lacp_tbl[]; +extern struct bond_parm_tbl bond_mode_tbl[]; +extern struct bond_parm_tbl xmit_hashtype_tbl[]; +extern struct bond_parm_tbl arp_validate_tbl[]; +extern struct bond_parm_tbl fail_over_mac_tbl[]; + #endif /* _LINUX_BONDING_H */ diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index f1936d51b45..86909cfb14d 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -74,6 +74,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/vmalloc.h> #include <linux/ioport.h> #include <linux/pci.h> #include <linux/mm.h> @@ -91,6 +92,7 @@ #include <linux/ip.h> #include <linux/tcp.h> #include <linux/mutex.h> +#include <linux/firmware.h> #include <net/checksum.h> @@ -197,6 +199,7 @@ static int link_mode; MODULE_AUTHOR("Adrian Sun (asun@darksunrising.com)"); MODULE_DESCRIPTION("Sun Cassini(+) ethernet driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("sun/cassini.bin"); module_param(cassini_debug, int, 0); MODULE_PARM_DESC(cassini_debug, "Cassini bitmapped debugging message enable value"); module_param(link_mode, int, 0); @@ -812,9 +815,44 @@ static int cas_reset_mii_phy(struct cas *cp) return (limit <= 0); } +static int cas_saturn_firmware_init(struct cas *cp) +{ + const struct firmware *fw; + const char fw_name[] = "sun/cassini.bin"; + int err; + + if (PHY_NS_DP83065 != cp->phy_id) + return 0; + + err = request_firmware(&fw, fw_name, &cp->pdev->dev); + if (err) { + printk(KERN_ERR "cassini: Failed to load firmware \"%s\"\n", + fw_name); + return err; + } + if (fw->size < 2) { + printk(KERN_ERR "cassini: bogus length %zu in \"%s\"\n", + fw->size, fw_name); + err = -EINVAL; + goto out; + } + cp->fw_load_addr= fw->data[1] << 8 | fw->data[0]; + cp->fw_size = fw->size - 2; + cp->fw_data = vmalloc(cp->fw_size); + if (!cp->fw_data) { + err = -ENOMEM; + printk(KERN_ERR "cassini: \"%s\" Failed %d\n", fw_name, err); + goto out; + } + memcpy(cp->fw_data, &fw->data[2], cp->fw_size); +out: + release_firmware(fw); + return err; +} + static void cas_saturn_firmware_load(struct cas *cp) { - cas_saturn_patch_t *patch = cas_saturn_patch; + int i; cas_phy_powerdown(cp); @@ -833,11 +871,9 @@ static void cas_saturn_firmware_load(struct cas *cp) /* download new firmware */ cas_phy_write(cp, DP83065_MII_MEM, 0x1); - cas_phy_write(cp, DP83065_MII_REGE, patch->addr); - while (patch->addr) { - cas_phy_write(cp, DP83065_MII_REGD, patch->val); - patch++; - } + cas_phy_write(cp, DP83065_MII_REGE, cp->fw_load_addr); + for (i = 0; i < cp->fw_size; i++) + cas_phy_write(cp, DP83065_MII_REGD, cp->fw_data[i]); /* enable firmware */ cas_phy_write(cp, DP83065_MII_REGE, 0x8ff8); @@ -2182,7 +2218,7 @@ static inline void cas_rx_flow_pkt(struct cas *cp, const u64 *words, * do any additional locking here. stick the buffer * at the end. */ - __skb_insert(skb, flow->prev, (struct sk_buff *) flow, flow); + __skb_queue_tail(flow, skb); if (words[0] & RX_COMP1_RELEASE_FLOW) { while ((skb = __skb_dequeue(flow))) { cas_skb_release(skb); @@ -5108,6 +5144,9 @@ static int __devinit cas_init_one(struct pci_dev *pdev, cas_reset(cp, 0); if (cas_check_invariants(cp)) goto err_out_iounmap; + if (cp->cas_flags & CAS_FLAG_SATURN) + if (cas_saturn_firmware_init(cp)) + goto err_out_iounmap; cp->init_block = (struct cas_init_block *) pci_alloc_consistent(pdev, sizeof(struct cas_init_block), @@ -5217,6 +5256,9 @@ static void __devexit cas_remove_one(struct pci_dev *pdev) cp = netdev_priv(dev); unregister_netdev(dev); + if (cp->fw_data) + vfree(cp->fw_data); + mutex_lock(&cp->pm_mutex); flush_scheduled_work(); if (cp->hw_running) diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h index 552af89ca1c..fd17a002b45 100644 --- a/drivers/net/cassini.h +++ b/drivers/net/cassini.h @@ -2514,1523 +2514,6 @@ static cas_hp_inst_t cas_prog_null[] = { {NULL} }; #define CAS_HP_FIRMWARE cas_prog_null #endif -/* firmware patch for NS_DP83065 */ -typedef struct cas_saturn_patch { - u16 addr; - u16 val; -} cas_saturn_patch_t; - -#if 1 -cas_saturn_patch_t cas_saturn_patch[] = { -{0x8200, 0x007e}, {0x8201, 0x0082}, {0x8202, 0x0009}, -{0x8203, 0x0000}, {0x8204, 0x0000}, {0x8205, 0x0000}, -{0x8206, 0x0000}, {0x8207, 0x0000}, {0x8208, 0x0000}, -{0x8209, 0x008e}, {0x820a, 0x008e}, {0x820b, 0x00ff}, -{0x820c, 0x00ce}, {0x820d, 0x0082}, {0x820e, 0x0025}, -{0x820f, 0x00ff}, {0x8210, 0x0001}, {0x8211, 0x000f}, -{0x8212, 0x00ce}, {0x8213, 0x0084}, {0x8214, 0x0026}, -{0x8215, 0x00ff}, {0x8216, 0x0001}, {0x8217, 0x0011}, -{0x8218, 0x00ce}, {0x8219, 0x0085}, {0x821a, 0x003d}, -{0x821b, 0x00df}, {0x821c, 0x00e5}, {0x821d, 0x0086}, -{0x821e, 0x0039}, {0x821f, 0x00b7}, {0x8220, 0x008f}, -{0x8221, 0x00f8}, {0x8222, 0x007e}, {0x8223, 0x00c3}, -{0x8224, 0x00c2}, {0x8225, 0x0096}, {0x8226, 0x0047}, -{0x8227, 0x0084}, {0x8228, 0x00f3}, {0x8229, 0x008a}, -{0x822a, 0x0000}, {0x822b, 0x0097}, {0x822c, 0x0047}, -{0x822d, 0x00ce}, {0x822e, 0x0082}, {0x822f, 0x0033}, -{0x8230, 0x00ff}, {0x8231, 0x0001}, {0x8232, 0x000f}, -{0x8233, 0x0096}, {0x8234, 0x0046}, {0x8235, 0x0084}, -{0x8236, 0x000c}, {0x8237, 0x0081}, {0x8238, 0x0004}, -{0x8239, 0x0027}, {0x823a, 0x000b}, {0x823b, 0x0096}, -{0x823c, 0x0046}, {0x823d, 0x0084}, {0x823e, 0x000c}, -{0x823f, 0x0081}, {0x8240, 0x0008}, {0x8241, 0x0027}, -{0x8242, 0x0057}, {0x8243, 0x007e}, {0x8244, 0x0084}, -{0x8245, 0x0025}, {0x8246, 0x0096}, {0x8247, 0x0047}, -{0x8248, 0x0084}, {0x8249, 0x00f3}, {0x824a, 0x008a}, -{0x824b, 0x0004}, {0x824c, 0x0097}, {0x824d, 0x0047}, -{0x824e, 0x00ce}, {0x824f, 0x0082}, {0x8250, 0x0054}, -{0x8251, 0x00ff}, {0x8252, 0x0001}, {0x8253, 0x000f}, -{0x8254, 0x0096}, {0x8255, 0x0046}, {0x8256, 0x0084}, -{0x8257, 0x000c}, {0x8258, 0x0081}, {0x8259, 0x0004}, -{0x825a, 0x0026}, {0x825b, 0x0038}, {0x825c, 0x00b6}, -{0x825d, 0x0012}, {0x825e, 0x0020}, {0x825f, 0x0084}, -{0x8260, 0x0020}, {0x8261, 0x0026}, {0x8262, 0x0003}, -{0x8263, 0x007e}, {0x8264, 0x0084}, {0x8265, 0x0025}, -{0x8266, 0x0096}, {0x8267, 0x007b}, {0x8268, 0x00d6}, -{0x8269, 0x007c}, {0x826a, 0x00fe}, {0x826b, 0x008f}, -{0x826c, 0x0056}, {0x826d, 0x00bd}, {0x826e, 0x00f7}, -{0x826f, 0x00b6}, {0x8270, 0x00fe}, {0x8271, 0x008f}, -{0x8272, 0x004e}, {0x8273, 0x00bd}, {0x8274, 0x00ec}, -{0x8275, 0x008e}, {0x8276, 0x00bd}, {0x8277, 0x00fa}, -{0x8278, 0x00f7}, {0x8279, 0x00bd}, {0x827a, 0x00f7}, -{0x827b, 0x0028}, {0x827c, 0x00ce}, {0x827d, 0x0082}, -{0x827e, 0x0082}, {0x827f, 0x00ff}, {0x8280, 0x0001}, -{0x8281, 0x000f}, {0x8282, 0x0096}, {0x8283, 0x0046}, -{0x8284, 0x0084}, {0x8285, 0x000c}, {0x8286, 0x0081}, -{0x8287, 0x0004}, {0x8288, 0x0026}, {0x8289, 0x000a}, -{0x828a, 0x00b6}, {0x828b, 0x0012}, {0x828c, 0x0020}, -{0x828d, 0x0084}, {0x828e, 0x0020}, {0x828f, 0x0027}, -{0x8290, 0x00b5}, {0x8291, 0x007e}, {0x8292, 0x0084}, -{0x8293, 0x0025}, {0x8294, 0x00bd}, {0x8295, 0x00f7}, -{0x8296, 0x001f}, {0x8297, 0x007e}, {0x8298, 0x0084}, -{0x8299, 0x001f}, {0x829a, 0x0096}, {0x829b, 0x0047}, -{0x829c, 0x0084}, {0x829d, 0x00f3}, {0x829e, 0x008a}, -{0x829f, 0x0008}, {0x82a0, 0x0097}, {0x82a1, 0x0047}, -{0x82a2, 0x00de}, {0x82a3, 0x00e1}, {0x82a4, 0x00ad}, -{0x82a5, 0x0000}, {0x82a6, 0x00ce}, {0x82a7, 0x0082}, -{0x82a8, 0x00af}, {0x82a9, 0x00ff}, {0x82aa, 0x0001}, -{0x82ab, 0x000f}, {0x82ac, 0x007e}, {0x82ad, 0x0084}, -{0x82ae, 0x0025}, {0x82af, 0x0096}, {0x82b0, 0x0041}, -{0x82b1, 0x0085}, {0x82b2, 0x0010}, {0x82b3, 0x0026}, -{0x82b4, 0x0006}, {0x82b5, 0x0096}, {0x82b6, 0x0023}, -{0x82b7, 0x0085}, {0x82b8, 0x0040}, {0x82b9, 0x0027}, -{0x82ba, 0x0006}, {0x82bb, 0x00bd}, {0x82bc, 0x00ed}, -{0x82bd, 0x0000}, {0x82be, 0x007e}, {0x82bf, 0x0083}, -{0x82c0, 0x00a2}, {0x82c1, 0x00de}, {0x82c2, 0x0042}, -{0x82c3, 0x00bd}, {0x82c4, 0x00eb}, {0x82c5, 0x008e}, -{0x82c6, 0x0096}, {0x82c7, 0x0024}, {0x82c8, 0x0084}, -{0x82c9, 0x0008}, {0x82ca, 0x0027}, {0x82cb, 0x0003}, -{0x82cc, 0x007e}, {0x82cd, 0x0083}, {0x82ce, 0x00df}, -{0x82cf, 0x0096}, {0x82d0, 0x007b}, {0x82d1, 0x00d6}, -{0x82d2, 0x007c}, {0x82d3, 0x00fe}, {0x82d4, 0x008f}, -{0x82d5, 0x0056}, {0x82d6, 0x00bd}, {0x82d7, 0x00f7}, -{0x82d8, 0x00b6}, {0x82d9, 0x00fe}, {0x82da, 0x008f}, -{0x82db, 0x0050}, {0x82dc, 0x00bd}, {0x82dd, 0x00ec}, -{0x82de, 0x008e}, {0x82df, 0x00bd}, {0x82e0, 0x00fa}, -{0x82e1, 0x00f7}, {0x82e2, 0x0086}, {0x82e3, 0x0011}, -{0x82e4, 0x00c6}, {0x82e5, 0x0049}, {0x82e6, 0x00bd}, -{0x82e7, 0x00e4}, {0x82e8, 0x0012}, {0x82e9, 0x00ce}, -{0x82ea, 0x0082}, {0x82eb, 0x00ef}, {0x82ec, 0x00ff}, -{0x82ed, 0x0001}, {0x82ee, 0x000f}, {0x82ef, 0x0096}, -{0x82f0, 0x0046}, {0x82f1, 0x0084}, {0x82f2, 0x000c}, -{0x82f3, 0x0081}, {0x82f4, 0x0000}, {0x82f5, 0x0027}, -{0x82f6, 0x0017}, {0x82f7, 0x00c6}, {0x82f8, 0x0049}, -{0x82f9, 0x00bd}, {0x82fa, 0x00e4}, {0x82fb, 0x0091}, -{0x82fc, 0x0024}, {0x82fd, 0x000d}, {0x82fe, 0x00b6}, -{0x82ff, 0x0012}, {0x8300, 0x0020}, {0x8301, 0x0085}, -{0x8302, 0x0020}, {0x8303, 0x0026}, {0x8304, 0x000c}, -{0x8305, 0x00ce}, {0x8306, 0x0082}, {0x8307, 0x00c1}, -{0x8308, 0x00ff}, {0x8309, 0x0001}, {0x830a, 0x000f}, -{0x830b, 0x007e}, {0x830c, 0x0084}, {0x830d, 0x0025}, -{0x830e, 0x007e}, {0x830f, 0x0084}, {0x8310, 0x0016}, -{0x8311, 0x00fe}, {0x8312, 0x008f}, {0x8313, 0x0052}, -{0x8314, 0x00bd}, {0x8315, 0x00ec}, {0x8316, 0x008e}, -{0x8317, 0x00bd}, {0x8318, 0x00fa}, {0x8319, 0x00f7}, -{0x831a, 0x0086}, {0x831b, 0x006a}, {0x831c, 0x00c6}, -{0x831d, 0x0049}, {0x831e, 0x00bd}, {0x831f, 0x00e4}, -{0x8320, 0x0012}, {0x8321, 0x00ce}, {0x8322, 0x0083}, -{0x8323, 0x0027}, {0x8324, 0x00ff}, {0x8325, 0x0001}, -{0x8326, 0x000f}, {0x8327, 0x0096}, {0x8328, 0x0046}, -{0x8329, 0x0084}, {0x832a, 0x000c}, {0x832b, 0x0081}, -{0x832c, 0x0000}, {0x832d, 0x0027}, {0x832e, 0x000a}, -{0x832f, 0x00c6}, {0x8330, 0x0049}, {0x8331, 0x00bd}, -{0x8332, 0x00e4}, {0x8333, 0x0091}, {0x8334, 0x0025}, -{0x8335, 0x0006}, {0x8336, 0x007e}, {0x8337, 0x0084}, -{0x8338, 0x0025}, {0x8339, 0x007e}, {0x833a, 0x0084}, -{0x833b, 0x0016}, {0x833c, 0x00b6}, {0x833d, 0x0018}, -{0x833e, 0x0070}, {0x833f, 0x00bb}, {0x8340, 0x0019}, -{0x8341, 0x0070}, {0x8342, 0x002a}, {0x8343, 0x0004}, -{0x8344, 0x0081}, {0x8345, 0x00af}, {0x8346, 0x002e}, -{0x8347, 0x0019}, {0x8348, 0x0096}, {0x8349, 0x007b}, -{0x834a, 0x00f6}, {0x834b, 0x0020}, {0x834c, 0x0007}, -{0x834d, 0x00fa}, {0x834e, 0x0020}, {0x834f, 0x0027}, -{0x8350, 0x00c4}, {0x8351, 0x0038}, {0x8352, 0x0081}, -{0x8353, 0x0038}, {0x8354, 0x0027}, {0x8355, 0x000b}, -{0x8356, 0x00f6}, {0x8357, 0x0020}, {0x8358, 0x0007}, -{0x8359, 0x00fa}, {0x835a, 0x0020}, {0x835b, 0x0027}, -{0x835c, 0x00cb}, {0x835d, 0x0008}, {0x835e, 0x007e}, -{0x835f, 0x0082}, {0x8360, 0x00d3}, {0x8361, 0x00bd}, -{0x8362, 0x00f7}, {0x8363, 0x0066}, {0x8364, 0x0086}, -{0x8365, 0x0074}, {0x8366, 0x00c6}, {0x8367, 0x0049}, -{0x8368, 0x00bd}, {0x8369, 0x00e4}, {0x836a, 0x0012}, -{0x836b, 0x00ce}, {0x836c, 0x0083}, {0x836d, 0x0071}, -{0x836e, 0x00ff}, {0x836f, 0x0001}, {0x8370, 0x000f}, -{0x8371, 0x0096}, {0x8372, 0x0046}, {0x8373, 0x0084}, -{0x8374, 0x000c}, {0x8375, 0x0081}, {0x8376, 0x0008}, -{0x8377, 0x0026}, {0x8378, 0x000a}, {0x8379, 0x00c6}, -{0x837a, 0x0049}, {0x837b, 0x00bd}, {0x837c, 0x00e4}, -{0x837d, 0x0091}, {0x837e, 0x0025}, {0x837f, 0x0006}, -{0x8380, 0x007e}, {0x8381, 0x0084}, {0x8382, 0x0025}, -{0x8383, 0x007e}, {0x8384, 0x0084}, {0x8385, 0x0016}, -{0x8386, 0x00bd}, {0x8387, 0x00f7}, {0x8388, 0x003e}, -{0x8389, 0x0026}, {0x838a, 0x000e}, {0x838b, 0x00bd}, -{0x838c, 0x00e5}, {0x838d, 0x0009}, {0x838e, 0x0026}, -{0x838f, 0x0006}, {0x8390, 0x00ce}, {0x8391, 0x0082}, -{0x8392, 0x00c1}, {0x8393, 0x00ff}, {0x8394, 0x0001}, -{0x8395, 0x000f}, {0x8396, 0x007e}, {0x8397, 0x0084}, -{0x8398, 0x0025}, {0x8399, 0x00fe}, {0x839a, 0x008f}, -{0x839b, 0x0054}, {0x839c, 0x00bd}, {0x839d, 0x00ec}, -{0x839e, 0x008e}, {0x839f, 0x00bd}, {0x83a0, 0x00fa}, -{0x83a1, 0x00f7}, {0x83a2, 0x00bd}, {0x83a3, 0x00f7}, -{0x83a4, 0x0033}, {0x83a5, 0x0086}, {0x83a6, 0x000f}, -{0x83a7, 0x00c6}, {0x83a8, 0x0051}, {0x83a9, 0x00bd}, -{0x83aa, 0x00e4}, {0x83ab, 0x0012}, {0x83ac, 0x00ce}, -{0x83ad, 0x0083}, {0x83ae, 0x00b2}, {0x83af, 0x00ff}, -{0x83b0, 0x0001}, {0x83b1, 0x000f}, {0x83b2, 0x0096}, -{0x83b3, 0x0046}, {0x83b4, 0x0084}, {0x83b5, 0x000c}, -{0x83b6, 0x0081}, {0x83b7, 0x0008}, {0x83b8, 0x0026}, -{0x83b9, 0x005c}, {0x83ba, 0x00b6}, {0x83bb, 0x0012}, -{0x83bc, 0x0020}, {0x83bd, 0x0084}, {0x83be, 0x003f}, -{0x83bf, 0x0081}, {0x83c0, 0x003a}, {0x83c1, 0x0027}, -{0x83c2, 0x001c}, {0x83c3, 0x0096}, {0x83c4, 0x0023}, -{0x83c5, 0x0085}, {0x83c6, 0x0040}, {0x83c7, 0x0027}, -{0x83c8, 0x0003}, {0x83c9, 0x007e}, {0x83ca, 0x0084}, -{0x83cb, 0x0025}, {0x83cc, 0x00c6}, {0x83cd, 0x0051}, -{0x83ce, 0x00bd}, {0x83cf, 0x00e4}, {0x83d0, 0x0091}, -{0x83d1, 0x0025}, {0x83d2, 0x0003}, {0x83d3, 0x007e}, -{0x83d4, 0x0084}, {0x83d5, 0x0025}, {0x83d6, 0x00ce}, -{0x83d7, 0x0082}, {0x83d8, 0x00c1}, {0x83d9, 0x00ff}, -{0x83da, 0x0001}, {0x83db, 0x000f}, {0x83dc, 0x007e}, -{0x83dd, 0x0084}, {0x83de, 0x0025}, {0x83df, 0x00bd}, -{0x83e0, 0x00f8}, {0x83e1, 0x0037}, {0x83e2, 0x007c}, -{0x83e3, 0x0000}, {0x83e4, 0x007a}, {0x83e5, 0x00ce}, -{0x83e6, 0x0083}, {0x83e7, 0x00ee}, {0x83e8, 0x00ff}, -{0x83e9, 0x0001}, {0x83ea, 0x000f}, {0x83eb, 0x007e}, -{0x83ec, 0x0084}, {0x83ed, 0x0025}, {0x83ee, 0x0096}, -{0x83ef, 0x0046}, {0x83f0, 0x0084}, {0x83f1, 0x000c}, -{0x83f2, 0x0081}, {0x83f3, 0x0008}, {0x83f4, 0x0026}, -{0x83f5, 0x0020}, {0x83f6, 0x0096}, {0x83f7, 0x0024}, -{0x83f8, 0x0084}, {0x83f9, 0x0008}, {0x83fa, 0x0026}, -{0x83fb, 0x0029}, {0x83fc, 0x00b6}, {0x83fd, 0x0018}, -{0x83fe, 0x0082}, {0x83ff, 0x00bb}, {0x8400, 0x0019}, -{0x8401, 0x0082}, {0x8402, 0x00b1}, {0x8403, 0x0001}, -{0x8404, 0x003b}, {0x8405, 0x0022}, {0x8406, 0x0009}, -{0x8407, 0x00b6}, {0x8408, 0x0012}, {0x8409, 0x0020}, -{0x840a, 0x0084}, {0x840b, 0x0037}, {0x840c, 0x0081}, -{0x840d, 0x0032}, {0x840e, 0x0027}, {0x840f, 0x0015}, -{0x8410, 0x00bd}, {0x8411, 0x00f8}, {0x8412, 0x0044}, -{0x8413, 0x007e}, {0x8414, 0x0082}, {0x8415, 0x00c1}, -{0x8416, 0x00bd}, {0x8417, 0x00f7}, {0x8418, 0x001f}, -{0x8419, 0x00bd}, {0x841a, 0x00f8}, {0x841b, 0x0044}, -{0x841c, 0x00bd}, {0x841d, 0x00fc}, {0x841e, 0x0029}, -{0x841f, 0x00ce}, {0x8420, 0x0082}, {0x8421, 0x0025}, -{0x8422, 0x00ff}, {0x8423, 0x0001}, {0x8424, 0x000f}, -{0x8425, 0x0039}, {0x8426, 0x0096}, {0x8427, 0x0047}, -{0x8428, 0x0084}, {0x8429, 0x00fc}, {0x842a, 0x008a}, -{0x842b, 0x0000}, {0x842c, 0x0097}, {0x842d, 0x0047}, -{0x842e, 0x00ce}, {0x842f, 0x0084}, {0x8430, 0x0034}, -{0x8431, 0x00ff}, {0x8432, 0x0001}, {0x8433, 0x0011}, -{0x8434, 0x0096}, {0x8435, 0x0046}, {0x8436, 0x0084}, -{0x8437, 0x0003}, {0x8438, 0x0081}, {0x8439, 0x0002}, -{0x843a, 0x0027}, {0x843b, 0x0003}, {0x843c, 0x007e}, -{0x843d, 0x0085}, {0x843e, 0x001e}, {0x843f, 0x0096}, -{0x8440, 0x0047}, {0x8441, 0x0084}, {0x8442, 0x00fc}, -{0x8443, 0x008a}, {0x8444, 0x0002}, {0x8445, 0x0097}, -{0x8446, 0x0047}, {0x8447, 0x00de}, {0x8448, 0x00e1}, -{0x8449, 0x00ad}, {0x844a, 0x0000}, {0x844b, 0x0086}, -{0x844c, 0x0001}, {0x844d, 0x00b7}, {0x844e, 0x0012}, -{0x844f, 0x0051}, {0x8450, 0x00bd}, {0x8451, 0x00f7}, -{0x8452, 0x0014}, {0x8453, 0x00b6}, {0x8454, 0x0010}, -{0x8455, 0x0031}, {0x8456, 0x0084}, {0x8457, 0x00fd}, -{0x8458, 0x00b7}, {0x8459, 0x0010}, {0x845a, 0x0031}, -{0x845b, 0x00bd}, {0x845c, 0x00f8}, {0x845d, 0x001e}, -{0x845e, 0x0096}, {0x845f, 0x0081}, {0x8460, 0x00d6}, -{0x8461, 0x0082}, {0x8462, 0x00fe}, {0x8463, 0x008f}, -{0x8464, 0x005a}, {0x8465, 0x00bd}, {0x8466, 0x00f7}, -{0x8467, 0x00b6}, {0x8468, 0x00fe}, {0x8469, 0x008f}, -{0x846a, 0x005c}, {0x846b, 0x00bd}, {0x846c, 0x00ec}, -{0x846d, 0x008e}, {0x846e, 0x00bd}, {0x846f, 0x00fa}, -{0x8470, 0x00f7}, {0x8471, 0x0086}, {0x8472, 0x0008}, -{0x8473, 0x00d6}, {0x8474, 0x0000}, {0x8475, 0x00c5}, -{0x8476, 0x0010}, {0x8477, 0x0026}, {0x8478, 0x0002}, -{0x8479, 0x008b}, {0x847a, 0x0020}, {0x847b, 0x00c6}, -{0x847c, 0x0051}, {0x847d, 0x00bd}, {0x847e, 0x00e4}, -{0x847f, 0x0012}, {0x8480, 0x00ce}, {0x8481, 0x0084}, -{0x8482, 0x0086}, {0x8483, 0x00ff}, {0x8484, 0x0001}, -{0x8485, 0x0011}, {0x8486, 0x0096}, {0x8487, 0x0046}, -{0x8488, 0x0084}, {0x8489, 0x0003}, {0x848a, 0x0081}, -{0x848b, 0x0002}, {0x848c, 0x0027}, {0x848d, 0x0003}, -{0x848e, 0x007e}, {0x848f, 0x0085}, {0x8490, 0x000f}, -{0x8491, 0x00c6}, {0x8492, 0x0051}, {0x8493, 0x00bd}, -{0x8494, 0x00e4}, {0x8495, 0x0091}, {0x8496, 0x0025}, -{0x8497, 0x0003}, {0x8498, 0x007e}, {0x8499, 0x0085}, -{0x849a, 0x001e}, {0x849b, 0x0096}, {0x849c, 0x0044}, -{0x849d, 0x0085}, {0x849e, 0x0010}, {0x849f, 0x0026}, -{0x84a0, 0x000a}, {0x84a1, 0x00b6}, {0x84a2, 0x0012}, -{0x84a3, 0x0050}, {0x84a4, 0x00ba}, {0x84a5, 0x0001}, -{0x84a6, 0x003c}, {0x84a7, 0x0085}, {0x84a8, 0x0010}, -{0x84a9, 0x0027}, {0x84aa, 0x00a8}, {0x84ab, 0x00bd}, -{0x84ac, 0x00f7}, {0x84ad, 0x0066}, {0x84ae, 0x00ce}, -{0x84af, 0x0084}, {0x84b0, 0x00b7}, {0x84b1, 0x00ff}, -{0x84b2, 0x0001}, {0x84b3, 0x0011}, {0x84b4, 0x007e}, -{0x84b5, 0x0085}, {0x84b6, 0x001e}, {0x84b7, 0x0096}, -{0x84b8, 0x0046}, {0x84b9, 0x0084}, {0x84ba, 0x0003}, -{0x84bb, 0x0081}, {0x84bc, 0x0002}, {0x84bd, 0x0026}, -{0x84be, 0x0050}, {0x84bf, 0x00b6}, {0x84c0, 0x0012}, -{0x84c1, 0x0030}, {0x84c2, 0x0084}, {0x84c3, 0x0003}, -{0x84c4, 0x0081}, {0x84c5, 0x0001}, {0x84c6, 0x0027}, -{0x84c7, 0x0003}, {0x84c8, 0x007e}, {0x84c9, 0x0085}, -{0x84ca, 0x001e}, {0x84cb, 0x0096}, {0x84cc, 0x0044}, -{0x84cd, 0x0085}, {0x84ce, 0x0010}, {0x84cf, 0x0026}, -{0x84d0, 0x0013}, {0x84d1, 0x00b6}, {0x84d2, 0x0012}, -{0x84d3, 0x0050}, {0x84d4, 0x00ba}, {0x84d5, 0x0001}, -{0x84d6, 0x003c}, {0x84d7, 0x0085}, {0x84d8, 0x0010}, -{0x84d9, 0x0026}, {0x84da, 0x0009}, {0x84db, 0x00ce}, -{0x84dc, 0x0084}, {0x84dd, 0x0053}, {0x84de, 0x00ff}, -{0x84df, 0x0001}, {0x84e0, 0x0011}, {0x84e1, 0x007e}, -{0x84e2, 0x0085}, {0x84e3, 0x001e}, {0x84e4, 0x00b6}, -{0x84e5, 0x0010}, {0x84e6, 0x0031}, {0x84e7, 0x008a}, -{0x84e8, 0x0002}, {0x84e9, 0x00b7}, {0x84ea, 0x0010}, -{0x84eb, 0x0031}, {0x84ec, 0x00bd}, {0x84ed, 0x0085}, -{0x84ee, 0x001f}, {0x84ef, 0x00bd}, {0x84f0, 0x00f8}, -{0x84f1, 0x0037}, {0x84f2, 0x007c}, {0x84f3, 0x0000}, -{0x84f4, 0x0080}, {0x84f5, 0x00ce}, {0x84f6, 0x0084}, -{0x84f7, 0x00fe}, {0x84f8, 0x00ff}, {0x84f9, 0x0001}, -{0x84fa, 0x0011}, {0x84fb, 0x007e}, {0x84fc, 0x0085}, -{0x84fd, 0x001e}, {0x84fe, 0x0096}, {0x84ff, 0x0046}, -{0x8500, 0x0084}, {0x8501, 0x0003}, {0x8502, 0x0081}, -{0x8503, 0x0002}, {0x8504, 0x0026}, {0x8505, 0x0009}, -{0x8506, 0x00b6}, {0x8507, 0x0012}, {0x8508, 0x0030}, -{0x8509, 0x0084}, {0x850a, 0x0003}, {0x850b, 0x0081}, -{0x850c, 0x0001}, {0x850d, 0x0027}, {0x850e, 0x000f}, -{0x850f, 0x00bd}, {0x8510, 0x00f8}, {0x8511, 0x0044}, -{0x8512, 0x00bd}, {0x8513, 0x00f7}, {0x8514, 0x000b}, -{0x8515, 0x00bd}, {0x8516, 0x00fc}, {0x8517, 0x0029}, -{0x8518, 0x00ce}, {0x8519, 0x0084}, {0x851a, 0x0026}, -{0x851b, 0x00ff}, {0x851c, 0x0001}, {0x851d, 0x0011}, -{0x851e, 0x0039}, {0x851f, 0x00d6}, {0x8520, 0x0022}, -{0x8521, 0x00c4}, {0x8522, 0x000f}, {0x8523, 0x00b6}, -{0x8524, 0x0012}, {0x8525, 0x0030}, {0x8526, 0x00ba}, -{0x8527, 0x0012}, {0x8528, 0x0032}, {0x8529, 0x0084}, -{0x852a, 0x0004}, {0x852b, 0x0027}, {0x852c, 0x000d}, -{0x852d, 0x0096}, {0x852e, 0x0022}, {0x852f, 0x0085}, -{0x8530, 0x0004}, {0x8531, 0x0027}, {0x8532, 0x0005}, -{0x8533, 0x00ca}, {0x8534, 0x0010}, {0x8535, 0x007e}, -{0x8536, 0x0085}, {0x8537, 0x003a}, {0x8538, 0x00ca}, -{0x8539, 0x0020}, {0x853a, 0x00d7}, {0x853b, 0x0022}, -{0x853c, 0x0039}, {0x853d, 0x0086}, {0x853e, 0x0000}, -{0x853f, 0x0097}, {0x8540, 0x0083}, {0x8541, 0x0018}, -{0x8542, 0x00ce}, {0x8543, 0x001c}, {0x8544, 0x0000}, -{0x8545, 0x00bd}, {0x8546, 0x00eb}, {0x8547, 0x0046}, -{0x8548, 0x0096}, {0x8549, 0x0057}, {0x854a, 0x0085}, -{0x854b, 0x0001}, {0x854c, 0x0027}, {0x854d, 0x0002}, -{0x854e, 0x004f}, {0x854f, 0x0039}, {0x8550, 0x0085}, -{0x8551, 0x0002}, {0x8552, 0x0027}, {0x8553, 0x0001}, -{0x8554, 0x0039}, {0x8555, 0x007f}, {0x8556, 0x008f}, -{0x8557, 0x007d}, {0x8558, 0x0086}, {0x8559, 0x0004}, -{0x855a, 0x00b7}, {0x855b, 0x0012}, {0x855c, 0x0004}, -{0x855d, 0x0086}, {0x855e, 0x0008}, {0x855f, 0x00b7}, -{0x8560, 0x0012}, {0x8561, 0x0007}, {0x8562, 0x0086}, -{0x8563, 0x0010}, {0x8564, 0x00b7}, {0x8565, 0x0012}, -{0x8566, 0x000c}, {0x8567, 0x0086}, {0x8568, 0x0007}, -{0x8569, 0x00b7}, {0x856a, 0x0012}, {0x856b, 0x0006}, -{0x856c, 0x00b6}, {0x856d, 0x008f}, {0x856e, 0x007d}, -{0x856f, 0x00b7}, {0x8570, 0x0012}, {0x8571, 0x0070}, -{0x8572, 0x0086}, {0x8573, 0x0001}, {0x8574, 0x00ba}, -{0x8575, 0x0012}, {0x8576, 0x0004}, {0x8577, 0x00b7}, -{0x8578, 0x0012}, {0x8579, 0x0004}, {0x857a, 0x0001}, -{0x857b, 0x0001}, {0x857c, 0x0001}, {0x857d, 0x0001}, -{0x857e, 0x0001}, {0x857f, 0x0001}, {0x8580, 0x00b6}, -{0x8581, 0x0012}, {0x8582, 0x0004}, {0x8583, 0x0084}, -{0x8584, 0x00fe}, {0x8585, 0x008a}, {0x8586, 0x0002}, -{0x8587, 0x00b7}, {0x8588, 0x0012}, {0x8589, 0x0004}, -{0x858a, 0x0001}, {0x858b, 0x0001}, {0x858c, 0x0001}, -{0x858d, 0x0001}, {0x858e, 0x0001}, {0x858f, 0x0001}, -{0x8590, 0x0086}, {0x8591, 0x00fd}, {0x8592, 0x00b4}, -{0x8593, 0x0012}, {0x8594, 0x0004}, {0x8595, 0x00b7}, -{0x8596, 0x0012}, {0x8597, 0x0004}, {0x8598, 0x00b6}, -{0x8599, 0x0012}, {0x859a, 0x0000}, {0x859b, 0x0084}, -{0x859c, 0x0008}, {0x859d, 0x0081}, {0x859e, 0x0008}, -{0x859f, 0x0027}, {0x85a0, 0x0016}, {0x85a1, 0x00b6}, -{0x85a2, 0x008f}, {0x85a3, 0x007d}, {0x85a4, 0x0081}, -{0x85a5, 0x000c}, {0x85a6, 0x0027}, {0x85a7, 0x0008}, -{0x85a8, 0x008b}, {0x85a9, 0x0004}, {0x85aa, 0x00b7}, -{0x85ab, 0x008f}, {0x85ac, 0x007d}, {0x85ad, 0x007e}, -{0x85ae, 0x0085}, {0x85af, 0x006c}, {0x85b0, 0x0086}, -{0x85b1, 0x0003}, {0x85b2, 0x0097}, {0x85b3, 0x0040}, -{0x85b4, 0x007e}, {0x85b5, 0x0089}, {0x85b6, 0x006e}, -{0x85b7, 0x0086}, {0x85b8, 0x0007}, {0x85b9, 0x00b7}, -{0x85ba, 0x0012}, {0x85bb, 0x0006}, {0x85bc, 0x005f}, -{0x85bd, 0x00f7}, {0x85be, 0x008f}, {0x85bf, 0x0082}, -{0x85c0, 0x005f}, {0x85c1, 0x00f7}, {0x85c2, 0x008f}, -{0x85c3, 0x007f}, {0x85c4, 0x00f7}, {0x85c5, 0x008f}, -{0x85c6, 0x0070}, {0x85c7, 0x00f7}, {0x85c8, 0x008f}, -{0x85c9, 0x0071}, {0x85ca, 0x00f7}, {0x85cb, 0x008f}, -{0x85cc, 0x0072}, {0x85cd, 0x00f7}, {0x85ce, 0x008f}, -{0x85cf, 0x0073}, {0x85d0, 0x00f7}, {0x85d1, 0x008f}, -{0x85d2, 0x0074}, {0x85d3, 0x00f7}, {0x85d4, 0x008f}, -{0x85d5, 0x0075}, {0x85d6, 0x00f7}, {0x85d7, 0x008f}, -{0x85d8, 0x0076}, {0x85d9, 0x00f7}, {0x85da, 0x008f}, -{0x85db, 0x0077}, {0x85dc, 0x00f7}, {0x85dd, 0x008f}, -{0x85de, 0x0078}, {0x85df, 0x00f7}, {0x85e0, 0x008f}, -{0x85e1, 0x0079}, {0x85e2, 0x00f7}, {0x85e3, 0x008f}, -{0x85e4, 0x007a}, {0x85e5, 0x00f7}, {0x85e6, 0x008f}, -{0x85e7, 0x007b}, {0x85e8, 0x00b6}, {0x85e9, 0x0012}, -{0x85ea, 0x0004}, {0x85eb, 0x008a}, {0x85ec, 0x0010}, -{0x85ed, 0x00b7}, {0x85ee, 0x0012}, {0x85ef, 0x0004}, -{0x85f0, 0x0086}, {0x85f1, 0x00e4}, {0x85f2, 0x00b7}, -{0x85f3, 0x0012}, {0x85f4, 0x0070}, {0x85f5, 0x00b7}, -{0x85f6, 0x0012}, {0x85f7, 0x0007}, {0x85f8, 0x00f7}, -{0x85f9, 0x0012}, {0x85fa, 0x0005}, {0x85fb, 0x00f7}, -{0x85fc, 0x0012}, {0x85fd, 0x0009}, {0x85fe, 0x0086}, -{0x85ff, 0x0008}, {0x8600, 0x00ba}, {0x8601, 0x0012}, -{0x8602, 0x0004}, {0x8603, 0x00b7}, {0x8604, 0x0012}, -{0x8605, 0x0004}, {0x8606, 0x0086}, {0x8607, 0x00f7}, -{0x8608, 0x00b4}, {0x8609, 0x0012}, {0x860a, 0x0004}, -{0x860b, 0x00b7}, {0x860c, 0x0012}, {0x860d, 0x0004}, -{0x860e, 0x0001}, {0x860f, 0x0001}, {0x8610, 0x0001}, -{0x8611, 0x0001}, {0x8612, 0x0001}, {0x8613, 0x0001}, -{0x8614, 0x00b6}, {0x8615, 0x0012}, {0x8616, 0x0008}, -{0x8617, 0x0027}, {0x8618, 0x007f}, {0x8619, 0x0081}, -{0x861a, 0x0080}, {0x861b, 0x0026}, {0x861c, 0x000b}, -{0x861d, 0x0086}, {0x861e, 0x0008}, {0x861f, 0x00ce}, -{0x8620, 0x008f}, {0x8621, 0x0079}, {0x8622, 0x00bd}, -{0x8623, 0x0089}, {0x8624, 0x007b}, {0x8625, 0x007e}, -{0x8626, 0x0086}, {0x8627, 0x008e}, {0x8628, 0x0081}, -{0x8629, 0x0040}, {0x862a, 0x0026}, {0x862b, 0x000b}, -{0x862c, 0x0086}, {0x862d, 0x0004}, {0x862e, 0x00ce}, -{0x862f, 0x008f}, {0x8630, 0x0076}, {0x8631, 0x00bd}, -{0x8632, 0x0089}, {0x8633, 0x007b}, {0x8634, 0x007e}, -{0x8635, 0x0086}, {0x8636, 0x008e}, {0x8637, 0x0081}, -{0x8638, 0x0020}, {0x8639, 0x0026}, {0x863a, 0x000b}, -{0x863b, 0x0086}, {0x863c, 0x0002}, {0x863d, 0x00ce}, -{0x863e, 0x008f}, {0x863f, 0x0073}, {0x8640, 0x00bd}, -{0x8641, 0x0089}, {0x8642, 0x007b}, {0x8643, 0x007e}, -{0x8644, 0x0086}, {0x8645, 0x008e}, {0x8646, 0x0081}, -{0x8647, 0x0010}, {0x8648, 0x0026}, {0x8649, 0x000b}, -{0x864a, 0x0086}, {0x864b, 0x0001}, {0x864c, 0x00ce}, -{0x864d, 0x008f}, {0x864e, 0x0070}, {0x864f, 0x00bd}, -{0x8650, 0x0089}, {0x8651, 0x007b}, {0x8652, 0x007e}, -{0x8653, 0x0086}, {0x8654, 0x008e}, {0x8655, 0x0081}, -{0x8656, 0x0008}, {0x8657, 0x0026}, {0x8658, 0x000b}, -{0x8659, 0x0086}, {0x865a, 0x0008}, {0x865b, 0x00ce}, -{0x865c, 0x008f}, {0x865d, 0x0079}, {0x865e, 0x00bd}, -{0x865f, 0x0089}, {0x8660, 0x007f}, {0x8661, 0x007e}, -{0x8662, 0x0086}, {0x8663, 0x008e}, {0x8664, 0x0081}, -{0x8665, 0x0004}, {0x8666, 0x0026}, {0x8667, 0x000b}, -{0x8668, 0x0086}, {0x8669, 0x0004}, {0x866a, 0x00ce}, -{0x866b, 0x008f}, {0x866c, 0x0076}, {0x866d, 0x00bd}, -{0x866e, 0x0089}, {0x866f, 0x007f}, {0x8670, 0x007e}, -{0x8671, 0x0086}, {0x8672, 0x008e}, {0x8673, 0x0081}, -{0x8674, 0x0002}, {0x8675, 0x0026}, {0x8676, 0x000b}, -{0x8677, 0x008a}, {0x8678, 0x0002}, {0x8679, 0x00ce}, -{0x867a, 0x008f}, {0x867b, 0x0073}, {0x867c, 0x00bd}, -{0x867d, 0x0089}, {0x867e, 0x007f}, {0x867f, 0x007e}, -{0x8680, 0x0086}, {0x8681, 0x008e}, {0x8682, 0x0081}, -{0x8683, 0x0001}, {0x8684, 0x0026}, {0x8685, 0x0008}, -{0x8686, 0x0086}, {0x8687, 0x0001}, {0x8688, 0x00ce}, -{0x8689, 0x008f}, {0x868a, 0x0070}, {0x868b, 0x00bd}, -{0x868c, 0x0089}, {0x868d, 0x007f}, {0x868e, 0x00b6}, -{0x868f, 0x008f}, {0x8690, 0x007f}, {0x8691, 0x0081}, -{0x8692, 0x000f}, {0x8693, 0x0026}, {0x8694, 0x0003}, -{0x8695, 0x007e}, {0x8696, 0x0087}, {0x8697, 0x0047}, -{0x8698, 0x00b6}, {0x8699, 0x0012}, {0x869a, 0x0009}, -{0x869b, 0x0084}, {0x869c, 0x0003}, {0x869d, 0x0081}, -{0x869e, 0x0003}, {0x869f, 0x0027}, {0x86a0, 0x0006}, -{0x86a1, 0x007c}, {0x86a2, 0x0012}, {0x86a3, 0x0009}, -{0x86a4, 0x007e}, {0x86a5, 0x0085}, {0x86a6, 0x00fe}, -{0x86a7, 0x00b6}, {0x86a8, 0x0012}, {0x86a9, 0x0006}, -{0x86aa, 0x0084}, {0x86ab, 0x0007}, {0x86ac, 0x0081}, -{0x86ad, 0x0007}, {0x86ae, 0x0027}, {0x86af, 0x0008}, -{0x86b0, 0x008b}, {0x86b1, 0x0001}, {0x86b2, 0x00b7}, -{0x86b3, 0x0012}, {0x86b4, 0x0006}, {0x86b5, 0x007e}, -{0x86b6, 0x0086}, {0x86b7, 0x00d5}, {0x86b8, 0x00b6}, -{0x86b9, 0x008f}, {0x86ba, 0x0082}, {0x86bb, 0x0026}, -{0x86bc, 0x000a}, {0x86bd, 0x007c}, {0x86be, 0x008f}, -{0x86bf, 0x0082}, {0x86c0, 0x004f}, {0x86c1, 0x00b7}, -{0x86c2, 0x0012}, {0x86c3, 0x0006}, {0x86c4, 0x007e}, -{0x86c5, 0x0085}, {0x86c6, 0x00c0}, {0x86c7, 0x00b6}, -{0x86c8, 0x0012}, {0x86c9, 0x0006}, {0x86ca, 0x0084}, -{0x86cb, 0x003f}, {0x86cc, 0x0081}, {0x86cd, 0x003f}, -{0x86ce, 0x0027}, {0x86cf, 0x0010}, {0x86d0, 0x008b}, -{0x86d1, 0x0008}, {0x86d2, 0x00b7}, {0x86d3, 0x0012}, -{0x86d4, 0x0006}, {0x86d5, 0x00b6}, {0x86d6, 0x0012}, -{0x86d7, 0x0009}, {0x86d8, 0x0084}, {0x86d9, 0x00fc}, -{0x86da, 0x00b7}, {0x86db, 0x0012}, {0x86dc, 0x0009}, -{0x86dd, 0x007e}, {0x86de, 0x0085}, {0x86df, 0x00fe}, -{0x86e0, 0x00ce}, {0x86e1, 0x008f}, {0x86e2, 0x0070}, -{0x86e3, 0x0018}, {0x86e4, 0x00ce}, {0x86e5, 0x008f}, -{0x86e6, 0x0084}, {0x86e7, 0x00c6}, {0x86e8, 0x000c}, -{0x86e9, 0x00bd}, {0x86ea, 0x0089}, {0x86eb, 0x006f}, -{0x86ec, 0x00ce}, {0x86ed, 0x008f}, {0x86ee, 0x0084}, -{0x86ef, 0x0018}, {0x86f0, 0x00ce}, {0x86f1, 0x008f}, -{0x86f2, 0x0070}, {0x86f3, 0x00c6}, {0x86f4, 0x000c}, -{0x86f5, 0x00bd}, {0x86f6, 0x0089}, {0x86f7, 0x006f}, -{0x86f8, 0x00d6}, {0x86f9, 0x0083}, {0x86fa, 0x00c1}, -{0x86fb, 0x004f}, {0x86fc, 0x002d}, {0x86fd, 0x0003}, -{0x86fe, 0x007e}, {0x86ff, 0x0087}, {0x8700, 0x0040}, -{0x8701, 0x00b6}, {0x8702, 0x008f}, {0x8703, 0x007f}, -{0x8704, 0x0081}, {0x8705, 0x0007}, {0x8706, 0x0027}, -{0x8707, 0x000f}, {0x8708, 0x0081}, {0x8709, 0x000b}, -{0x870a, 0x0027}, {0x870b, 0x0015}, {0x870c, 0x0081}, -{0x870d, 0x000d}, {0x870e, 0x0027}, {0x870f, 0x001b}, -{0x8710, 0x0081}, {0x8711, 0x000e}, {0x8712, 0x0027}, -{0x8713, 0x0021}, {0x8714, 0x007e}, {0x8715, 0x0087}, -{0x8716, 0x0040}, {0x8717, 0x00f7}, {0x8718, 0x008f}, -{0x8719, 0x007b}, {0x871a, 0x0086}, {0x871b, 0x0002}, -{0x871c, 0x00b7}, {0x871d, 0x008f}, {0x871e, 0x007a}, -{0x871f, 0x0020}, {0x8720, 0x001c}, {0x8721, 0x00f7}, -{0x8722, 0x008f}, {0x8723, 0x0078}, {0x8724, 0x0086}, -{0x8725, 0x0002}, {0x8726, 0x00b7}, {0x8727, 0x008f}, -{0x8728, 0x0077}, {0x8729, 0x0020}, {0x872a, 0x0012}, -{0x872b, 0x00f7}, {0x872c, 0x008f}, {0x872d, 0x0075}, -{0x872e, 0x0086}, {0x872f, 0x0002}, {0x8730, 0x00b7}, -{0x8731, 0x008f}, {0x8732, 0x0074}, {0x8733, 0x0020}, -{0x8734, 0x0008}, {0x8735, 0x00f7}, {0x8736, 0x008f}, -{0x8737, 0x0072}, {0x8738, 0x0086}, {0x8739, 0x0002}, -{0x873a, 0x00b7}, {0x873b, 0x008f}, {0x873c, 0x0071}, -{0x873d, 0x007e}, {0x873e, 0x0087}, {0x873f, 0x0047}, -{0x8740, 0x0086}, {0x8741, 0x0004}, {0x8742, 0x0097}, -{0x8743, 0x0040}, {0x8744, 0x007e}, {0x8745, 0x0089}, -{0x8746, 0x006e}, {0x8747, 0x00ce}, {0x8748, 0x008f}, -{0x8749, 0x0072}, {0x874a, 0x00bd}, {0x874b, 0x0089}, -{0x874c, 0x00f7}, {0x874d, 0x00ce}, {0x874e, 0x008f}, -{0x874f, 0x0075}, {0x8750, 0x00bd}, {0x8751, 0x0089}, -{0x8752, 0x00f7}, {0x8753, 0x00ce}, {0x8754, 0x008f}, -{0x8755, 0x0078}, {0x8756, 0x00bd}, {0x8757, 0x0089}, -{0x8758, 0x00f7}, {0x8759, 0x00ce}, {0x875a, 0x008f}, -{0x875b, 0x007b}, {0x875c, 0x00bd}, {0x875d, 0x0089}, -{0x875e, 0x00f7}, {0x875f, 0x004f}, {0x8760, 0x00b7}, -{0x8761, 0x008f}, {0x8762, 0x007d}, {0x8763, 0x00b7}, -{0x8764, 0x008f}, {0x8765, 0x0081}, {0x8766, 0x00b6}, -{0x8767, 0x008f}, {0x8768, 0x0072}, {0x8769, 0x0027}, -{0x876a, 0x0047}, {0x876b, 0x007c}, {0x876c, 0x008f}, -{0x876d, 0x007d}, {0x876e, 0x00b6}, {0x876f, 0x008f}, -{0x8770, 0x0075}, {0x8771, 0x0027}, {0x8772, 0x003f}, -{0x8773, 0x007c}, {0x8774, 0x008f}, {0x8775, 0x007d}, -{0x8776, 0x00b6}, {0x8777, 0x008f}, {0x8778, 0x0078}, -{0x8779, 0x0027}, {0x877a, 0x0037}, {0x877b, 0x007c}, -{0x877c, 0x008f}, {0x877d, 0x007d}, {0x877e, 0x00b6}, -{0x877f, 0x008f}, {0x8780, 0x007b}, {0x8781, 0x0027}, -{0x8782, 0x002f}, {0x8783, 0x007f}, {0x8784, 0x008f}, -{0x8785, 0x007d}, {0x8786, 0x007c}, {0x8787, 0x008f}, -{0x8788, 0x0081}, {0x8789, 0x007a}, {0x878a, 0x008f}, -{0x878b, 0x0072}, {0x878c, 0x0027}, {0x878d, 0x001b}, -{0x878e, 0x007c}, {0x878f, 0x008f}, {0x8790, 0x007d}, -{0x8791, 0x007a}, {0x8792, 0x008f}, {0x8793, 0x0075}, -{0x8794, 0x0027}, {0x8795, 0x0016}, {0x8796, 0x007c}, -{0x8797, 0x008f}, {0x8798, 0x007d}, {0x8799, 0x007a}, -{0x879a, 0x008f}, {0x879b, 0x0078}, {0x879c, 0x0027}, -{0x879d, 0x0011}, {0x879e, 0x007c}, {0x879f, 0x008f}, -{0x87a0, 0x007d}, {0x87a1, 0x007a}, {0x87a2, 0x008f}, -{0x87a3, 0x007b}, {0x87a4, 0x0027}, {0x87a5, 0x000c}, -{0x87a6, 0x007e}, {0x87a7, 0x0087}, {0x87a8, 0x0083}, -{0x87a9, 0x007a}, {0x87aa, 0x008f}, {0x87ab, 0x0075}, -{0x87ac, 0x007a}, {0x87ad, 0x008f}, {0x87ae, 0x0078}, -{0x87af, 0x007a}, {0x87b0, 0x008f}, {0x87b1, 0x007b}, -{0x87b2, 0x00ce}, {0x87b3, 0x00c1}, {0x87b4, 0x00fc}, -{0x87b5, 0x00f6}, {0x87b6, 0x008f}, {0x87b7, 0x007d}, -{0x87b8, 0x003a}, {0x87b9, 0x00a6}, {0x87ba, 0x0000}, -{0x87bb, 0x00b7}, {0x87bc, 0x0012}, {0x87bd, 0x0070}, -{0x87be, 0x00b6}, {0x87bf, 0x008f}, {0x87c0, 0x0072}, -{0x87c1, 0x0026}, {0x87c2, 0x0003}, {0x87c3, 0x007e}, -{0x87c4, 0x0087}, {0x87c5, 0x00fa}, {0x87c6, 0x00b6}, -{0x87c7, 0x008f}, {0x87c8, 0x0075}, {0x87c9, 0x0026}, -{0x87ca, 0x000a}, {0x87cb, 0x0018}, {0x87cc, 0x00ce}, -{0x87cd, 0x008f}, {0x87ce, 0x0073}, {0x87cf, 0x00bd}, -{0x87d0, 0x0089}, {0x87d1, 0x00d5}, {0x87d2, 0x007e}, -{0x87d3, 0x0087}, {0x87d4, 0x00fa}, {0x87d5, 0x00b6}, -{0x87d6, 0x008f}, {0x87d7, 0x0078}, {0x87d8, 0x0026}, -{0x87d9, 0x000a}, {0x87da, 0x0018}, {0x87db, 0x00ce}, -{0x87dc, 0x008f}, {0x87dd, 0x0076}, {0x87de, 0x00bd}, -{0x87df, 0x0089}, {0x87e0, 0x00d5}, {0x87e1, 0x007e}, -{0x87e2, 0x0087}, {0x87e3, 0x00fa}, {0x87e4, 0x00b6}, -{0x87e5, 0x008f}, {0x87e6, 0x007b}, {0x87e7, 0x0026}, -{0x87e8, 0x000a}, {0x87e9, 0x0018}, {0x87ea, 0x00ce}, -{0x87eb, 0x008f}, {0x87ec, 0x0079}, {0x87ed, 0x00bd}, -{0x87ee, 0x0089}, {0x87ef, 0x00d5}, {0x87f0, 0x007e}, -{0x87f1, 0x0087}, {0x87f2, 0x00fa}, {0x87f3, 0x0086}, -{0x87f4, 0x0005}, {0x87f5, 0x0097}, {0x87f6, 0x0040}, -{0x87f7, 0x007e}, {0x87f8, 0x0089}, {0x87f9, 0x0000}, -{0x87fa, 0x00b6}, {0x87fb, 0x008f}, {0x87fc, 0x0075}, -{0x87fd, 0x0081}, {0x87fe, 0x0007}, {0x87ff, 0x002e}, -{0x8800, 0x00f2}, {0x8801, 0x00f6}, {0x8802, 0x0012}, -{0x8803, 0x0006}, {0x8804, 0x00c4}, {0x8805, 0x00f8}, -{0x8806, 0x001b}, {0x8807, 0x00b7}, {0x8808, 0x0012}, -{0x8809, 0x0006}, {0x880a, 0x00b6}, {0x880b, 0x008f}, -{0x880c, 0x0078}, {0x880d, 0x0081}, {0x880e, 0x0007}, -{0x880f, 0x002e}, {0x8810, 0x00e2}, {0x8811, 0x0048}, -{0x8812, 0x0048}, {0x8813, 0x0048}, {0x8814, 0x00f6}, -{0x8815, 0x0012}, {0x8816, 0x0006}, {0x8817, 0x00c4}, -{0x8818, 0x00c7}, {0x8819, 0x001b}, {0x881a, 0x00b7}, -{0x881b, 0x0012}, {0x881c, 0x0006}, {0x881d, 0x00b6}, -{0x881e, 0x008f}, {0x881f, 0x007b}, {0x8820, 0x0081}, -{0x8821, 0x0007}, {0x8822, 0x002e}, {0x8823, 0x00cf}, -{0x8824, 0x00f6}, {0x8825, 0x0012}, {0x8826, 0x0005}, -{0x8827, 0x00c4}, {0x8828, 0x00f8}, {0x8829, 0x001b}, -{0x882a, 0x00b7}, {0x882b, 0x0012}, {0x882c, 0x0005}, -{0x882d, 0x0086}, {0x882e, 0x0000}, {0x882f, 0x00f6}, -{0x8830, 0x008f}, {0x8831, 0x0071}, {0x8832, 0x00bd}, -{0x8833, 0x0089}, {0x8834, 0x0094}, {0x8835, 0x0086}, -{0x8836, 0x0001}, {0x8837, 0x00f6}, {0x8838, 0x008f}, -{0x8839, 0x0074}, {0x883a, 0x00bd}, {0x883b, 0x0089}, -{0x883c, 0x0094}, {0x883d, 0x0086}, {0x883e, 0x0002}, -{0x883f, 0x00f6}, {0x8840, 0x008f}, {0x8841, 0x0077}, -{0x8842, 0x00bd}, {0x8843, 0x0089}, {0x8844, 0x0094}, -{0x8845, 0x0086}, {0x8846, 0x0003}, {0x8847, 0x00f6}, -{0x8848, 0x008f}, {0x8849, 0x007a}, {0x884a, 0x00bd}, -{0x884b, 0x0089}, {0x884c, 0x0094}, {0x884d, 0x00ce}, -{0x884e, 0x008f}, {0x884f, 0x0070}, {0x8850, 0x00a6}, -{0x8851, 0x0001}, {0x8852, 0x0081}, {0x8853, 0x0001}, -{0x8854, 0x0027}, {0x8855, 0x0007}, {0x8856, 0x0081}, -{0x8857, 0x0003}, {0x8858, 0x0027}, {0x8859, 0x0003}, -{0x885a, 0x007e}, {0x885b, 0x0088}, {0x885c, 0x0066}, -{0x885d, 0x00a6}, {0x885e, 0x0000}, {0x885f, 0x00b8}, -{0x8860, 0x008f}, {0x8861, 0x0081}, {0x8862, 0x0084}, -{0x8863, 0x0001}, {0x8864, 0x0026}, {0x8865, 0x000b}, -{0x8866, 0x008c}, {0x8867, 0x008f}, {0x8868, 0x0079}, -{0x8869, 0x002c}, {0x886a, 0x000e}, {0x886b, 0x0008}, -{0x886c, 0x0008}, {0x886d, 0x0008}, {0x886e, 0x007e}, -{0x886f, 0x0088}, {0x8870, 0x0050}, {0x8871, 0x00b6}, -{0x8872, 0x0012}, {0x8873, 0x0004}, {0x8874, 0x008a}, -{0x8875, 0x0040}, {0x8876, 0x00b7}, {0x8877, 0x0012}, -{0x8878, 0x0004}, {0x8879, 0x00b6}, {0x887a, 0x0012}, -{0x887b, 0x0004}, {0x887c, 0x0084}, {0x887d, 0x00fb}, -{0x887e, 0x0084}, {0x887f, 0x00ef}, {0x8880, 0x00b7}, -{0x8881, 0x0012}, {0x8882, 0x0004}, {0x8883, 0x00b6}, -{0x8884, 0x0012}, {0x8885, 0x0007}, {0x8886, 0x0036}, -{0x8887, 0x00b6}, {0x8888, 0x008f}, {0x8889, 0x007c}, -{0x888a, 0x0048}, {0x888b, 0x0048}, {0x888c, 0x00b7}, -{0x888d, 0x0012}, {0x888e, 0x0007}, {0x888f, 0x0086}, -{0x8890, 0x0001}, {0x8891, 0x00ba}, {0x8892, 0x0012}, -{0x8893, 0x0004}, {0x8894, 0x00b7}, {0x8895, 0x0012}, -{0x8896, 0x0004}, {0x8897, 0x0001}, {0x8898, 0x0001}, -{0x8899, 0x0001}, {0x889a, 0x0001}, {0x889b, 0x0001}, -{0x889c, 0x0001}, {0x889d, 0x0086}, {0x889e, 0x00fe}, -{0x889f, 0x00b4}, {0x88a0, 0x0012}, {0x88a1, 0x0004}, -{0x88a2, 0x00b7}, {0x88a3, 0x0012}, {0x88a4, 0x0004}, -{0x88a5, 0x0086}, {0x88a6, 0x0002}, {0x88a7, 0x00ba}, -{0x88a8, 0x0012}, {0x88a9, 0x0004}, {0x88aa, 0x00b7}, -{0x88ab, 0x0012}, {0x88ac, 0x0004}, {0x88ad, 0x0086}, -{0x88ae, 0x00fd}, {0x88af, 0x00b4}, {0x88b0, 0x0012}, -{0x88b1, 0x0004}, {0x88b2, 0x00b7}, {0x88b3, 0x0012}, -{0x88b4, 0x0004}, {0x88b5, 0x0032}, {0x88b6, 0x00b7}, -{0x88b7, 0x0012}, {0x88b8, 0x0007}, {0x88b9, 0x00b6}, -{0x88ba, 0x0012}, {0x88bb, 0x0000}, {0x88bc, 0x0084}, -{0x88bd, 0x0008}, {0x88be, 0x0081}, {0x88bf, 0x0008}, -{0x88c0, 0x0027}, {0x88c1, 0x000f}, {0x88c2, 0x007c}, -{0x88c3, 0x0082}, {0x88c4, 0x0008}, {0x88c5, 0x0026}, -{0x88c6, 0x0007}, {0x88c7, 0x0086}, {0x88c8, 0x0076}, -{0x88c9, 0x0097}, {0x88ca, 0x0040}, {0x88cb, 0x007e}, -{0x88cc, 0x0089}, {0x88cd, 0x006e}, {0x88ce, 0x007e}, -{0x88cf, 0x0086}, {0x88d0, 0x00ec}, {0x88d1, 0x00b6}, -{0x88d2, 0x008f}, {0x88d3, 0x007f}, {0x88d4, 0x0081}, -{0x88d5, 0x000f}, {0x88d6, 0x0027}, {0x88d7, 0x003c}, -{0x88d8, 0x00bd}, {0x88d9, 0x00e6}, {0x88da, 0x00c7}, -{0x88db, 0x00b7}, {0x88dc, 0x0012}, {0x88dd, 0x000d}, -{0x88de, 0x00bd}, {0x88df, 0x00e6}, {0x88e0, 0x00cb}, -{0x88e1, 0x00b6}, {0x88e2, 0x0012}, {0x88e3, 0x0004}, -{0x88e4, 0x008a}, {0x88e5, 0x0020}, {0x88e6, 0x00b7}, -{0x88e7, 0x0012}, {0x88e8, 0x0004}, {0x88e9, 0x00ce}, -{0x88ea, 0x00ff}, {0x88eb, 0x00ff}, {0x88ec, 0x00b6}, -{0x88ed, 0x0012}, {0x88ee, 0x0000}, {0x88ef, 0x0081}, -{0x88f0, 0x000c}, {0x88f1, 0x0026}, {0x88f2, 0x0005}, -{0x88f3, 0x0009}, {0x88f4, 0x0026}, {0x88f5, 0x00f6}, -{0x88f6, 0x0027}, {0x88f7, 0x001c}, {0x88f8, 0x00b6}, -{0x88f9, 0x0012}, {0x88fa, 0x0004}, {0x88fb, 0x0084}, -{0x88fc, 0x00df}, {0x88fd, 0x00b7}, {0x88fe, 0x0012}, -{0x88ff, 0x0004}, {0x8900, 0x0096}, {0x8901, 0x0083}, -{0x8902, 0x0081}, {0x8903, 0x0007}, {0x8904, 0x002c}, -{0x8905, 0x0005}, {0x8906, 0x007c}, {0x8907, 0x0000}, -{0x8908, 0x0083}, {0x8909, 0x0020}, {0x890a, 0x0006}, -{0x890b, 0x0096}, {0x890c, 0x0083}, {0x890d, 0x008b}, -{0x890e, 0x0008}, {0x890f, 0x0097}, {0x8910, 0x0083}, -{0x8911, 0x007e}, {0x8912, 0x0085}, {0x8913, 0x0041}, -{0x8914, 0x007f}, {0x8915, 0x008f}, {0x8916, 0x007e}, -{0x8917, 0x0086}, {0x8918, 0x0080}, {0x8919, 0x00b7}, -{0x891a, 0x0012}, {0x891b, 0x000c}, {0x891c, 0x0086}, -{0x891d, 0x0001}, {0x891e, 0x00b7}, {0x891f, 0x008f}, -{0x8920, 0x007d}, {0x8921, 0x00b6}, {0x8922, 0x0012}, -{0x8923, 0x000c}, {0x8924, 0x0084}, {0x8925, 0x007f}, -{0x8926, 0x00b7}, {0x8927, 0x0012}, {0x8928, 0x000c}, -{0x8929, 0x008a}, {0x892a, 0x0080}, {0x892b, 0x00b7}, -{0x892c, 0x0012}, {0x892d, 0x000c}, {0x892e, 0x0086}, -{0x892f, 0x000a}, {0x8930, 0x00bd}, {0x8931, 0x008a}, -{0x8932, 0x0006}, {0x8933, 0x00b6}, {0x8934, 0x0012}, -{0x8935, 0x000a}, {0x8936, 0x002a}, {0x8937, 0x0009}, -{0x8938, 0x00b6}, {0x8939, 0x0012}, {0x893a, 0x000c}, -{0x893b, 0x00ba}, {0x893c, 0x008f}, {0x893d, 0x007d}, -{0x893e, 0x00b7}, {0x893f, 0x0012}, {0x8940, 0x000c}, -{0x8941, 0x00b6}, {0x8942, 0x008f}, {0x8943, 0x007e}, -{0x8944, 0x0081}, {0x8945, 0x0060}, {0x8946, 0x0027}, -{0x8947, 0x001a}, {0x8948, 0x008b}, {0x8949, 0x0020}, -{0x894a, 0x00b7}, {0x894b, 0x008f}, {0x894c, 0x007e}, -{0x894d, 0x00b6}, {0x894e, 0x0012}, {0x894f, 0x000c}, -{0x8950, 0x0084}, {0x8951, 0x009f}, {0x8952, 0x00ba}, -{0x8953, 0x008f}, {0x8954, 0x007e}, {0x8955, 0x00b7}, -{0x8956, 0x0012}, {0x8957, 0x000c}, {0x8958, 0x00b6}, -{0x8959, 0x008f}, {0x895a, 0x007d}, {0x895b, 0x0048}, -{0x895c, 0x00b7}, {0x895d, 0x008f}, {0x895e, 0x007d}, -{0x895f, 0x007e}, {0x8960, 0x0089}, {0x8961, 0x0021}, -{0x8962, 0x00b6}, {0x8963, 0x0012}, {0x8964, 0x0004}, -{0x8965, 0x008a}, {0x8966, 0x0020}, {0x8967, 0x00b7}, -{0x8968, 0x0012}, {0x8969, 0x0004}, {0x896a, 0x00bd}, -{0x896b, 0x008a}, {0x896c, 0x000a}, {0x896d, 0x004f}, -{0x896e, 0x0039}, {0x896f, 0x00a6}, {0x8970, 0x0000}, -{0x8971, 0x0018}, {0x8972, 0x00a7}, {0x8973, 0x0000}, -{0x8974, 0x0008}, {0x8975, 0x0018}, {0x8976, 0x0008}, -{0x8977, 0x005a}, {0x8978, 0x0026}, {0x8979, 0x00f5}, -{0x897a, 0x0039}, {0x897b, 0x0036}, {0x897c, 0x006c}, -{0x897d, 0x0000}, {0x897e, 0x0032}, {0x897f, 0x00ba}, -{0x8980, 0x008f}, {0x8981, 0x007f}, {0x8982, 0x00b7}, -{0x8983, 0x008f}, {0x8984, 0x007f}, {0x8985, 0x00b6}, -{0x8986, 0x0012}, {0x8987, 0x0009}, {0x8988, 0x0084}, -{0x8989, 0x0003}, {0x898a, 0x00a7}, {0x898b, 0x0001}, -{0x898c, 0x00b6}, {0x898d, 0x0012}, {0x898e, 0x0006}, -{0x898f, 0x0084}, {0x8990, 0x003f}, {0x8991, 0x00a7}, -{0x8992, 0x0002}, {0x8993, 0x0039}, {0x8994, 0x0036}, -{0x8995, 0x0086}, {0x8996, 0x0003}, {0x8997, 0x00b7}, -{0x8998, 0x008f}, {0x8999, 0x0080}, {0x899a, 0x0032}, -{0x899b, 0x00c1}, {0x899c, 0x0000}, {0x899d, 0x0026}, -{0x899e, 0x0006}, {0x899f, 0x00b7}, {0x89a0, 0x008f}, -{0x89a1, 0x007c}, {0x89a2, 0x007e}, {0x89a3, 0x0089}, -{0x89a4, 0x00c9}, {0x89a5, 0x00c1}, {0x89a6, 0x0001}, -{0x89a7, 0x0027}, {0x89a8, 0x0018}, {0x89a9, 0x00c1}, -{0x89aa, 0x0002}, {0x89ab, 0x0027}, {0x89ac, 0x000c}, -{0x89ad, 0x00c1}, {0x89ae, 0x0003}, {0x89af, 0x0027}, -{0x89b0, 0x0000}, {0x89b1, 0x00f6}, {0x89b2, 0x008f}, -{0x89b3, 0x0080}, {0x89b4, 0x0005}, {0x89b5, 0x0005}, -{0x89b6, 0x00f7}, {0x89b7, 0x008f}, {0x89b8, 0x0080}, -{0x89b9, 0x00f6}, {0x89ba, 0x008f}, {0x89bb, 0x0080}, -{0x89bc, 0x0005}, {0x89bd, 0x0005}, {0x89be, 0x00f7}, -{0x89bf, 0x008f}, {0x89c0, 0x0080}, {0x89c1, 0x00f6}, -{0x89c2, 0x008f}, {0x89c3, 0x0080}, {0x89c4, 0x0005}, -{0x89c5, 0x0005}, {0x89c6, 0x00f7}, {0x89c7, 0x008f}, -{0x89c8, 0x0080}, {0x89c9, 0x00f6}, {0x89ca, 0x008f}, -{0x89cb, 0x0080}, {0x89cc, 0x0053}, {0x89cd, 0x00f4}, -{0x89ce, 0x0012}, {0x89cf, 0x0007}, {0x89d0, 0x001b}, -{0x89d1, 0x00b7}, {0x89d2, 0x0012}, {0x89d3, 0x0007}, -{0x89d4, 0x0039}, {0x89d5, 0x00ce}, {0x89d6, 0x008f}, -{0x89d7, 0x0070}, {0x89d8, 0x00a6}, {0x89d9, 0x0000}, -{0x89da, 0x0018}, {0x89db, 0x00e6}, {0x89dc, 0x0000}, -{0x89dd, 0x0018}, {0x89de, 0x00a7}, {0x89df, 0x0000}, -{0x89e0, 0x00e7}, {0x89e1, 0x0000}, {0x89e2, 0x00a6}, -{0x89e3, 0x0001}, {0x89e4, 0x0018}, {0x89e5, 0x00e6}, -{0x89e6, 0x0001}, {0x89e7, 0x0018}, {0x89e8, 0x00a7}, -{0x89e9, 0x0001}, {0x89ea, 0x00e7}, {0x89eb, 0x0001}, -{0x89ec, 0x00a6}, {0x89ed, 0x0002}, {0x89ee, 0x0018}, -{0x89ef, 0x00e6}, {0x89f0, 0x0002}, {0x89f1, 0x0018}, -{0x89f2, 0x00a7}, {0x89f3, 0x0002}, {0x89f4, 0x00e7}, -{0x89f5, 0x0002}, {0x89f6, 0x0039}, {0x89f7, 0x00a6}, -{0x89f8, 0x0000}, {0x89f9, 0x0084}, {0x89fa, 0x0007}, -{0x89fb, 0x00e6}, {0x89fc, 0x0000}, {0x89fd, 0x00c4}, -{0x89fe, 0x0038}, {0x89ff, 0x0054}, {0x8a00, 0x0054}, -{0x8a01, 0x0054}, {0x8a02, 0x001b}, {0x8a03, 0x00a7}, -{0x8a04, 0x0000}, {0x8a05, 0x0039}, {0x8a06, 0x004a}, -{0x8a07, 0x0026}, {0x8a08, 0x00fd}, {0x8a09, 0x0039}, -{0x8a0a, 0x0096}, {0x8a0b, 0x0022}, {0x8a0c, 0x0084}, -{0x8a0d, 0x000f}, {0x8a0e, 0x0097}, {0x8a0f, 0x0022}, -{0x8a10, 0x0086}, {0x8a11, 0x0001}, {0x8a12, 0x00b7}, -{0x8a13, 0x008f}, {0x8a14, 0x0070}, {0x8a15, 0x00b6}, -{0x8a16, 0x0012}, {0x8a17, 0x0007}, {0x8a18, 0x00b7}, -{0x8a19, 0x008f}, {0x8a1a, 0x0071}, {0x8a1b, 0x00f6}, -{0x8a1c, 0x0012}, {0x8a1d, 0x000c}, {0x8a1e, 0x00c4}, -{0x8a1f, 0x000f}, {0x8a20, 0x00c8}, {0x8a21, 0x000f}, -{0x8a22, 0x00f7}, {0x8a23, 0x008f}, {0x8a24, 0x0072}, -{0x8a25, 0x00f6}, {0x8a26, 0x008f}, {0x8a27, 0x0072}, -{0x8a28, 0x00b6}, {0x8a29, 0x008f}, {0x8a2a, 0x0071}, -{0x8a2b, 0x0084}, {0x8a2c, 0x0003}, {0x8a2d, 0x0027}, -{0x8a2e, 0x0014}, {0x8a2f, 0x0081}, {0x8a30, 0x0001}, -{0x8a31, 0x0027}, {0x8a32, 0x001c}, {0x8a33, 0x0081}, -{0x8a34, 0x0002}, {0x8a35, 0x0027}, {0x8a36, 0x0024}, -{0x8a37, 0x00f4}, {0x8a38, 0x008f}, {0x8a39, 0x0070}, -{0x8a3a, 0x0027}, {0x8a3b, 0x002a}, {0x8a3c, 0x0096}, -{0x8a3d, 0x0022}, {0x8a3e, 0x008a}, {0x8a3f, 0x0080}, -{0x8a40, 0x007e}, {0x8a41, 0x008a}, {0x8a42, 0x0064}, -{0x8a43, 0x00f4}, {0x8a44, 0x008f}, {0x8a45, 0x0070}, -{0x8a46, 0x0027}, {0x8a47, 0x001e}, {0x8a48, 0x0096}, -{0x8a49, 0x0022}, {0x8a4a, 0x008a}, {0x8a4b, 0x0010}, -{0x8a4c, 0x007e}, {0x8a4d, 0x008a}, {0x8a4e, 0x0064}, -{0x8a4f, 0x00f4}, {0x8a50, 0x008f}, {0x8a51, 0x0070}, -{0x8a52, 0x0027}, {0x8a53, 0x0012}, {0x8a54, 0x0096}, -{0x8a55, 0x0022}, {0x8a56, 0x008a}, {0x8a57, 0x0020}, -{0x8a58, 0x007e}, {0x8a59, 0x008a}, {0x8a5a, 0x0064}, -{0x8a5b, 0x00f4}, {0x8a5c, 0x008f}, {0x8a5d, 0x0070}, -{0x8a5e, 0x0027}, {0x8a5f, 0x0006}, {0x8a60, 0x0096}, -{0x8a61, 0x0022}, {0x8a62, 0x008a}, {0x8a63, 0x0040}, -{0x8a64, 0x0097}, {0x8a65, 0x0022}, {0x8a66, 0x0074}, -{0x8a67, 0x008f}, {0x8a68, 0x0071}, {0x8a69, 0x0074}, -{0x8a6a, 0x008f}, {0x8a6b, 0x0071}, {0x8a6c, 0x0078}, -{0x8a6d, 0x008f}, {0x8a6e, 0x0070}, {0x8a6f, 0x00b6}, -{0x8a70, 0x008f}, {0x8a71, 0x0070}, {0x8a72, 0x0085}, -{0x8a73, 0x0010}, {0x8a74, 0x0027}, {0x8a75, 0x00af}, -{0x8a76, 0x00d6}, {0x8a77, 0x0022}, {0x8a78, 0x00c4}, -{0x8a79, 0x0010}, {0x8a7a, 0x0058}, {0x8a7b, 0x00b6}, -{0x8a7c, 0x0012}, {0x8a7d, 0x0070}, {0x8a7e, 0x0081}, -{0x8a7f, 0x00e4}, {0x8a80, 0x0027}, {0x8a81, 0x0036}, -{0x8a82, 0x0081}, {0x8a83, 0x00e1}, {0x8a84, 0x0026}, -{0x8a85, 0x000c}, {0x8a86, 0x0096}, {0x8a87, 0x0022}, -{0x8a88, 0x0084}, {0x8a89, 0x0020}, {0x8a8a, 0x0044}, -{0x8a8b, 0x001b}, {0x8a8c, 0x00d6}, {0x8a8d, 0x0022}, -{0x8a8e, 0x00c4}, {0x8a8f, 0x00cf}, {0x8a90, 0x0020}, -{0x8a91, 0x0023}, {0x8a92, 0x0058}, {0x8a93, 0x0081}, -{0x8a94, 0x00c6}, {0x8a95, 0x0026}, {0x8a96, 0x000d}, -{0x8a97, 0x0096}, {0x8a98, 0x0022}, {0x8a99, 0x0084}, -{0x8a9a, 0x0040}, {0x8a9b, 0x0044}, {0x8a9c, 0x0044}, -{0x8a9d, 0x001b}, {0x8a9e, 0x00d6}, {0x8a9f, 0x0022}, -{0x8aa0, 0x00c4}, {0x8aa1, 0x00af}, {0x8aa2, 0x0020}, -{0x8aa3, 0x0011}, {0x8aa4, 0x0058}, {0x8aa5, 0x0081}, -{0x8aa6, 0x0027}, {0x8aa7, 0x0026}, {0x8aa8, 0x000f}, -{0x8aa9, 0x0096}, {0x8aaa, 0x0022}, {0x8aab, 0x0084}, -{0x8aac, 0x0080}, {0x8aad, 0x0044}, {0x8aae, 0x0044}, -{0x8aaf, 0x0044}, {0x8ab0, 0x001b}, {0x8ab1, 0x00d6}, -{0x8ab2, 0x0022}, {0x8ab3, 0x00c4}, {0x8ab4, 0x006f}, -{0x8ab5, 0x001b}, {0x8ab6, 0x0097}, {0x8ab7, 0x0022}, -{0x8ab8, 0x0039}, {0x8ab9, 0x0027}, {0x8aba, 0x000c}, -{0x8abb, 0x007c}, {0x8abc, 0x0082}, {0x8abd, 0x0006}, -{0x8abe, 0x00bd}, {0x8abf, 0x00d9}, {0x8ac0, 0x00ed}, -{0x8ac1, 0x00b6}, {0x8ac2, 0x0082}, {0x8ac3, 0x0007}, -{0x8ac4, 0x007e}, {0x8ac5, 0x008a}, {0x8ac6, 0x00b9}, -{0x8ac7, 0x007f}, {0x8ac8, 0x0082}, {0x8ac9, 0x0006}, -{0x8aca, 0x0039}, { 0x0, 0x0 } -}; -#else -cas_saturn_patch_t cas_saturn_patch[] = { -{0x8200, 0x007e}, {0x8201, 0x0082}, {0x8202, 0x0009}, -{0x8203, 0x0000}, {0x8204, 0x0000}, {0x8205, 0x0000}, -{0x8206, 0x0000}, {0x8207, 0x0000}, {0x8208, 0x0000}, -{0x8209, 0x008e}, {0x820a, 0x008e}, {0x820b, 0x00ff}, -{0x820c, 0x00ce}, {0x820d, 0x0082}, {0x820e, 0x0025}, -{0x820f, 0x00ff}, {0x8210, 0x0001}, {0x8211, 0x000f}, -{0x8212, 0x00ce}, {0x8213, 0x0084}, {0x8214, 0x0026}, -{0x8215, 0x00ff}, {0x8216, 0x0001}, {0x8217, 0x0011}, -{0x8218, 0x00ce}, {0x8219, 0x0085}, {0x821a, 0x003d}, -{0x821b, 0x00df}, {0x821c, 0x00e5}, {0x821d, 0x0086}, -{0x821e, 0x0039}, {0x821f, 0x00b7}, {0x8220, 0x008f}, -{0x8221, 0x00f8}, {0x8222, 0x007e}, {0x8223, 0x00c3}, -{0x8224, 0x00c2}, {0x8225, 0x0096}, {0x8226, 0x0047}, -{0x8227, 0x0084}, {0x8228, 0x00f3}, {0x8229, 0x008a}, -{0x822a, 0x0000}, {0x822b, 0x0097}, {0x822c, 0x0047}, -{0x822d, 0x00ce}, {0x822e, 0x0082}, {0x822f, 0x0033}, -{0x8230, 0x00ff}, {0x8231, 0x0001}, {0x8232, 0x000f}, -{0x8233, 0x0096}, {0x8234, 0x0046}, {0x8235, 0x0084}, -{0x8236, 0x000c}, {0x8237, 0x0081}, {0x8238, 0x0004}, -{0x8239, 0x0027}, {0x823a, 0x000b}, {0x823b, 0x0096}, -{0x823c, 0x0046}, {0x823d, 0x0084}, {0x823e, 0x000c}, -{0x823f, 0x0081}, {0x8240, 0x0008}, {0x8241, 0x0027}, -{0x8242, 0x0057}, {0x8243, 0x007e}, {0x8244, 0x0084}, -{0x8245, 0x0025}, {0x8246, 0x0096}, {0x8247, 0x0047}, -{0x8248, 0x0084}, {0x8249, 0x00f3}, {0x824a, 0x008a}, -{0x824b, 0x0004}, {0x824c, 0x0097}, {0x824d, 0x0047}, -{0x824e, 0x00ce}, {0x824f, 0x0082}, {0x8250, 0x0054}, -{0x8251, 0x00ff}, {0x8252, 0x0001}, {0x8253, 0x000f}, -{0x8254, 0x0096}, {0x8255, 0x0046}, {0x8256, 0x0084}, -{0x8257, 0x000c}, {0x8258, 0x0081}, {0x8259, 0x0004}, -{0x825a, 0x0026}, {0x825b, 0x0038}, {0x825c, 0x00b6}, -{0x825d, 0x0012}, {0x825e, 0x0020}, {0x825f, 0x0084}, -{0x8260, 0x0020}, {0x8261, 0x0026}, {0x8262, 0x0003}, -{0x8263, 0x007e}, {0x8264, 0x0084}, {0x8265, 0x0025}, -{0x8266, 0x0096}, {0x8267, 0x007b}, {0x8268, 0x00d6}, -{0x8269, 0x007c}, {0x826a, 0x00fe}, {0x826b, 0x008f}, -{0x826c, 0x0056}, {0x826d, 0x00bd}, {0x826e, 0x00f7}, -{0x826f, 0x00b6}, {0x8270, 0x00fe}, {0x8271, 0x008f}, -{0x8272, 0x004e}, {0x8273, 0x00bd}, {0x8274, 0x00ec}, -{0x8275, 0x008e}, {0x8276, 0x00bd}, {0x8277, 0x00fa}, -{0x8278, 0x00f7}, {0x8279, 0x00bd}, {0x827a, 0x00f7}, -{0x827b, 0x0028}, {0x827c, 0x00ce}, {0x827d, 0x0082}, -{0x827e, 0x0082}, {0x827f, 0x00ff}, {0x8280, 0x0001}, -{0x8281, 0x000f}, {0x8282, 0x0096}, {0x8283, 0x0046}, -{0x8284, 0x0084}, {0x8285, 0x000c}, {0x8286, 0x0081}, -{0x8287, 0x0004}, {0x8288, 0x0026}, {0x8289, 0x000a}, -{0x828a, 0x00b6}, {0x828b, 0x0012}, {0x828c, 0x0020}, -{0x828d, 0x0084}, {0x828e, 0x0020}, {0x828f, 0x0027}, -{0x8290, 0x00b5}, {0x8291, 0x007e}, {0x8292, 0x0084}, -{0x8293, 0x0025}, {0x8294, 0x00bd}, {0x8295, 0x00f7}, -{0x8296, 0x001f}, {0x8297, 0x007e}, {0x8298, 0x0084}, -{0x8299, 0x001f}, {0x829a, 0x0096}, {0x829b, 0x0047}, -{0x829c, 0x0084}, {0x829d, 0x00f3}, {0x829e, 0x008a}, -{0x829f, 0x0008}, {0x82a0, 0x0097}, {0x82a1, 0x0047}, -{0x82a2, 0x00de}, {0x82a3, 0x00e1}, {0x82a4, 0x00ad}, -{0x82a5, 0x0000}, {0x82a6, 0x00ce}, {0x82a7, 0x0082}, -{0x82a8, 0x00af}, {0x82a9, 0x00ff}, {0x82aa, 0x0001}, -{0x82ab, 0x000f}, {0x82ac, 0x007e}, {0x82ad, 0x0084}, -{0x82ae, 0x0025}, {0x82af, 0x0096}, {0x82b0, 0x0041}, -{0x82b1, 0x0085}, {0x82b2, 0x0010}, {0x82b3, 0x0026}, -{0x82b4, 0x0006}, {0x82b5, 0x0096}, {0x82b6, 0x0023}, -{0x82b7, 0x0085}, {0x82b8, 0x0040}, {0x82b9, 0x0027}, -{0x82ba, 0x0006}, {0x82bb, 0x00bd}, {0x82bc, 0x00ed}, -{0x82bd, 0x0000}, {0x82be, 0x007e}, {0x82bf, 0x0083}, -{0x82c0, 0x00a2}, {0x82c1, 0x00de}, {0x82c2, 0x0042}, -{0x82c3, 0x00bd}, {0x82c4, 0x00eb}, {0x82c5, 0x008e}, -{0x82c6, 0x0096}, {0x82c7, 0x0024}, {0x82c8, 0x0084}, -{0x82c9, 0x0008}, {0x82ca, 0x0027}, {0x82cb, 0x0003}, -{0x82cc, 0x007e}, {0x82cd, 0x0083}, {0x82ce, 0x00df}, -{0x82cf, 0x0096}, {0x82d0, 0x007b}, {0x82d1, 0x00d6}, -{0x82d2, 0x007c}, {0x82d3, 0x00fe}, {0x82d4, 0x008f}, -{0x82d5, 0x0056}, {0x82d6, 0x00bd}, {0x82d7, 0x00f7}, -{0x82d8, 0x00b6}, {0x82d9, 0x00fe}, {0x82da, 0x008f}, -{0x82db, 0x0050}, {0x82dc, 0x00bd}, {0x82dd, 0x00ec}, -{0x82de, 0x008e}, {0x82df, 0x00bd}, {0x82e0, 0x00fa}, -{0x82e1, 0x00f7}, {0x82e2, 0x0086}, {0x82e3, 0x0011}, -{0x82e4, 0x00c6}, {0x82e5, 0x0049}, {0x82e6, 0x00bd}, -{0x82e7, 0x00e4}, {0x82e8, 0x0012}, {0x82e9, 0x00ce}, -{0x82ea, 0x0082}, {0x82eb, 0x00ef}, {0x82ec, 0x00ff}, -{0x82ed, 0x0001}, {0x82ee, 0x000f}, {0x82ef, 0x0096}, -{0x82f0, 0x0046}, {0x82f1, 0x0084}, {0x82f2, 0x000c}, -{0x82f3, 0x0081}, {0x82f4, 0x0000}, {0x82f5, 0x0027}, -{0x82f6, 0x0017}, {0x82f7, 0x00c6}, {0x82f8, 0x0049}, -{0x82f9, 0x00bd}, {0x82fa, 0x00e4}, {0x82fb, 0x0091}, -{0x82fc, 0x0024}, {0x82fd, 0x000d}, {0x82fe, 0x00b6}, -{0x82ff, 0x0012}, {0x8300, 0x0020}, {0x8301, 0x0085}, -{0x8302, 0x0020}, {0x8303, 0x0026}, {0x8304, 0x000c}, -{0x8305, 0x00ce}, {0x8306, 0x0082}, {0x8307, 0x00c1}, -{0x8308, 0x00ff}, {0x8309, 0x0001}, {0x830a, 0x000f}, -{0x830b, 0x007e}, {0x830c, 0x0084}, {0x830d, 0x0025}, -{0x830e, 0x007e}, {0x830f, 0x0084}, {0x8310, 0x0016}, -{0x8311, 0x00fe}, {0x8312, 0x008f}, {0x8313, 0x0052}, -{0x8314, 0x00bd}, {0x8315, 0x00ec}, {0x8316, 0x008e}, -{0x8317, 0x00bd}, {0x8318, 0x00fa}, {0x8319, 0x00f7}, -{0x831a, 0x0086}, {0x831b, 0x006a}, {0x831c, 0x00c6}, -{0x831d, 0x0049}, {0x831e, 0x00bd}, {0x831f, 0x00e4}, -{0x8320, 0x0012}, {0x8321, 0x00ce}, {0x8322, 0x0083}, -{0x8323, 0x0027}, {0x8324, 0x00ff}, {0x8325, 0x0001}, -{0x8326, 0x000f}, {0x8327, 0x0096}, {0x8328, 0x0046}, -{0x8329, 0x0084}, {0x832a, 0x000c}, {0x832b, 0x0081}, -{0x832c, 0x0000}, {0x832d, 0x0027}, {0x832e, 0x000a}, -{0x832f, 0x00c6}, {0x8330, 0x0049}, {0x8331, 0x00bd}, -{0x8332, 0x00e4}, {0x8333, 0x0091}, {0x8334, 0x0025}, -{0x8335, 0x0006}, {0x8336, 0x007e}, {0x8337, 0x0084}, -{0x8338, 0x0025}, {0x8339, 0x007e}, {0x833a, 0x0084}, -{0x833b, 0x0016}, {0x833c, 0x00b6}, {0x833d, 0x0018}, -{0x833e, 0x0070}, {0x833f, 0x00bb}, {0x8340, 0x0019}, -{0x8341, 0x0070}, {0x8342, 0x002a}, {0x8343, 0x0004}, -{0x8344, 0x0081}, {0x8345, 0x00af}, {0x8346, 0x002e}, -{0x8347, 0x0019}, {0x8348, 0x0096}, {0x8349, 0x007b}, -{0x834a, 0x00f6}, {0x834b, 0x0020}, {0x834c, 0x0007}, -{0x834d, 0x00fa}, {0x834e, 0x0020}, {0x834f, 0x0027}, -{0x8350, 0x00c4}, {0x8351, 0x0038}, {0x8352, 0x0081}, -{0x8353, 0x0038}, {0x8354, 0x0027}, {0x8355, 0x000b}, -{0x8356, 0x00f6}, {0x8357, 0x0020}, {0x8358, 0x0007}, -{0x8359, 0x00fa}, {0x835a, 0x0020}, {0x835b, 0x0027}, -{0x835c, 0x00cb}, {0x835d, 0x0008}, {0x835e, 0x007e}, -{0x835f, 0x0082}, {0x8360, 0x00d3}, {0x8361, 0x00bd}, -{0x8362, 0x00f7}, {0x8363, 0x0066}, {0x8364, 0x0086}, -{0x8365, 0x0074}, {0x8366, 0x00c6}, {0x8367, 0x0049}, -{0x8368, 0x00bd}, {0x8369, 0x00e4}, {0x836a, 0x0012}, -{0x836b, 0x00ce}, {0x836c, 0x0083}, {0x836d, 0x0071}, -{0x836e, 0x00ff}, {0x836f, 0x0001}, {0x8370, 0x000f}, -{0x8371, 0x0096}, {0x8372, 0x0046}, {0x8373, 0x0084}, -{0x8374, 0x000c}, {0x8375, 0x0081}, {0x8376, 0x0008}, -{0x8377, 0x0026}, {0x8378, 0x000a}, {0x8379, 0x00c6}, -{0x837a, 0x0049}, {0x837b, 0x00bd}, {0x837c, 0x00e4}, -{0x837d, 0x0091}, {0x837e, 0x0025}, {0x837f, 0x0006}, -{0x8380, 0x007e}, {0x8381, 0x0084}, {0x8382, 0x0025}, -{0x8383, 0x007e}, {0x8384, 0x0084}, {0x8385, 0x0016}, -{0x8386, 0x00bd}, {0x8387, 0x00f7}, {0x8388, 0x003e}, -{0x8389, 0x0026}, {0x838a, 0x000e}, {0x838b, 0x00bd}, -{0x838c, 0x00e5}, {0x838d, 0x0009}, {0x838e, 0x0026}, -{0x838f, 0x0006}, {0x8390, 0x00ce}, {0x8391, 0x0082}, -{0x8392, 0x00c1}, {0x8393, 0x00ff}, {0x8394, 0x0001}, -{0x8395, 0x000f}, {0x8396, 0x007e}, {0x8397, 0x0084}, -{0x8398, 0x0025}, {0x8399, 0x00fe}, {0x839a, 0x008f}, -{0x839b, 0x0054}, {0x839c, 0x00bd}, {0x839d, 0x00ec}, -{0x839e, 0x008e}, {0x839f, 0x00bd}, {0x83a0, 0x00fa}, -{0x83a1, 0x00f7}, {0x83a2, 0x00bd}, {0x83a3, 0x00f7}, -{0x83a4, 0x0033}, {0x83a5, 0x0086}, {0x83a6, 0x000f}, -{0x83a7, 0x00c6}, {0x83a8, 0x0051}, {0x83a9, 0x00bd}, -{0x83aa, 0x00e4}, {0x83ab, 0x0012}, {0x83ac, 0x00ce}, -{0x83ad, 0x0083}, {0x83ae, 0x00b2}, {0x83af, 0x00ff}, -{0x83b0, 0x0001}, {0x83b1, 0x000f}, {0x83b2, 0x0096}, -{0x83b3, 0x0046}, {0x83b4, 0x0084}, {0x83b5, 0x000c}, -{0x83b6, 0x0081}, {0x83b7, 0x0008}, {0x83b8, 0x0026}, -{0x83b9, 0x005c}, {0x83ba, 0x00b6}, {0x83bb, 0x0012}, -{0x83bc, 0x0020}, {0x83bd, 0x0084}, {0x83be, 0x003f}, -{0x83bf, 0x0081}, {0x83c0, 0x003a}, {0x83c1, 0x0027}, -{0x83c2, 0x001c}, {0x83c3, 0x0096}, {0x83c4, 0x0023}, -{0x83c5, 0x0085}, {0x83c6, 0x0040}, {0x83c7, 0x0027}, -{0x83c8, 0x0003}, {0x83c9, 0x007e}, {0x83ca, 0x0084}, -{0x83cb, 0x0025}, {0x83cc, 0x00c6}, {0x83cd, 0x0051}, -{0x83ce, 0x00bd}, {0x83cf, 0x00e4}, {0x83d0, 0x0091}, -{0x83d1, 0x0025}, {0x83d2, 0x0003}, {0x83d3, 0x007e}, -{0x83d4, 0x0084}, {0x83d5, 0x0025}, {0x83d6, 0x00ce}, -{0x83d7, 0x0082}, {0x83d8, 0x00c1}, {0x83d9, 0x00ff}, -{0x83da, 0x0001}, {0x83db, 0x000f}, {0x83dc, 0x007e}, -{0x83dd, 0x0084}, {0x83de, 0x0025}, {0x83df, 0x00bd}, -{0x83e0, 0x00f8}, {0x83e1, 0x0037}, {0x83e2, 0x007c}, -{0x83e3, 0x0000}, {0x83e4, 0x007a}, {0x83e5, 0x00ce}, -{0x83e6, 0x0083}, {0x83e7, 0x00ee}, {0x83e8, 0x00ff}, -{0x83e9, 0x0001}, {0x83ea, 0x000f}, {0x83eb, 0x007e}, -{0x83ec, 0x0084}, {0x83ed, 0x0025}, {0x83ee, 0x0096}, -{0x83ef, 0x0046}, {0x83f0, 0x0084}, {0x83f1, 0x000c}, -{0x83f2, 0x0081}, {0x83f3, 0x0008}, {0x83f4, 0x0026}, -{0x83f5, 0x0020}, {0x83f6, 0x0096}, {0x83f7, 0x0024}, -{0x83f8, 0x0084}, {0x83f9, 0x0008}, {0x83fa, 0x0026}, -{0x83fb, 0x0029}, {0x83fc, 0x00b6}, {0x83fd, 0x0018}, -{0x83fe, 0x0082}, {0x83ff, 0x00bb}, {0x8400, 0x0019}, -{0x8401, 0x0082}, {0x8402, 0x00b1}, {0x8403, 0x0001}, -{0x8404, 0x003b}, {0x8405, 0x0022}, {0x8406, 0x0009}, -{0x8407, 0x00b6}, {0x8408, 0x0012}, {0x8409, 0x0020}, -{0x840a, 0x0084}, {0x840b, 0x0037}, {0x840c, 0x0081}, -{0x840d, 0x0032}, {0x840e, 0x0027}, {0x840f, 0x0015}, -{0x8410, 0x00bd}, {0x8411, 0x00f8}, {0x8412, 0x0044}, -{0x8413, 0x007e}, {0x8414, 0x0082}, {0x8415, 0x00c1}, -{0x8416, 0x00bd}, {0x8417, 0x00f7}, {0x8418, 0x001f}, -{0x8419, 0x00bd}, {0x841a, 0x00f8}, {0x841b, 0x0044}, -{0x841c, 0x00bd}, {0x841d, 0x00fc}, {0x841e, 0x0029}, -{0x841f, 0x00ce}, {0x8420, 0x0082}, {0x8421, 0x0025}, -{0x8422, 0x00ff}, {0x8423, 0x0001}, {0x8424, 0x000f}, -{0x8425, 0x0039}, {0x8426, 0x0096}, {0x8427, 0x0047}, -{0x8428, 0x0084}, {0x8429, 0x00fc}, {0x842a, 0x008a}, -{0x842b, 0x0000}, {0x842c, 0x0097}, {0x842d, 0x0047}, -{0x842e, 0x00ce}, {0x842f, 0x0084}, {0x8430, 0x0034}, -{0x8431, 0x00ff}, {0x8432, 0x0001}, {0x8433, 0x0011}, -{0x8434, 0x0096}, {0x8435, 0x0046}, {0x8436, 0x0084}, -{0x8437, 0x0003}, {0x8438, 0x0081}, {0x8439, 0x0002}, -{0x843a, 0x0027}, {0x843b, 0x0003}, {0x843c, 0x007e}, -{0x843d, 0x0085}, {0x843e, 0x001e}, {0x843f, 0x0096}, -{0x8440, 0x0047}, {0x8441, 0x0084}, {0x8442, 0x00fc}, -{0x8443, 0x008a}, {0x8444, 0x0002}, {0x8445, 0x0097}, -{0x8446, 0x0047}, {0x8447, 0x00de}, {0x8448, 0x00e1}, -{0x8449, 0x00ad}, {0x844a, 0x0000}, {0x844b, 0x0086}, -{0x844c, 0x0001}, {0x844d, 0x00b7}, {0x844e, 0x0012}, -{0x844f, 0x0051}, {0x8450, 0x00bd}, {0x8451, 0x00f7}, -{0x8452, 0x0014}, {0x8453, 0x00b6}, {0x8454, 0x0010}, -{0x8455, 0x0031}, {0x8456, 0x0084}, {0x8457, 0x00fd}, -{0x8458, 0x00b7}, {0x8459, 0x0010}, {0x845a, 0x0031}, -{0x845b, 0x00bd}, {0x845c, 0x00f8}, {0x845d, 0x001e}, -{0x845e, 0x0096}, {0x845f, 0x0081}, {0x8460, 0x00d6}, -{0x8461, 0x0082}, {0x8462, 0x00fe}, {0x8463, 0x008f}, -{0x8464, 0x005a}, {0x8465, 0x00bd}, {0x8466, 0x00f7}, -{0x8467, 0x00b6}, {0x8468, 0x00fe}, {0x8469, 0x008f}, -{0x846a, 0x005c}, {0x846b, 0x00bd}, {0x846c, 0x00ec}, -{0x846d, 0x008e}, {0x846e, 0x00bd}, {0x846f, 0x00fa}, -{0x8470, 0x00f7}, {0x8471, 0x0086}, {0x8472, 0x0008}, -{0x8473, 0x00d6}, {0x8474, 0x0000}, {0x8475, 0x00c5}, -{0x8476, 0x0010}, {0x8477, 0x0026}, {0x8478, 0x0002}, -{0x8479, 0x008b}, {0x847a, 0x0020}, {0x847b, 0x00c6}, -{0x847c, 0x0051}, {0x847d, 0x00bd}, {0x847e, 0x00e4}, -{0x847f, 0x0012}, {0x8480, 0x00ce}, {0x8481, 0x0084}, -{0x8482, 0x0086}, {0x8483, 0x00ff}, {0x8484, 0x0001}, -{0x8485, 0x0011}, {0x8486, 0x0096}, {0x8487, 0x0046}, -{0x8488, 0x0084}, {0x8489, 0x0003}, {0x848a, 0x0081}, -{0x848b, 0x0002}, {0x848c, 0x0027}, {0x848d, 0x0003}, -{0x848e, 0x007e}, {0x848f, 0x0085}, {0x8490, 0x000f}, -{0x8491, 0x00c6}, {0x8492, 0x0051}, {0x8493, 0x00bd}, -{0x8494, 0x00e4}, {0x8495, 0x0091}, {0x8496, 0x0025}, -{0x8497, 0x0003}, {0x8498, 0x007e}, {0x8499, 0x0085}, -{0x849a, 0x001e}, {0x849b, 0x0096}, {0x849c, 0x0044}, -{0x849d, 0x0085}, {0x849e, 0x0010}, {0x849f, 0x0026}, -{0x84a0, 0x000a}, {0x84a1, 0x00b6}, {0x84a2, 0x0012}, -{0x84a3, 0x0050}, {0x84a4, 0x00ba}, {0x84a5, 0x0001}, -{0x84a6, 0x003c}, {0x84a7, 0x0085}, {0x84a8, 0x0010}, -{0x84a9, 0x0027}, {0x84aa, 0x00a8}, {0x84ab, 0x00bd}, -{0x84ac, 0x00f7}, {0x84ad, 0x0066}, {0x84ae, 0x00ce}, -{0x84af, 0x0084}, {0x84b0, 0x00b7}, {0x84b1, 0x00ff}, -{0x84b2, 0x0001}, {0x84b3, 0x0011}, {0x84b4, 0x007e}, -{0x84b5, 0x0085}, {0x84b6, 0x001e}, {0x84b7, 0x0096}, -{0x84b8, 0x0046}, {0x84b9, 0x0084}, {0x84ba, 0x0003}, -{0x84bb, 0x0081}, {0x84bc, 0x0002}, {0x84bd, 0x0026}, -{0x84be, 0x0050}, {0x84bf, 0x00b6}, {0x84c0, 0x0012}, -{0x84c1, 0x0030}, {0x84c2, 0x0084}, {0x84c3, 0x0003}, -{0x84c4, 0x0081}, {0x84c5, 0x0001}, {0x84c6, 0x0027}, -{0x84c7, 0x0003}, {0x84c8, 0x007e}, {0x84c9, 0x0085}, -{0x84ca, 0x001e}, {0x84cb, 0x0096}, {0x84cc, 0x0044}, -{0x84cd, 0x0085}, {0x84ce, 0x0010}, {0x84cf, 0x0026}, -{0x84d0, 0x0013}, {0x84d1, 0x00b6}, {0x84d2, 0x0012}, -{0x84d3, 0x0050}, {0x84d4, 0x00ba}, {0x84d5, 0x0001}, -{0x84d6, 0x003c}, {0x84d7, 0x0085}, {0x84d8, 0x0010}, -{0x84d9, 0x0026}, {0x84da, 0x0009}, {0x84db, 0x00ce}, -{0x84dc, 0x0084}, {0x84dd, 0x0053}, {0x84de, 0x00ff}, -{0x84df, 0x0001}, {0x84e0, 0x0011}, {0x84e1, 0x007e}, -{0x84e2, 0x0085}, {0x84e3, 0x001e}, {0x84e4, 0x00b6}, -{0x84e5, 0x0010}, {0x84e6, 0x0031}, {0x84e7, 0x008a}, -{0x84e8, 0x0002}, {0x84e9, 0x00b7}, {0x84ea, 0x0010}, -{0x84eb, 0x0031}, {0x84ec, 0x00bd}, {0x84ed, 0x0085}, -{0x84ee, 0x001f}, {0x84ef, 0x00bd}, {0x84f0, 0x00f8}, -{0x84f1, 0x0037}, {0x84f2, 0x007c}, {0x84f3, 0x0000}, -{0x84f4, 0x0080}, {0x84f5, 0x00ce}, {0x84f6, 0x0084}, -{0x84f7, 0x00fe}, {0x84f8, 0x00ff}, {0x84f9, 0x0001}, -{0x84fa, 0x0011}, {0x84fb, 0x007e}, {0x84fc, 0x0085}, -{0x84fd, 0x001e}, {0x84fe, 0x0096}, {0x84ff, 0x0046}, -{0x8500, 0x0084}, {0x8501, 0x0003}, {0x8502, 0x0081}, -{0x8503, 0x0002}, {0x8504, 0x0026}, {0x8505, 0x0009}, -{0x8506, 0x00b6}, {0x8507, 0x0012}, {0x8508, 0x0030}, -{0x8509, 0x0084}, {0x850a, 0x0003}, {0x850b, 0x0081}, -{0x850c, 0x0001}, {0x850d, 0x0027}, {0x850e, 0x000f}, -{0x850f, 0x00bd}, {0x8510, 0x00f8}, {0x8511, 0x0044}, -{0x8512, 0x00bd}, {0x8513, 0x00f7}, {0x8514, 0x000b}, -{0x8515, 0x00bd}, {0x8516, 0x00fc}, {0x8517, 0x0029}, -{0x8518, 0x00ce}, {0x8519, 0x0084}, {0x851a, 0x0026}, -{0x851b, 0x00ff}, {0x851c, 0x0001}, {0x851d, 0x0011}, -{0x851e, 0x0039}, {0x851f, 0x00d6}, {0x8520, 0x0022}, -{0x8521, 0x00c4}, {0x8522, 0x000f}, {0x8523, 0x00b6}, -{0x8524, 0x0012}, {0x8525, 0x0030}, {0x8526, 0x00ba}, -{0x8527, 0x0012}, {0x8528, 0x0032}, {0x8529, 0x0084}, -{0x852a, 0x0004}, {0x852b, 0x0027}, {0x852c, 0x000d}, -{0x852d, 0x0096}, {0x852e, 0x0022}, {0x852f, 0x0085}, -{0x8530, 0x0004}, {0x8531, 0x0027}, {0x8532, 0x0005}, -{0x8533, 0x00ca}, {0x8534, 0x0010}, {0x8535, 0x007e}, -{0x8536, 0x0085}, {0x8537, 0x003a}, {0x8538, 0x00ca}, -{0x8539, 0x0020}, {0x853a, 0x00d7}, {0x853b, 0x0022}, -{0x853c, 0x0039}, {0x853d, 0x0086}, {0x853e, 0x0000}, -{0x853f, 0x0097}, {0x8540, 0x0083}, {0x8541, 0x0018}, -{0x8542, 0x00ce}, {0x8543, 0x001c}, {0x8544, 0x0000}, -{0x8545, 0x00bd}, {0x8546, 0x00eb}, {0x8547, 0x0046}, -{0x8548, 0x0096}, {0x8549, 0x0057}, {0x854a, 0x0085}, -{0x854b, 0x0001}, {0x854c, 0x0027}, {0x854d, 0x0002}, -{0x854e, 0x004f}, {0x854f, 0x0039}, {0x8550, 0x0085}, -{0x8551, 0x0002}, {0x8552, 0x0027}, {0x8553, 0x0001}, -{0x8554, 0x0039}, {0x8555, 0x007f}, {0x8556, 0x008f}, -{0x8557, 0x007d}, {0x8558, 0x0086}, {0x8559, 0x0004}, -{0x855a, 0x00b7}, {0x855b, 0x0012}, {0x855c, 0x0004}, -{0x855d, 0x0086}, {0x855e, 0x0008}, {0x855f, 0x00b7}, -{0x8560, 0x0012}, {0x8561, 0x0007}, {0x8562, 0x0086}, -{0x8563, 0x0010}, {0x8564, 0x00b7}, {0x8565, 0x0012}, -{0x8566, 0x000c}, {0x8567, 0x0086}, {0x8568, 0x0007}, -{0x8569, 0x00b7}, {0x856a, 0x0012}, {0x856b, 0x0006}, -{0x856c, 0x00b6}, {0x856d, 0x008f}, {0x856e, 0x007d}, -{0x856f, 0x00b7}, {0x8570, 0x0012}, {0x8571, 0x0070}, -{0x8572, 0x0086}, {0x8573, 0x0001}, {0x8574, 0x00ba}, -{0x8575, 0x0012}, {0x8576, 0x0004}, {0x8577, 0x00b7}, -{0x8578, 0x0012}, {0x8579, 0x0004}, {0x857a, 0x0001}, -{0x857b, 0x0001}, {0x857c, 0x0001}, {0x857d, 0x0001}, -{0x857e, 0x0001}, {0x857f, 0x0001}, {0x8580, 0x00b6}, -{0x8581, 0x0012}, {0x8582, 0x0004}, {0x8583, 0x0084}, -{0x8584, 0x00fe}, {0x8585, 0x008a}, {0x8586, 0x0002}, -{0x8587, 0x00b7}, {0x8588, 0x0012}, {0x8589, 0x0004}, -{0x858a, 0x0001}, {0x858b, 0x0001}, {0x858c, 0x0001}, -{0x858d, 0x0001}, {0x858e, 0x0001}, {0x858f, 0x0001}, -{0x8590, 0x0086}, {0x8591, 0x00fd}, {0x8592, 0x00b4}, -{0x8593, 0x0012}, {0x8594, 0x0004}, {0x8595, 0x00b7}, -{0x8596, 0x0012}, {0x8597, 0x0004}, {0x8598, 0x00b6}, -{0x8599, 0x0012}, {0x859a, 0x0000}, {0x859b, 0x0084}, -{0x859c, 0x0008}, {0x859d, 0x0081}, {0x859e, 0x0008}, -{0x859f, 0x0027}, {0x85a0, 0x0016}, {0x85a1, 0x00b6}, -{0x85a2, 0x008f}, {0x85a3, 0x007d}, {0x85a4, 0x0081}, -{0x85a5, 0x000c}, {0x85a6, 0x0027}, {0x85a7, 0x0008}, -{0x85a8, 0x008b}, {0x85a9, 0x0004}, {0x85aa, 0x00b7}, -{0x85ab, 0x008f}, {0x85ac, 0x007d}, {0x85ad, 0x007e}, -{0x85ae, 0x0085}, {0x85af, 0x006c}, {0x85b0, 0x0086}, -{0x85b1, 0x0003}, {0x85b2, 0x0097}, {0x85b3, 0x0040}, -{0x85b4, 0x007e}, {0x85b5, 0x0089}, {0x85b6, 0x006e}, -{0x85b7, 0x0086}, {0x85b8, 0x0007}, {0x85b9, 0x00b7}, -{0x85ba, 0x0012}, {0x85bb, 0x0006}, {0x85bc, 0x005f}, -{0x85bd, 0x00f7}, {0x85be, 0x008f}, {0x85bf, 0x0082}, -{0x85c0, 0x005f}, {0x85c1, 0x00f7}, {0x85c2, 0x008f}, -{0x85c3, 0x007f}, {0x85c4, 0x00f7}, {0x85c5, 0x008f}, -{0x85c6, 0x0070}, {0x85c7, 0x00f7}, {0x85c8, 0x008f}, -{0x85c9, 0x0071}, {0x85ca, 0x00f7}, {0x85cb, 0x008f}, -{0x85cc, 0x0072}, {0x85cd, 0x00f7}, {0x85ce, 0x008f}, -{0x85cf, 0x0073}, {0x85d0, 0x00f7}, {0x85d1, 0x008f}, -{0x85d2, 0x0074}, {0x85d3, 0x00f7}, {0x85d4, 0x008f}, -{0x85d5, 0x0075}, {0x85d6, 0x00f7}, {0x85d7, 0x008f}, -{0x85d8, 0x0076}, {0x85d9, 0x00f7}, {0x85da, 0x008f}, -{0x85db, 0x0077}, {0x85dc, 0x00f7}, {0x85dd, 0x008f}, -{0x85de, 0x0078}, {0x85df, 0x00f7}, {0x85e0, 0x008f}, -{0x85e1, 0x0079}, {0x85e2, 0x00f7}, {0x85e3, 0x008f}, -{0x85e4, 0x007a}, {0x85e5, 0x00f7}, {0x85e6, 0x008f}, -{0x85e7, 0x007b}, {0x85e8, 0x00b6}, {0x85e9, 0x0012}, -{0x85ea, 0x0004}, {0x85eb, 0x008a}, {0x85ec, 0x0010}, -{0x85ed, 0x00b7}, {0x85ee, 0x0012}, {0x85ef, 0x0004}, -{0x85f0, 0x0086}, {0x85f1, 0x00e4}, {0x85f2, 0x00b7}, -{0x85f3, 0x0012}, {0x85f4, 0x0070}, {0x85f5, 0x00b7}, -{0x85f6, 0x0012}, {0x85f7, 0x0007}, {0x85f8, 0x00f7}, -{0x85f9, 0x0012}, {0x85fa, 0x0005}, {0x85fb, 0x00f7}, -{0x85fc, 0x0012}, {0x85fd, 0x0009}, {0x85fe, 0x0086}, -{0x85ff, 0x0008}, {0x8600, 0x00ba}, {0x8601, 0x0012}, -{0x8602, 0x0004}, {0x8603, 0x00b7}, {0x8604, 0x0012}, -{0x8605, 0x0004}, {0x8606, 0x0086}, {0x8607, 0x00f7}, -{0x8608, 0x00b4}, {0x8609, 0x0012}, {0x860a, 0x0004}, -{0x860b, 0x00b7}, {0x860c, 0x0012}, {0x860d, 0x0004}, -{0x860e, 0x0001}, {0x860f, 0x0001}, {0x8610, 0x0001}, -{0x8611, 0x0001}, {0x8612, 0x0001}, {0x8613, 0x0001}, -{0x8614, 0x00b6}, {0x8615, 0x0012}, {0x8616, 0x0008}, -{0x8617, 0x0027}, {0x8618, 0x007f}, {0x8619, 0x0081}, -{0x861a, 0x0080}, {0x861b, 0x0026}, {0x861c, 0x000b}, -{0x861d, 0x0086}, {0x861e, 0x0008}, {0x861f, 0x00ce}, -{0x8620, 0x008f}, {0x8621, 0x0079}, {0x8622, 0x00bd}, -{0x8623, 0x0089}, {0x8624, 0x007b}, {0x8625, 0x007e}, -{0x8626, 0x0086}, {0x8627, 0x008e}, {0x8628, 0x0081}, -{0x8629, 0x0040}, {0x862a, 0x0026}, {0x862b, 0x000b}, -{0x862c, 0x0086}, {0x862d, 0x0004}, {0x862e, 0x00ce}, -{0x862f, 0x008f}, {0x8630, 0x0076}, {0x8631, 0x00bd}, -{0x8632, 0x0089}, {0x8633, 0x007b}, {0x8634, 0x007e}, -{0x8635, 0x0086}, {0x8636, 0x008e}, {0x8637, 0x0081}, -{0x8638, 0x0020}, {0x8639, 0x0026}, {0x863a, 0x000b}, -{0x863b, 0x0086}, {0x863c, 0x0002}, {0x863d, 0x00ce}, -{0x863e, 0x008f}, {0x863f, 0x0073}, {0x8640, 0x00bd}, -{0x8641, 0x0089}, {0x8642, 0x007b}, {0x8643, 0x007e}, -{0x8644, 0x0086}, {0x8645, 0x008e}, {0x8646, 0x0081}, -{0x8647, 0x0010}, {0x8648, 0x0026}, {0x8649, 0x000b}, -{0x864a, 0x0086}, {0x864b, 0x0001}, {0x864c, 0x00ce}, -{0x864d, 0x008f}, {0x864e, 0x0070}, {0x864f, 0x00bd}, -{0x8650, 0x0089}, {0x8651, 0x007b}, {0x8652, 0x007e}, -{0x8653, 0x0086}, {0x8654, 0x008e}, {0x8655, 0x0081}, -{0x8656, 0x0008}, {0x8657, 0x0026}, {0x8658, 0x000b}, -{0x8659, 0x0086}, {0x865a, 0x0008}, {0x865b, 0x00ce}, -{0x865c, 0x008f}, {0x865d, 0x0079}, {0x865e, 0x00bd}, -{0x865f, 0x0089}, {0x8660, 0x007f}, {0x8661, 0x007e}, -{0x8662, 0x0086}, {0x8663, 0x008e}, {0x8664, 0x0081}, -{0x8665, 0x0004}, {0x8666, 0x0026}, {0x8667, 0x000b}, -{0x8668, 0x0086}, {0x8669, 0x0004}, {0x866a, 0x00ce}, -{0x866b, 0x008f}, {0x866c, 0x0076}, {0x866d, 0x00bd}, -{0x866e, 0x0089}, {0x866f, 0x007f}, {0x8670, 0x007e}, -{0x8671, 0x0086}, {0x8672, 0x008e}, {0x8673, 0x0081}, -{0x8674, 0x0002}, {0x8675, 0x0026}, {0x8676, 0x000b}, -{0x8677, 0x008a}, {0x8678, 0x0002}, {0x8679, 0x00ce}, -{0x867a, 0x008f}, {0x867b, 0x0073}, {0x867c, 0x00bd}, -{0x867d, 0x0089}, {0x867e, 0x007f}, {0x867f, 0x007e}, -{0x8680, 0x0086}, {0x8681, 0x008e}, {0x8682, 0x0081}, -{0x8683, 0x0001}, {0x8684, 0x0026}, {0x8685, 0x0008}, -{0x8686, 0x0086}, {0x8687, 0x0001}, {0x8688, 0x00ce}, -{0x8689, 0x008f}, {0x868a, 0x0070}, {0x868b, 0x00bd}, -{0x868c, 0x0089}, {0x868d, 0x007f}, {0x868e, 0x00b6}, -{0x868f, 0x008f}, {0x8690, 0x007f}, {0x8691, 0x0081}, -{0x8692, 0x000f}, {0x8693, 0x0026}, {0x8694, 0x0003}, -{0x8695, 0x007e}, {0x8696, 0x0087}, {0x8697, 0x0047}, -{0x8698, 0x00b6}, {0x8699, 0x0012}, {0x869a, 0x0009}, -{0x869b, 0x0084}, {0x869c, 0x0003}, {0x869d, 0x0081}, -{0x869e, 0x0003}, {0x869f, 0x0027}, {0x86a0, 0x0006}, -{0x86a1, 0x007c}, {0x86a2, 0x0012}, {0x86a3, 0x0009}, -{0x86a4, 0x007e}, {0x86a5, 0x0085}, {0x86a6, 0x00fe}, -{0x86a7, 0x00b6}, {0x86a8, 0x0012}, {0x86a9, 0x0006}, -{0x86aa, 0x0084}, {0x86ab, 0x0007}, {0x86ac, 0x0081}, -{0x86ad, 0x0007}, {0x86ae, 0x0027}, {0x86af, 0x0008}, -{0x86b0, 0x008b}, {0x86b1, 0x0001}, {0x86b2, 0x00b7}, -{0x86b3, 0x0012}, {0x86b4, 0x0006}, {0x86b5, 0x007e}, -{0x86b6, 0x0086}, {0x86b7, 0x00d5}, {0x86b8, 0x00b6}, -{0x86b9, 0x008f}, {0x86ba, 0x0082}, {0x86bb, 0x0026}, -{0x86bc, 0x000a}, {0x86bd, 0x007c}, {0x86be, 0x008f}, -{0x86bf, 0x0082}, {0x86c0, 0x004f}, {0x86c1, 0x00b7}, -{0x86c2, 0x0012}, {0x86c3, 0x0006}, {0x86c4, 0x007e}, -{0x86c5, 0x0085}, {0x86c6, 0x00c0}, {0x86c7, 0x00b6}, -{0x86c8, 0x0012}, {0x86c9, 0x0006}, {0x86ca, 0x0084}, -{0x86cb, 0x003f}, {0x86cc, 0x0081}, {0x86cd, 0x003f}, -{0x86ce, 0x0027}, {0x86cf, 0x0010}, {0x86d0, 0x008b}, -{0x86d1, 0x0008}, {0x86d2, 0x00b7}, {0x86d3, 0x0012}, -{0x86d4, 0x0006}, {0x86d5, 0x00b6}, {0x86d6, 0x0012}, -{0x86d7, 0x0009}, {0x86d8, 0x0084}, {0x86d9, 0x00fc}, -{0x86da, 0x00b7}, {0x86db, 0x0012}, {0x86dc, 0x0009}, -{0x86dd, 0x007e}, {0x86de, 0x0085}, {0x86df, 0x00fe}, -{0x86e0, 0x00ce}, {0x86e1, 0x008f}, {0x86e2, 0x0070}, -{0x86e3, 0x0018}, {0x86e4, 0x00ce}, {0x86e5, 0x008f}, -{0x86e6, 0x0084}, {0x86e7, 0x00c6}, {0x86e8, 0x000c}, -{0x86e9, 0x00bd}, {0x86ea, 0x0089}, {0x86eb, 0x006f}, -{0x86ec, 0x00ce}, {0x86ed, 0x008f}, {0x86ee, 0x0084}, -{0x86ef, 0x0018}, {0x86f0, 0x00ce}, {0x86f1, 0x008f}, -{0x86f2, 0x0070}, {0x86f3, 0x00c6}, {0x86f4, 0x000c}, -{0x86f5, 0x00bd}, {0x86f6, 0x0089}, {0x86f7, 0x006f}, -{0x86f8, 0x00d6}, {0x86f9, 0x0083}, {0x86fa, 0x00c1}, -{0x86fb, 0x004f}, {0x86fc, 0x002d}, {0x86fd, 0x0003}, -{0x86fe, 0x007e}, {0x86ff, 0x0087}, {0x8700, 0x0040}, -{0x8701, 0x00b6}, {0x8702, 0x008f}, {0x8703, 0x007f}, -{0x8704, 0x0081}, {0x8705, 0x0007}, {0x8706, 0x0027}, -{0x8707, 0x000f}, {0x8708, 0x0081}, {0x8709, 0x000b}, -{0x870a, 0x0027}, {0x870b, 0x0015}, {0x870c, 0x0081}, -{0x870d, 0x000d}, {0x870e, 0x0027}, {0x870f, 0x001b}, -{0x8710, 0x0081}, {0x8711, 0x000e}, {0x8712, 0x0027}, -{0x8713, 0x0021}, {0x8714, 0x007e}, {0x8715, 0x0087}, -{0x8716, 0x0040}, {0x8717, 0x00f7}, {0x8718, 0x008f}, -{0x8719, 0x007b}, {0x871a, 0x0086}, {0x871b, 0x0002}, -{0x871c, 0x00b7}, {0x871d, 0x008f}, {0x871e, 0x007a}, -{0x871f, 0x0020}, {0x8720, 0x001c}, {0x8721, 0x00f7}, -{0x8722, 0x008f}, {0x8723, 0x0078}, {0x8724, 0x0086}, -{0x8725, 0x0002}, {0x8726, 0x00b7}, {0x8727, 0x008f}, -{0x8728, 0x0077}, {0x8729, 0x0020}, {0x872a, 0x0012}, -{0x872b, 0x00f7}, {0x872c, 0x008f}, {0x872d, 0x0075}, -{0x872e, 0x0086}, {0x872f, 0x0002}, {0x8730, 0x00b7}, -{0x8731, 0x008f}, {0x8732, 0x0074}, {0x8733, 0x0020}, -{0x8734, 0x0008}, {0x8735, 0x00f7}, {0x8736, 0x008f}, -{0x8737, 0x0072}, {0x8738, 0x0086}, {0x8739, 0x0002}, -{0x873a, 0x00b7}, {0x873b, 0x008f}, {0x873c, 0x0071}, -{0x873d, 0x007e}, {0x873e, 0x0087}, {0x873f, 0x0047}, -{0x8740, 0x0086}, {0x8741, 0x0004}, {0x8742, 0x0097}, -{0x8743, 0x0040}, {0x8744, 0x007e}, {0x8745, 0x0089}, -{0x8746, 0x006e}, {0x8747, 0x00ce}, {0x8748, 0x008f}, -{0x8749, 0x0072}, {0x874a, 0x00bd}, {0x874b, 0x0089}, -{0x874c, 0x00f7}, {0x874d, 0x00ce}, {0x874e, 0x008f}, -{0x874f, 0x0075}, {0x8750, 0x00bd}, {0x8751, 0x0089}, -{0x8752, 0x00f7}, {0x8753, 0x00ce}, {0x8754, 0x008f}, -{0x8755, 0x0078}, {0x8756, 0x00bd}, {0x8757, 0x0089}, -{0x8758, 0x00f7}, {0x8759, 0x00ce}, {0x875a, 0x008f}, -{0x875b, 0x007b}, {0x875c, 0x00bd}, {0x875d, 0x0089}, -{0x875e, 0x00f7}, {0x875f, 0x004f}, {0x8760, 0x00b7}, -{0x8761, 0x008f}, {0x8762, 0x007d}, {0x8763, 0x00b7}, -{0x8764, 0x008f}, {0x8765, 0x0081}, {0x8766, 0x00b6}, -{0x8767, 0x008f}, {0x8768, 0x0072}, {0x8769, 0x0027}, -{0x876a, 0x0047}, {0x876b, 0x007c}, {0x876c, 0x008f}, -{0x876d, 0x007d}, {0x876e, 0x00b6}, {0x876f, 0x008f}, -{0x8770, 0x0075}, {0x8771, 0x0027}, {0x8772, 0x003f}, -{0x8773, 0x007c}, {0x8774, 0x008f}, {0x8775, 0x007d}, -{0x8776, 0x00b6}, {0x8777, 0x008f}, {0x8778, 0x0078}, -{0x8779, 0x0027}, {0x877a, 0x0037}, {0x877b, 0x007c}, -{0x877c, 0x008f}, {0x877d, 0x007d}, {0x877e, 0x00b6}, -{0x877f, 0x008f}, {0x8780, 0x007b}, {0x8781, 0x0027}, -{0x8782, 0x002f}, {0x8783, 0x007f}, {0x8784, 0x008f}, -{0x8785, 0x007d}, {0x8786, 0x007c}, {0x8787, 0x008f}, -{0x8788, 0x0081}, {0x8789, 0x007a}, {0x878a, 0x008f}, -{0x878b, 0x0072}, {0x878c, 0x0027}, {0x878d, 0x001b}, -{0x878e, 0x007c}, {0x878f, 0x008f}, {0x8790, 0x007d}, -{0x8791, 0x007a}, {0x8792, 0x008f}, {0x8793, 0x0075}, -{0x8794, 0x0027}, {0x8795, 0x0016}, {0x8796, 0x007c}, -{0x8797, 0x008f}, {0x8798, 0x007d}, {0x8799, 0x007a}, -{0x879a, 0x008f}, {0x879b, 0x0078}, {0x879c, 0x0027}, -{0x879d, 0x0011}, {0x879e, 0x007c}, {0x879f, 0x008f}, -{0x87a0, 0x007d}, {0x87a1, 0x007a}, {0x87a2, 0x008f}, -{0x87a3, 0x007b}, {0x87a4, 0x0027}, {0x87a5, 0x000c}, -{0x87a6, 0x007e}, {0x87a7, 0x0087}, {0x87a8, 0x0083}, -{0x87a9, 0x007a}, {0x87aa, 0x008f}, {0x87ab, 0x0075}, -{0x87ac, 0x007a}, {0x87ad, 0x008f}, {0x87ae, 0x0078}, -{0x87af, 0x007a}, {0x87b0, 0x008f}, {0x87b1, 0x007b}, -{0x87b2, 0x00ce}, {0x87b3, 0x00c1}, {0x87b4, 0x00fc}, -{0x87b5, 0x00f6}, {0x87b6, 0x008f}, {0x87b7, 0x007d}, -{0x87b8, 0x003a}, {0x87b9, 0x00a6}, {0x87ba, 0x0000}, -{0x87bb, 0x00b7}, {0x87bc, 0x0012}, {0x87bd, 0x0070}, -{0x87be, 0x00b6}, {0x87bf, 0x008f}, {0x87c0, 0x0072}, -{0x87c1, 0x0026}, {0x87c2, 0x0003}, {0x87c3, 0x007e}, -{0x87c4, 0x0087}, {0x87c5, 0x00fa}, {0x87c6, 0x00b6}, -{0x87c7, 0x008f}, {0x87c8, 0x0075}, {0x87c9, 0x0026}, -{0x87ca, 0x000a}, {0x87cb, 0x0018}, {0x87cc, 0x00ce}, -{0x87cd, 0x008f}, {0x87ce, 0x0073}, {0x87cf, 0x00bd}, -{0x87d0, 0x0089}, {0x87d1, 0x00d5}, {0x87d2, 0x007e}, -{0x87d3, 0x0087}, {0x87d4, 0x00fa}, {0x87d5, 0x00b6}, -{0x87d6, 0x008f}, {0x87d7, 0x0078}, {0x87d8, 0x0026}, -{0x87d9, 0x000a}, {0x87da, 0x0018}, {0x87db, 0x00ce}, -{0x87dc, 0x008f}, {0x87dd, 0x0076}, {0x87de, 0x00bd}, -{0x87df, 0x0089}, {0x87e0, 0x00d5}, {0x87e1, 0x007e}, -{0x87e2, 0x0087}, {0x87e3, 0x00fa}, {0x87e4, 0x00b6}, -{0x87e5, 0x008f}, {0x87e6, 0x007b}, {0x87e7, 0x0026}, -{0x87e8, 0x000a}, {0x87e9, 0x0018}, {0x87ea, 0x00ce}, -{0x87eb, 0x008f}, {0x87ec, 0x0079}, {0x87ed, 0x00bd}, -{0x87ee, 0x0089}, {0x87ef, 0x00d5}, {0x87f0, 0x007e}, -{0x87f1, 0x0087}, {0x87f2, 0x00fa}, {0x87f3, 0x0086}, -{0x87f4, 0x0005}, {0x87f5, 0x0097}, {0x87f6, 0x0040}, -{0x87f7, 0x007e}, {0x87f8, 0x0089}, {0x87f9, 0x006e}, -{0x87fa, 0x00b6}, {0x87fb, 0x008f}, {0x87fc, 0x0075}, -{0x87fd, 0x0081}, {0x87fe, 0x0007}, {0x87ff, 0x002e}, -{0x8800, 0x00f2}, {0x8801, 0x00f6}, {0x8802, 0x0012}, -{0x8803, 0x0006}, {0x8804, 0x00c4}, {0x8805, 0x00f8}, -{0x8806, 0x001b}, {0x8807, 0x00b7}, {0x8808, 0x0012}, -{0x8809, 0x0006}, {0x880a, 0x00b6}, {0x880b, 0x008f}, -{0x880c, 0x0078}, {0x880d, 0x0081}, {0x880e, 0x0007}, -{0x880f, 0x002e}, {0x8810, 0x00e2}, {0x8811, 0x0048}, -{0x8812, 0x0048}, {0x8813, 0x0048}, {0x8814, 0x00f6}, -{0x8815, 0x0012}, {0x8816, 0x0006}, {0x8817, 0x00c4}, -{0x8818, 0x00c7}, {0x8819, 0x001b}, {0x881a, 0x00b7}, -{0x881b, 0x0012}, {0x881c, 0x0006}, {0x881d, 0x00b6}, -{0x881e, 0x008f}, {0x881f, 0x007b}, {0x8820, 0x0081}, -{0x8821, 0x0007}, {0x8822, 0x002e}, {0x8823, 0x00cf}, -{0x8824, 0x00f6}, {0x8825, 0x0012}, {0x8826, 0x0005}, -{0x8827, 0x00c4}, {0x8828, 0x00f8}, {0x8829, 0x001b}, -{0x882a, 0x00b7}, {0x882b, 0x0012}, {0x882c, 0x0005}, -{0x882d, 0x0086}, {0x882e, 0x0000}, {0x882f, 0x00f6}, -{0x8830, 0x008f}, {0x8831, 0x0071}, {0x8832, 0x00bd}, -{0x8833, 0x0089}, {0x8834, 0x0094}, {0x8835, 0x0086}, -{0x8836, 0x0001}, {0x8837, 0x00f6}, {0x8838, 0x008f}, -{0x8839, 0x0074}, {0x883a, 0x00bd}, {0x883b, 0x0089}, -{0x883c, 0x0094}, {0x883d, 0x0086}, {0x883e, 0x0002}, -{0x883f, 0x00f6}, {0x8840, 0x008f}, {0x8841, 0x0077}, -{0x8842, 0x00bd}, {0x8843, 0x0089}, {0x8844, 0x0094}, -{0x8845, 0x0086}, {0x8846, 0x0003}, {0x8847, 0x00f6}, -{0x8848, 0x008f}, {0x8849, 0x007a}, {0x884a, 0x00bd}, -{0x884b, 0x0089}, {0x884c, 0x0094}, {0x884d, 0x00ce}, -{0x884e, 0x008f}, {0x884f, 0x0070}, {0x8850, 0x00a6}, -{0x8851, 0x0001}, {0x8852, 0x0081}, {0x8853, 0x0001}, -{0x8854, 0x0027}, {0x8855, 0x0007}, {0x8856, 0x0081}, -{0x8857, 0x0003}, {0x8858, 0x0027}, {0x8859, 0x0003}, -{0x885a, 0x007e}, {0x885b, 0x0088}, {0x885c, 0x0066}, -{0x885d, 0x00a6}, {0x885e, 0x0000}, {0x885f, 0x00b8}, -{0x8860, 0x008f}, {0x8861, 0x0081}, {0x8862, 0x0084}, -{0x8863, 0x0001}, {0x8864, 0x0026}, {0x8865, 0x000b}, -{0x8866, 0x008c}, {0x8867, 0x008f}, {0x8868, 0x0079}, -{0x8869, 0x002c}, {0x886a, 0x000e}, {0x886b, 0x0008}, -{0x886c, 0x0008}, {0x886d, 0x0008}, {0x886e, 0x007e}, -{0x886f, 0x0088}, {0x8870, 0x0050}, {0x8871, 0x00b6}, -{0x8872, 0x0012}, {0x8873, 0x0004}, {0x8874, 0x008a}, -{0x8875, 0x0040}, {0x8876, 0x00b7}, {0x8877, 0x0012}, -{0x8878, 0x0004}, {0x8879, 0x00b6}, {0x887a, 0x0012}, -{0x887b, 0x0004}, {0x887c, 0x0084}, {0x887d, 0x00fb}, -{0x887e, 0x0084}, {0x887f, 0x00ef}, {0x8880, 0x00b7}, -{0x8881, 0x0012}, {0x8882, 0x0004}, {0x8883, 0x00b6}, -{0x8884, 0x0012}, {0x8885, 0x0007}, {0x8886, 0x0036}, -{0x8887, 0x00b6}, {0x8888, 0x008f}, {0x8889, 0x007c}, -{0x888a, 0x0048}, {0x888b, 0x0048}, {0x888c, 0x00b7}, -{0x888d, 0x0012}, {0x888e, 0x0007}, {0x888f, 0x0086}, -{0x8890, 0x0001}, {0x8891, 0x00ba}, {0x8892, 0x0012}, -{0x8893, 0x0004}, {0x8894, 0x00b7}, {0x8895, 0x0012}, -{0x8896, 0x0004}, {0x8897, 0x0001}, {0x8898, 0x0001}, -{0x8899, 0x0001}, {0x889a, 0x0001}, {0x889b, 0x0001}, -{0x889c, 0x0001}, {0x889d, 0x0086}, {0x889e, 0x00fe}, -{0x889f, 0x00b4}, {0x88a0, 0x0012}, {0x88a1, 0x0004}, -{0x88a2, 0x00b7}, {0x88a3, 0x0012}, {0x88a4, 0x0004}, -{0x88a5, 0x0086}, {0x88a6, 0x0002}, {0x88a7, 0x00ba}, -{0x88a8, 0x0012}, {0x88a9, 0x0004}, {0x88aa, 0x00b7}, -{0x88ab, 0x0012}, {0x88ac, 0x0004}, {0x88ad, 0x0086}, -{0x88ae, 0x00fd}, {0x88af, 0x00b4}, {0x88b0, 0x0012}, -{0x88b1, 0x0004}, {0x88b2, 0x00b7}, {0x88b3, 0x0012}, -{0x88b4, 0x0004}, {0x88b5, 0x0032}, {0x88b6, 0x00b7}, -{0x88b7, 0x0012}, {0x88b8, 0x0007}, {0x88b9, 0x00b6}, -{0x88ba, 0x0012}, {0x88bb, 0x0000}, {0x88bc, 0x0084}, -{0x88bd, 0x0008}, {0x88be, 0x0081}, {0x88bf, 0x0008}, -{0x88c0, 0x0027}, {0x88c1, 0x000f}, {0x88c2, 0x007c}, -{0x88c3, 0x0082}, {0x88c4, 0x0008}, {0x88c5, 0x0026}, -{0x88c6, 0x0007}, {0x88c7, 0x0086}, {0x88c8, 0x0076}, -{0x88c9, 0x0097}, {0x88ca, 0x0040}, {0x88cb, 0x007e}, -{0x88cc, 0x0089}, {0x88cd, 0x006e}, {0x88ce, 0x007e}, -{0x88cf, 0x0086}, {0x88d0, 0x00ec}, {0x88d1, 0x00b6}, -{0x88d2, 0x008f}, {0x88d3, 0x007f}, {0x88d4, 0x0081}, -{0x88d5, 0x000f}, {0x88d6, 0x0027}, {0x88d7, 0x003c}, -{0x88d8, 0x00bd}, {0x88d9, 0x00e6}, {0x88da, 0x00c7}, -{0x88db, 0x00b7}, {0x88dc, 0x0012}, {0x88dd, 0x000d}, -{0x88de, 0x00bd}, {0x88df, 0x00e6}, {0x88e0, 0x00cb}, -{0x88e1, 0x00b6}, {0x88e2, 0x0012}, {0x88e3, 0x0004}, -{0x88e4, 0x008a}, {0x88e5, 0x0020}, {0x88e6, 0x00b7}, -{0x88e7, 0x0012}, {0x88e8, 0x0004}, {0x88e9, 0x00ce}, -{0x88ea, 0x00ff}, {0x88eb, 0x00ff}, {0x88ec, 0x00b6}, -{0x88ed, 0x0012}, {0x88ee, 0x0000}, {0x88ef, 0x0081}, -{0x88f0, 0x000c}, {0x88f1, 0x0026}, {0x88f2, 0x0005}, -{0x88f3, 0x0009}, {0x88f4, 0x0026}, {0x88f5, 0x00f6}, -{0x88f6, 0x0027}, {0x88f7, 0x001c}, {0x88f8, 0x00b6}, -{0x88f9, 0x0012}, {0x88fa, 0x0004}, {0x88fb, 0x0084}, -{0x88fc, 0x00df}, {0x88fd, 0x00b7}, {0x88fe, 0x0012}, -{0x88ff, 0x0004}, {0x8900, 0x0096}, {0x8901, 0x0083}, -{0x8902, 0x0081}, {0x8903, 0x0007}, {0x8904, 0x002c}, -{0x8905, 0x0005}, {0x8906, 0x007c}, {0x8907, 0x0000}, -{0x8908, 0x0083}, {0x8909, 0x0020}, {0x890a, 0x0006}, -{0x890b, 0x0096}, {0x890c, 0x0083}, {0x890d, 0x008b}, -{0x890e, 0x0008}, {0x890f, 0x0097}, {0x8910, 0x0083}, -{0x8911, 0x007e}, {0x8912, 0x0085}, {0x8913, 0x0041}, -{0x8914, 0x007f}, {0x8915, 0x008f}, {0x8916, 0x007e}, -{0x8917, 0x0086}, {0x8918, 0x0080}, {0x8919, 0x00b7}, -{0x891a, 0x0012}, {0x891b, 0x000c}, {0x891c, 0x0086}, -{0x891d, 0x0001}, {0x891e, 0x00b7}, {0x891f, 0x008f}, -{0x8920, 0x007d}, {0x8921, 0x00b6}, {0x8922, 0x0012}, -{0x8923, 0x000c}, {0x8924, 0x0084}, {0x8925, 0x007f}, -{0x8926, 0x00b7}, {0x8927, 0x0012}, {0x8928, 0x000c}, -{0x8929, 0x008a}, {0x892a, 0x0080}, {0x892b, 0x00b7}, -{0x892c, 0x0012}, {0x892d, 0x000c}, {0x892e, 0x0086}, -{0x892f, 0x000a}, {0x8930, 0x00bd}, {0x8931, 0x008a}, -{0x8932, 0x0006}, {0x8933, 0x00b6}, {0x8934, 0x0012}, -{0x8935, 0x000a}, {0x8936, 0x002a}, {0x8937, 0x0009}, -{0x8938, 0x00b6}, {0x8939, 0x0012}, {0x893a, 0x000c}, -{0x893b, 0x00ba}, {0x893c, 0x008f}, {0x893d, 0x007d}, -{0x893e, 0x00b7}, {0x893f, 0x0012}, {0x8940, 0x000c}, -{0x8941, 0x00b6}, {0x8942, 0x008f}, {0x8943, 0x007e}, -{0x8944, 0x0081}, {0x8945, 0x0060}, {0x8946, 0x0027}, -{0x8947, 0x001a}, {0x8948, 0x008b}, {0x8949, 0x0020}, -{0x894a, 0x00b7}, {0x894b, 0x008f}, {0x894c, 0x007e}, -{0x894d, 0x00b6}, {0x894e, 0x0012}, {0x894f, 0x000c}, -{0x8950, 0x0084}, {0x8951, 0x009f}, {0x8952, 0x00ba}, -{0x8953, 0x008f}, {0x8954, 0x007e}, {0x8955, 0x00b7}, -{0x8956, 0x0012}, {0x8957, 0x000c}, {0x8958, 0x00b6}, -{0x8959, 0x008f}, {0x895a, 0x007d}, {0x895b, 0x0048}, -{0x895c, 0x00b7}, {0x895d, 0x008f}, {0x895e, 0x007d}, -{0x895f, 0x007e}, {0x8960, 0x0089}, {0x8961, 0x0021}, -{0x8962, 0x00b6}, {0x8963, 0x0012}, {0x8964, 0x0004}, -{0x8965, 0x008a}, {0x8966, 0x0020}, {0x8967, 0x00b7}, -{0x8968, 0x0012}, {0x8969, 0x0004}, {0x896a, 0x00bd}, -{0x896b, 0x008a}, {0x896c, 0x000a}, {0x896d, 0x004f}, -{0x896e, 0x0039}, {0x896f, 0x00a6}, {0x8970, 0x0000}, -{0x8971, 0x0018}, {0x8972, 0x00a7}, {0x8973, 0x0000}, -{0x8974, 0x0008}, {0x8975, 0x0018}, {0x8976, 0x0008}, -{0x8977, 0x005a}, {0x8978, 0x0026}, {0x8979, 0x00f5}, -{0x897a, 0x0039}, {0x897b, 0x0036}, {0x897c, 0x006c}, -{0x897d, 0x0000}, {0x897e, 0x0032}, {0x897f, 0x00ba}, -{0x8980, 0x008f}, {0x8981, 0x007f}, {0x8982, 0x00b7}, -{0x8983, 0x008f}, {0x8984, 0x007f}, {0x8985, 0x00b6}, -{0x8986, 0x0012}, {0x8987, 0x0009}, {0x8988, 0x0084}, -{0x8989, 0x0003}, {0x898a, 0x00a7}, {0x898b, 0x0001}, -{0x898c, 0x00b6}, {0x898d, 0x0012}, {0x898e, 0x0006}, -{0x898f, 0x0084}, {0x8990, 0x003f}, {0x8991, 0x00a7}, -{0x8992, 0x0002}, {0x8993, 0x0039}, {0x8994, 0x0036}, -{0x8995, 0x0086}, {0x8996, 0x0003}, {0x8997, 0x00b7}, -{0x8998, 0x008f}, {0x8999, 0x0080}, {0x899a, 0x0032}, -{0x899b, 0x00c1}, {0x899c, 0x0000}, {0x899d, 0x0026}, -{0x899e, 0x0006}, {0x899f, 0x00b7}, {0x89a0, 0x008f}, -{0x89a1, 0x007c}, {0x89a2, 0x007e}, {0x89a3, 0x0089}, -{0x89a4, 0x00c9}, {0x89a5, 0x00c1}, {0x89a6, 0x0001}, -{0x89a7, 0x0027}, {0x89a8, 0x0018}, {0x89a9, 0x00c1}, -{0x89aa, 0x0002}, {0x89ab, 0x0027}, {0x89ac, 0x000c}, -{0x89ad, 0x00c1}, {0x89ae, 0x0003}, {0x89af, 0x0027}, -{0x89b0, 0x0000}, {0x89b1, 0x00f6}, {0x89b2, 0x008f}, -{0x89b3, 0x0080}, {0x89b4, 0x0005}, {0x89b5, 0x0005}, -{0x89b6, 0x00f7}, {0x89b7, 0x008f}, {0x89b8, 0x0080}, -{0x89b9, 0x00f6}, {0x89ba, 0x008f}, {0x89bb, 0x0080}, -{0x89bc, 0x0005}, {0x89bd, 0x0005}, {0x89be, 0x00f7}, -{0x89bf, 0x008f}, {0x89c0, 0x0080}, {0x89c1, 0x00f6}, -{0x89c2, 0x008f}, {0x89c3, 0x0080}, {0x89c4, 0x0005}, -{0x89c5, 0x0005}, {0x89c6, 0x00f7}, {0x89c7, 0x008f}, -{0x89c8, 0x0080}, {0x89c9, 0x00f6}, {0x89ca, 0x008f}, -{0x89cb, 0x0080}, {0x89cc, 0x0053}, {0x89cd, 0x00f4}, -{0x89ce, 0x0012}, {0x89cf, 0x0007}, {0x89d0, 0x001b}, -{0x89d1, 0x00b7}, {0x89d2, 0x0012}, {0x89d3, 0x0007}, -{0x89d4, 0x0039}, {0x89d5, 0x00ce}, {0x89d6, 0x008f}, -{0x89d7, 0x0070}, {0x89d8, 0x00a6}, {0x89d9, 0x0000}, -{0x89da, 0x0018}, {0x89db, 0x00e6}, {0x89dc, 0x0000}, -{0x89dd, 0x0018}, {0x89de, 0x00a7}, {0x89df, 0x0000}, -{0x89e0, 0x00e7}, {0x89e1, 0x0000}, {0x89e2, 0x00a6}, -{0x89e3, 0x0001}, {0x89e4, 0x0018}, {0x89e5, 0x00e6}, -{0x89e6, 0x0001}, {0x89e7, 0x0018}, {0x89e8, 0x00a7}, -{0x89e9, 0x0001}, {0x89ea, 0x00e7}, {0x89eb, 0x0001}, -{0x89ec, 0x00a6}, {0x89ed, 0x0002}, {0x89ee, 0x0018}, -{0x89ef, 0x00e6}, {0x89f0, 0x0002}, {0x89f1, 0x0018}, -{0x89f2, 0x00a7}, {0x89f3, 0x0002}, {0x89f4, 0x00e7}, -{0x89f5, 0x0002}, {0x89f6, 0x0039}, {0x89f7, 0x00a6}, -{0x89f8, 0x0000}, {0x89f9, 0x0084}, {0x89fa, 0x0007}, -{0x89fb, 0x00e6}, {0x89fc, 0x0000}, {0x89fd, 0x00c4}, -{0x89fe, 0x0038}, {0x89ff, 0x0054}, {0x8a00, 0x0054}, -{0x8a01, 0x0054}, {0x8a02, 0x001b}, {0x8a03, 0x00a7}, -{0x8a04, 0x0000}, {0x8a05, 0x0039}, {0x8a06, 0x004a}, -{0x8a07, 0x0026}, {0x8a08, 0x00fd}, {0x8a09, 0x0039}, -{0x8a0a, 0x0096}, {0x8a0b, 0x0022}, {0x8a0c, 0x0084}, -{0x8a0d, 0x000f}, {0x8a0e, 0x0097}, {0x8a0f, 0x0022}, -{0x8a10, 0x0086}, {0x8a11, 0x0001}, {0x8a12, 0x00b7}, -{0x8a13, 0x008f}, {0x8a14, 0x0070}, {0x8a15, 0x00b6}, -{0x8a16, 0x0012}, {0x8a17, 0x0007}, {0x8a18, 0x00b7}, -{0x8a19, 0x008f}, {0x8a1a, 0x0071}, {0x8a1b, 0x00f6}, -{0x8a1c, 0x0012}, {0x8a1d, 0x000c}, {0x8a1e, 0x00c4}, -{0x8a1f, 0x000f}, {0x8a20, 0x00c8}, {0x8a21, 0x000f}, -{0x8a22, 0x00f7}, {0x8a23, 0x008f}, {0x8a24, 0x0072}, -{0x8a25, 0x00f6}, {0x8a26, 0x008f}, {0x8a27, 0x0072}, -{0x8a28, 0x00b6}, {0x8a29, 0x008f}, {0x8a2a, 0x0071}, -{0x8a2b, 0x0084}, {0x8a2c, 0x0003}, {0x8a2d, 0x0027}, -{0x8a2e, 0x0014}, {0x8a2f, 0x0081}, {0x8a30, 0x0001}, -{0x8a31, 0x0027}, {0x8a32, 0x001c}, {0x8a33, 0x0081}, -{0x8a34, 0x0002}, {0x8a35, 0x0027}, {0x8a36, 0x0024}, -{0x8a37, 0x00f4}, {0x8a38, 0x008f}, {0x8a39, 0x0070}, -{0x8a3a, 0x0027}, {0x8a3b, 0x002a}, {0x8a3c, 0x0096}, -{0x8a3d, 0x0022}, {0x8a3e, 0x008a}, {0x8a3f, 0x0080}, -{0x8a40, 0x007e}, {0x8a41, 0x008a}, {0x8a42, 0x0064}, -{0x8a43, 0x00f4}, {0x8a44, 0x008f}, {0x8a45, 0x0070}, -{0x8a46, 0x0027}, {0x8a47, 0x001e}, {0x8a48, 0x0096}, -{0x8a49, 0x0022}, {0x8a4a, 0x008a}, {0x8a4b, 0x0010}, -{0x8a4c, 0x007e}, {0x8a4d, 0x008a}, {0x8a4e, 0x0064}, -{0x8a4f, 0x00f4}, {0x8a50, 0x008f}, {0x8a51, 0x0070}, -{0x8a52, 0x0027}, {0x8a53, 0x0012}, {0x8a54, 0x0096}, -{0x8a55, 0x0022}, {0x8a56, 0x008a}, {0x8a57, 0x0020}, -{0x8a58, 0x007e}, {0x8a59, 0x008a}, {0x8a5a, 0x0064}, -{0x8a5b, 0x00f4}, {0x8a5c, 0x008f}, {0x8a5d, 0x0070}, -{0x8a5e, 0x0027}, {0x8a5f, 0x0006}, {0x8a60, 0x0096}, -{0x8a61, 0x0022}, {0x8a62, 0x008a}, {0x8a63, 0x0040}, -{0x8a64, 0x0097}, {0x8a65, 0x0022}, {0x8a66, 0x0074}, -{0x8a67, 0x008f}, {0x8a68, 0x0071}, {0x8a69, 0x0074}, -{0x8a6a, 0x008f}, {0x8a6b, 0x0071}, {0x8a6c, 0x0078}, -{0x8a6d, 0x008f}, {0x8a6e, 0x0070}, {0x8a6f, 0x00b6}, -{0x8a70, 0x008f}, {0x8a71, 0x0070}, {0x8a72, 0x0085}, -{0x8a73, 0x0010}, {0x8a74, 0x0027}, {0x8a75, 0x00af}, -{0x8a76, 0x00d6}, {0x8a77, 0x0022}, {0x8a78, 0x00c4}, -{0x8a79, 0x0010}, {0x8a7a, 0x0058}, {0x8a7b, 0x00b6}, -{0x8a7c, 0x0012}, {0x8a7d, 0x0070}, {0x8a7e, 0x0081}, -{0x8a7f, 0x00e4}, {0x8a80, 0x0027}, {0x8a81, 0x0036}, -{0x8a82, 0x0081}, {0x8a83, 0x00e1}, {0x8a84, 0x0026}, -{0x8a85, 0x000c}, {0x8a86, 0x0096}, {0x8a87, 0x0022}, -{0x8a88, 0x0084}, {0x8a89, 0x0020}, {0x8a8a, 0x0044}, -{0x8a8b, 0x001b}, {0x8a8c, 0x00d6}, {0x8a8d, 0x0022}, -{0x8a8e, 0x00c4}, {0x8a8f, 0x00cf}, {0x8a90, 0x0020}, -{0x8a91, 0x0023}, {0x8a92, 0x0058}, {0x8a93, 0x0081}, -{0x8a94, 0x00c6}, {0x8a95, 0x0026}, {0x8a96, 0x000d}, -{0x8a97, 0x0096}, {0x8a98, 0x0022}, {0x8a99, 0x0084}, -{0x8a9a, 0x0040}, {0x8a9b, 0x0044}, {0x8a9c, 0x0044}, -{0x8a9d, 0x001b}, {0x8a9e, 0x00d6}, {0x8a9f, 0x0022}, -{0x8aa0, 0x00c4}, {0x8aa1, 0x00af}, {0x8aa2, 0x0020}, -{0x8aa3, 0x0011}, {0x8aa4, 0x0058}, {0x8aa5, 0x0081}, -{0x8aa6, 0x0027}, {0x8aa7, 0x0026}, {0x8aa8, 0x000f}, -{0x8aa9, 0x0096}, {0x8aaa, 0x0022}, {0x8aab, 0x0084}, -{0x8aac, 0x0080}, {0x8aad, 0x0044}, {0x8aae, 0x0044}, -{0x8aaf, 0x0044}, {0x8ab0, 0x001b}, {0x8ab1, 0x00d6}, -{0x8ab2, 0x0022}, {0x8ab3, 0x00c4}, {0x8ab4, 0x006f}, -{0x8ab5, 0x001b}, {0x8ab6, 0x0097}, {0x8ab7, 0x0022}, -{0x8ab8, 0x0039}, {0x8ab9, 0x0027}, {0x8aba, 0x000c}, -{0x8abb, 0x007c}, {0x8abc, 0x0082}, {0x8abd, 0x0006}, -{0x8abe, 0x00bd}, {0x8abf, 0x00d9}, {0x8ac0, 0x00ed}, -{0x8ac1, 0x00b6}, {0x8ac2, 0x0082}, {0x8ac3, 0x0007}, -{0x8ac4, 0x007e}, {0x8ac5, 0x008a}, {0x8ac6, 0x00b9}, -{0x8ac7, 0x007f}, {0x8ac8, 0x0082}, {0x8ac9, 0x0006}, -{0x8aca, 0x0039}, { 0x0, 0x0 } -}; -#endif - - /* phy types */ #define CAS_PHY_UNKNOWN 0x00 #define CAS_PHY_SERDES 0x01 @@ -4389,6 +2872,11 @@ struct cas { dma_addr_t block_dvma, tx_tiny_dvma[N_TX_RINGS]; struct pci_dev *pdev; struct net_device *dev; + + /* Firmware Info */ + u16 fw_load_addr; + u32 fw_size; + u8 *fw_data; }; #define TX_DESC_NEXT(r, x) (((x) + 1) & (TX_DESC_RINGN_SIZE(r) - 1)) diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index ec6b0af3d46..017a5361b98 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -302,13 +302,7 @@ static int cpmac_mdio_reset(struct mii_bus *bus) static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, }; -static struct mii_bus cpmac_mii = { - .name = "cpmac-mii", - .read = cpmac_mdio_read, - .write = cpmac_mdio_write, - .reset = cpmac_mdio_reset, - .irq = mii_irqs, -}; +static struct mii_bus *cpmac_mii; static int cpmac_config(struct net_device *dev, struct ifmap *map) { @@ -1116,7 +1110,7 @@ static int __devinit cpmac_probe(struct platform_device *pdev) for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { if (!(pdata->phy_mask & (1 << phy_id))) continue; - if (!cpmac_mii.phy_map[phy_id]) + if (!cpmac_mii->phy_map[phy_id]) continue; break; } @@ -1168,7 +1162,7 @@ static int __devinit cpmac_probe(struct platform_device *pdev) priv->msg_enable = netif_msg_init(debug_level, 0xff); memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); - priv->phy = phy_connect(dev, cpmac_mii.phy_map[phy_id]->dev.bus_id, + priv->phy = phy_connect(dev, cpmac_mii->phy_map[phy_id]->dev.bus_id, &cpmac_adjust_link, 0, PHY_INTERFACE_MODE_MII); if (IS_ERR(priv->phy)) { if (netif_msg_drv(priv)) @@ -1216,11 +1210,22 @@ int __devinit cpmac_init(void) u32 mask; int i, res; - cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256); + cpmac_mii = mdiobus_alloc(); + if (cpmac_mii == NULL) + return -ENOMEM; + + cpmac_mii->name = "cpmac-mii"; + cpmac_mii->read = cpmac_mdio_read; + cpmac_mii->write = cpmac_mdio_write; + cpmac_mii->reset = cpmac_mdio_reset; + cpmac_mii->irq = mii_irqs; + + cpmac_mii->priv = ioremap(AR7_REGS_MDIO, 256); - if (!cpmac_mii.priv) { + if (!cpmac_mii->priv) { printk(KERN_ERR "Can't ioremap mdio registers\n"); - return -ENXIO; + res = -ENXIO; + goto fail_alloc; } #warning FIXME: unhardcode gpio&reset bits @@ -1230,10 +1235,10 @@ int __devinit cpmac_init(void) ar7_device_reset(AR7_RESET_BIT_CPMAC_HI); ar7_device_reset(AR7_RESET_BIT_EPHY); - cpmac_mii.reset(&cpmac_mii); + cpmac_mii->reset(cpmac_mii); for (i = 0; i < 300000; i++) - if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE))) + if ((mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE))) break; else cpu_relax(); @@ -1244,10 +1249,10 @@ int __devinit cpmac_init(void) mask = 0; } - cpmac_mii.phy_mask = ~(mask | 0x80000000); - snprintf(cpmac_mii.id, MII_BUS_ID_SIZE, "0"); + cpmac_mii->phy_mask = ~(mask | 0x80000000); + snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "0"); - res = mdiobus_register(&cpmac_mii); + res = mdiobus_register(cpmac_mii); if (res) goto fail_mii; @@ -1258,10 +1263,13 @@ int __devinit cpmac_init(void) return 0; fail_cpmac: - mdiobus_unregister(&cpmac_mii); + mdiobus_unregister(cpmac_mii); fail_mii: - iounmap(cpmac_mii.priv); + iounmap(cpmac_mii->priv); + +fail_alloc: + mdiobus_free(cpmac_mii); return res; } @@ -1269,8 +1277,9 @@ fail_mii: void __devexit cpmac_exit(void) { platform_driver_unregister(&cpmac_driver); - mdiobus_unregister(&cpmac_mii); - iounmap(cpmac_mii.priv); + mdiobus_unregister(cpmac_mii); + mdiobus_free(cpmac_mii); + iounmap(cpmac_mii->priv); } module_init(cpmac_init); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index ea6144a9565..7107620f615 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -36,8 +36,7 @@ Alan Cox : Removed 1.2 support, added 2.1 extra counters. - Andrew Morton : andrewm@uow.edu.au - : Kernel 2.3.48 + Andrew Morton : Kernel 2.3.48 : Handle kmalloc() failures : Other resource allocation fixes : Add SMP locks @@ -49,7 +48,7 @@ : Fixed an out-of-mem bug in dma_rx() : Updated Documentation/networking/cs89x0.txt - Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre1 + Andrew Morton : Kernel 2.3.99-pre1 : Use skb_reserve to longword align IP header (two places) : Remove a delay loop from dma_rx() : Replace '100' with HZ @@ -57,11 +56,11 @@ : Added 'cs89x0_dma=N' kernel boot option : Correctly initialise lp->lock in non-module compile - Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre4-1 + Andrew Morton : Kernel 2.3.99-pre4-1 : MOD_INC/DEC race fix (see : http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html) - Andrew Morton : andrewm@uow.edu.au / Kernel 2.4.0-test7-pre2 + Andrew Morton : Kernel 2.4.0-test7-pre2 : Enhanced EEPROM support to cover more devices, : abstracted IRQ mapping to support CONFIG_ARCH_CLPS7500 arch : (Jason Gunthorpe <jgg@ualberta.ca>) @@ -156,7 +155,7 @@ #include "cs89x0.h" static char version[] __initdata = -"cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n"; +"cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton\n"; #define DRV_NAME "cs89x0" @@ -194,6 +193,12 @@ static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; #define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */ static unsigned int netcard_portlist[] __used __initdata = {CIRRUS_DEFAULT_BASE, 0}; static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0}; +#elif defined(CONFIG_MACH_MX31ADS) +#include <mach/board-mx31ads.h> +static unsigned int netcard_portlist[] __used __initdata = { + PBC_BASE_ADDRESS + PBC_CS8900A_IOBASE + 0x300, 0 +}; +static unsigned cs8900_irq_map[] = {EXPIO_INT_ENET_INT, 0, 0, 0}; #else static unsigned int netcard_portlist[] __used __initdata = { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; @@ -802,7 +807,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) } else { i = lp->isa_config & INT_NO_MASK; if (lp->chip_type == CS8900) { -#if defined(CONFIG_MACH_IXDP2351) || defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X) +#ifdef CONFIG_CS89x0_NONISA_IRQ i = cs8900_irq_map[0]; #else /* Translate the IRQ using the IRQ mapping table. */ @@ -1029,6 +1034,7 @@ skip_this_frame: void __init reset_chip(struct net_device *dev) { +#if !defined(CONFIG_MACH_MX31ADS) #if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; @@ -1057,6 +1063,7 @@ void __init reset_chip(struct net_device *dev) reset_start_time = jiffies; while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) ; +#endif /* !CONFIG_MACH_MX31ADS */ } @@ -1304,7 +1311,7 @@ net_open(struct net_device *dev) else #endif { -#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X) +#ifndef CONFIG_CS89x0_NONISA_IRQ if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); @@ -1397,9 +1404,7 @@ net_open(struct net_device *dev) release_dma: #if ALLOW_DMA free_dma(dev->dma); -#endif release_irq: -#if ALLOW_DMA release_dma_buff(lp); #endif writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON)); @@ -1871,7 +1876,7 @@ MODULE_PARM_DESC(dmasize , "(ignored)"); MODULE_PARM_DESC(use_dma , "(ignored)"); #endif -MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>"); +MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 271140433b0..bc8e2413abd 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -54,7 +54,6 @@ struct port_info { struct adapter *adapter; struct vlan_group *vlan_grp; struct sge_qset *qs; - const struct port_type_info *port_type; u8 port_id; u8 rx_csum_offload; u8 nqsets; @@ -124,8 +123,7 @@ struct sge_rspq { /* state for an SGE response queue */ dma_addr_t phys_addr; /* physical address of the ring */ unsigned int cntxt_id; /* SGE context id for the response q */ spinlock_t lock; /* guards response processing */ - struct sk_buff *rx_head; /* offload packet receive queue head */ - struct sk_buff *rx_tail; /* offload packet receive queue tail */ + struct sk_buff_head rx_queue; /* offload packet receive queue */ struct sk_buff *pg_skb; /* used to build frag list in napi handler */ unsigned long offload_pkts; @@ -241,6 +239,7 @@ struct adapter { unsigned int check_task_cnt; struct delayed_work adap_check_task; struct work_struct ext_intr_handler_task; + struct work_struct fatal_error_handler_task; struct dentry *debugfs_root; @@ -282,9 +281,11 @@ int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb); void t3_os_ext_intr_handler(struct adapter *adapter); void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status, int speed, int duplex, int fc); +void t3_os_phymod_changed(struct adapter *adap, int port_id); void t3_sge_start(struct adapter *adap); void t3_sge_stop(struct adapter *adap); +void t3_stop_sge_timers(struct adapter *adap); void t3_free_sge_resources(struct adapter *adap); void t3_sge_err_intr_handler(struct adapter *adapter); irq_handler_t t3_intr_handler(struct adapter *adap, int polling); diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index ee140e63ddc..5c3c05da4d9 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -33,17 +33,57 @@ #include "regs.h" enum { + PMD_RSD = 10, /* PMA/PMD receive signal detect register */ + PCS_STAT1_X = 24, /* 10GBASE-X PCS status 1 register */ + PCS_STAT1_R = 32, /* 10GBASE-R PCS status 1 register */ + XS_LN_STAT = 24 /* XS lane status register */ +}; + +enum { AEL100X_TX_DISABLE = 9, AEL100X_TX_CONFIG1 = 0xc002, AEL1002_PWR_DOWN_HI = 0xc011, AEL1002_PWR_DOWN_LO = 0xc012, AEL1002_XFI_EQL = 0xc015, AEL1002_LB_EN = 0xc017, + AEL_OPT_SETTINGS = 0xc017, + AEL_I2C_CTRL = 0xc30a, + AEL_I2C_DATA = 0xc30b, + AEL_I2C_STAT = 0xc30c, + AEL2005_GPIO_CTRL = 0xc214, + AEL2005_GPIO_STAT = 0xc215, +}; + +enum { edc_none, edc_sr, edc_twinax }; - LASI_CTRL = 0x9002, - LASI_STAT = 0x9005 +/* PHY module I2C device address */ +#define MODULE_DEV_ADDR 0xa0 + +#define AEL2005_MODDET_IRQ 4 + +struct reg_val { + unsigned short mmd_addr; + unsigned short reg_addr; + unsigned short clear_bits; + unsigned short set_bits; }; +static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) +{ + int err; + + for (err = 0; rv->mmd_addr && !err; rv++) { + if (rv->clear_bits == 0xffff) + err = mdio_write(phy, rv->mmd_addr, rv->reg_addr, + rv->set_bits); + else + err = t3_mdio_change_bits(phy, rv->mmd_addr, + rv->reg_addr, rv->clear_bits, + rv->set_bits); + } + return err; +} + static void ael100x_txon(struct cphy *phy) { int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; @@ -84,23 +124,23 @@ static int ael1002_intr_noop(struct cphy *phy) return 0; } -static int ael100x_get_link_status(struct cphy *phy, int *link_ok, - int *speed, int *duplex, int *fc) +/* + * Get link status for a 10GBASE-R device. + */ +static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed, + int *duplex, int *fc) { if (link_ok) { - unsigned int status; - int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status); - - /* - * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it - * once more to get the current link state. - */ - if (!err && !(status & BMSR_LSTATUS)) - err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, - &status); + unsigned int stat0, stat1, stat2; + int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); + + if (!err) + err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_R, &stat1); + if (!err) + err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); if (err) return err; - *link_ok = !!(status & BMSR_LSTATUS); + *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1; } if (speed) *speed = SPEED_10000; @@ -115,15 +155,18 @@ static struct cphy_ops ael1002_ops = { .intr_disable = ael1002_intr_noop, .intr_clear = ael1002_intr_noop, .intr_handler = ael1002_intr_noop, - .get_link_status = ael100x_get_link_status, + .get_link_status = get_link_status_r, .power_down = ael1002_power_down, }; -void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) +int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) { - cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops); + cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, + "10GBASE-R"); ael100x_txon(phy); + return 0; } static int ael1006_reset(struct cphy *phy, int wait) @@ -131,72 +174,985 @@ static int ael1006_reset(struct cphy *phy, int wait) return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); } -static int ael1006_intr_enable(struct cphy *phy) +static int ael1006_power_down(struct cphy *phy, int enable) { - return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); + return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, + BMCR_PDOWN, enable ? BMCR_PDOWN : 0); } -static int ael1006_intr_disable(struct cphy *phy) +static struct cphy_ops ael1006_ops = { + .reset = ael1006_reset, + .intr_enable = t3_phy_lasi_intr_enable, + .intr_disable = t3_phy_lasi_intr_disable, + .intr_clear = t3_phy_lasi_intr_clear, + .intr_handler = t3_phy_lasi_intr_handler, + .get_link_status = get_link_status_r, + .power_down = ael1006_power_down, +}; + +int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) { - return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); + cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, + "10GBASE-SR"); + ael100x_txon(phy); + return 0; } -static int ael1006_intr_clear(struct cphy *phy) +static int ael2005_setup_sr_edc(struct cphy *phy) { - u32 val; + static struct reg_val regs[] = { + { MDIO_DEV_PMA_PMD, 0xc003, 0xffff, 0x181 }, + { MDIO_DEV_PMA_PMD, 0xc010, 0xffff, 0x448a }, + { MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5200 }, + { 0, 0, 0, 0 } + }; + static u16 sr_edc[] = { + 0xcc00, 0x2ff4, + 0xcc01, 0x3cd4, + 0xcc02, 0x2015, + 0xcc03, 0x3105, + 0xcc04, 0x6524, + 0xcc05, 0x27ff, + 0xcc06, 0x300f, + 0xcc07, 0x2c8b, + 0xcc08, 0x300b, + 0xcc09, 0x4009, + 0xcc0a, 0x400e, + 0xcc0b, 0x2f72, + 0xcc0c, 0x3002, + 0xcc0d, 0x1002, + 0xcc0e, 0x2172, + 0xcc0f, 0x3012, + 0xcc10, 0x1002, + 0xcc11, 0x25d2, + 0xcc12, 0x3012, + 0xcc13, 0x1002, + 0xcc14, 0xd01e, + 0xcc15, 0x27d2, + 0xcc16, 0x3012, + 0xcc17, 0x1002, + 0xcc18, 0x2004, + 0xcc19, 0x3c84, + 0xcc1a, 0x6436, + 0xcc1b, 0x2007, + 0xcc1c, 0x3f87, + 0xcc1d, 0x8676, + 0xcc1e, 0x40b7, + 0xcc1f, 0xa746, + 0xcc20, 0x4047, + 0xcc21, 0x5673, + 0xcc22, 0x2982, + 0xcc23, 0x3002, + 0xcc24, 0x13d2, + 0xcc25, 0x8bbd, + 0xcc26, 0x2862, + 0xcc27, 0x3012, + 0xcc28, 0x1002, + 0xcc29, 0x2092, + 0xcc2a, 0x3012, + 0xcc2b, 0x1002, + 0xcc2c, 0x5cc3, + 0xcc2d, 0x314, + 0xcc2e, 0x2942, + 0xcc2f, 0x3002, + 0xcc30, 0x1002, + 0xcc31, 0xd019, + 0xcc32, 0x2032, + 0xcc33, 0x3012, + 0xcc34, 0x1002, + 0xcc35, 0x2a04, + 0xcc36, 0x3c74, + 0xcc37, 0x6435, + 0xcc38, 0x2fa4, + 0xcc39, 0x3cd4, + 0xcc3a, 0x6624, + 0xcc3b, 0x5563, + 0xcc3c, 0x2d42, + 0xcc3d, 0x3002, + 0xcc3e, 0x13d2, + 0xcc3f, 0x464d, + 0xcc40, 0x2862, + 0xcc41, 0x3012, + 0xcc42, 0x1002, + 0xcc43, 0x2032, + 0xcc44, 0x3012, + 0xcc45, 0x1002, + 0xcc46, 0x2fb4, + 0xcc47, 0x3cd4, + 0xcc48, 0x6624, + 0xcc49, 0x5563, + 0xcc4a, 0x2d42, + 0xcc4b, 0x3002, + 0xcc4c, 0x13d2, + 0xcc4d, 0x2ed2, + 0xcc4e, 0x3002, + 0xcc4f, 0x1002, + 0xcc50, 0x2fd2, + 0xcc51, 0x3002, + 0xcc52, 0x1002, + 0xcc53, 0x004, + 0xcc54, 0x2942, + 0xcc55, 0x3002, + 0xcc56, 0x1002, + 0xcc57, 0x2092, + 0xcc58, 0x3012, + 0xcc59, 0x1002, + 0xcc5a, 0x5cc3, + 0xcc5b, 0x317, + 0xcc5c, 0x2f72, + 0xcc5d, 0x3002, + 0xcc5e, 0x1002, + 0xcc5f, 0x2942, + 0xcc60, 0x3002, + 0xcc61, 0x1002, + 0xcc62, 0x22cd, + 0xcc63, 0x301d, + 0xcc64, 0x2862, + 0xcc65, 0x3012, + 0xcc66, 0x1002, + 0xcc67, 0x2ed2, + 0xcc68, 0x3002, + 0xcc69, 0x1002, + 0xcc6a, 0x2d72, + 0xcc6b, 0x3002, + 0xcc6c, 0x1002, + 0xcc6d, 0x628f, + 0xcc6e, 0x2112, + 0xcc6f, 0x3012, + 0xcc70, 0x1002, + 0xcc71, 0x5aa3, + 0xcc72, 0x2dc2, + 0xcc73, 0x3002, + 0xcc74, 0x1312, + 0xcc75, 0x6f72, + 0xcc76, 0x1002, + 0xcc77, 0x2807, + 0xcc78, 0x31a7, + 0xcc79, 0x20c4, + 0xcc7a, 0x3c24, + 0xcc7b, 0x6724, + 0xcc7c, 0x1002, + 0xcc7d, 0x2807, + 0xcc7e, 0x3187, + 0xcc7f, 0x20c4, + 0xcc80, 0x3c24, + 0xcc81, 0x6724, + 0xcc82, 0x1002, + 0xcc83, 0x2514, + 0xcc84, 0x3c64, + 0xcc85, 0x6436, + 0xcc86, 0xdff4, + 0xcc87, 0x6436, + 0xcc88, 0x1002, + 0xcc89, 0x40a4, + 0xcc8a, 0x643c, + 0xcc8b, 0x4016, + 0xcc8c, 0x8c6c, + 0xcc8d, 0x2b24, + 0xcc8e, 0x3c24, + 0xcc8f, 0x6435, + 0xcc90, 0x1002, + 0xcc91, 0x2b24, + 0xcc92, 0x3c24, + 0xcc93, 0x643a, + 0xcc94, 0x4025, + 0xcc95, 0x8a5a, + 0xcc96, 0x1002, + 0xcc97, 0x2731, + 0xcc98, 0x3011, + 0xcc99, 0x1001, + 0xcc9a, 0xc7a0, + 0xcc9b, 0x100, + 0xcc9c, 0xc502, + 0xcc9d, 0x53ac, + 0xcc9e, 0xc503, + 0xcc9f, 0xd5d5, + 0xcca0, 0xc600, + 0xcca1, 0x2a6d, + 0xcca2, 0xc601, + 0xcca3, 0x2a4c, + 0xcca4, 0xc602, + 0xcca5, 0x111, + 0xcca6, 0xc60c, + 0xcca7, 0x5900, + 0xcca8, 0xc710, + 0xcca9, 0x700, + 0xccaa, 0xc718, + 0xccab, 0x700, + 0xccac, 0xc720, + 0xccad, 0x4700, + 0xccae, 0xc801, + 0xccaf, 0x7f50, + 0xccb0, 0xc802, + 0xccb1, 0x7760, + 0xccb2, 0xc803, + 0xccb3, 0x7fce, + 0xccb4, 0xc804, + 0xccb5, 0x5700, + 0xccb6, 0xc805, + 0xccb7, 0x5f11, + 0xccb8, 0xc806, + 0xccb9, 0x4751, + 0xccba, 0xc807, + 0xccbb, 0x57e1, + 0xccbc, 0xc808, + 0xccbd, 0x2700, + 0xccbe, 0xc809, + 0xccbf, 0x000, + 0xccc0, 0xc821, + 0xccc1, 0x002, + 0xccc2, 0xc822, + 0xccc3, 0x014, + 0xccc4, 0xc832, + 0xccc5, 0x1186, + 0xccc6, 0xc847, + 0xccc7, 0x1e02, + 0xccc8, 0xc013, + 0xccc9, 0xf341, + 0xccca, 0xc01a, + 0xcccb, 0x446, + 0xcccc, 0xc024, + 0xcccd, 0x1000, + 0xccce, 0xc025, + 0xcccf, 0xa00, + 0xccd0, 0xc026, + 0xccd1, 0xc0c, + 0xccd2, 0xc027, + 0xccd3, 0xc0c, + 0xccd4, 0xc029, + 0xccd5, 0x0a0, + 0xccd6, 0xc030, + 0xccd7, 0xa00, + 0xccd8, 0xc03c, + 0xccd9, 0x01c, + 0xccda, 0xc005, + 0xccdb, 0x7a06, + 0xccdc, 0x000, + 0xccdd, 0x2731, + 0xccde, 0x3011, + 0xccdf, 0x1001, + 0xcce0, 0xc620, + 0xcce1, 0x000, + 0xcce2, 0xc621, + 0xcce3, 0x03f, + 0xcce4, 0xc622, + 0xcce5, 0x000, + 0xcce6, 0xc623, + 0xcce7, 0x000, + 0xcce8, 0xc624, + 0xcce9, 0x000, + 0xccea, 0xc625, + 0xcceb, 0x000, + 0xccec, 0xc627, + 0xcced, 0x000, + 0xccee, 0xc628, + 0xccef, 0x000, + 0xccf0, 0xc62c, + 0xccf1, 0x000, + 0xccf2, 0x000, + 0xccf3, 0x2806, + 0xccf4, 0x3cb6, + 0xccf5, 0xc161, + 0xccf6, 0x6134, + 0xccf7, 0x6135, + 0xccf8, 0x5443, + 0xccf9, 0x303, + 0xccfa, 0x6524, + 0xccfb, 0x00b, + 0xccfc, 0x1002, + 0xccfd, 0x2104, + 0xccfe, 0x3c24, + 0xccff, 0x2105, + 0xcd00, 0x3805, + 0xcd01, 0x6524, + 0xcd02, 0xdff4, + 0xcd03, 0x4005, + 0xcd04, 0x6524, + 0xcd05, 0x1002, + 0xcd06, 0x5dd3, + 0xcd07, 0x306, + 0xcd08, 0x2ff7, + 0xcd09, 0x38f7, + 0xcd0a, 0x60b7, + 0xcd0b, 0xdffd, + 0xcd0c, 0x00a, + 0xcd0d, 0x1002, + 0xcd0e, 0 + }; + int i, err; + + err = set_phy_regs(phy, regs); + if (err) + return err; - return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); + msleep(50); + + for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2) + err = mdio_write(phy, MDIO_DEV_PMA_PMD, sr_edc[i], + sr_edc[i + 1]); + if (!err) + phy->priv = edc_sr; + return err; } -static int ael1006_intr_handler(struct cphy *phy) +static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) { - unsigned int status; - int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); + static struct reg_val regs[] = { + { MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5a00 }, + { 0, 0, 0, 0 } + }; + static struct reg_val preemphasis[] = { + { MDIO_DEV_PMA_PMD, 0xc014, 0xffff, 0xfe16 }, + { MDIO_DEV_PMA_PMD, 0xc015, 0xffff, 0xa000 }, + { 0, 0, 0, 0 } + }; + static u16 twinax_edc[] = { + 0xcc00, 0x4009, + 0xcc01, 0x27ff, + 0xcc02, 0x300f, + 0xcc03, 0x40aa, + 0xcc04, 0x401c, + 0xcc05, 0x401e, + 0xcc06, 0x2ff4, + 0xcc07, 0x3cd4, + 0xcc08, 0x2035, + 0xcc09, 0x3145, + 0xcc0a, 0x6524, + 0xcc0b, 0x26a2, + 0xcc0c, 0x3012, + 0xcc0d, 0x1002, + 0xcc0e, 0x29c2, + 0xcc0f, 0x3002, + 0xcc10, 0x1002, + 0xcc11, 0x2072, + 0xcc12, 0x3012, + 0xcc13, 0x1002, + 0xcc14, 0x22cd, + 0xcc15, 0x301d, + 0xcc16, 0x2e52, + 0xcc17, 0x3012, + 0xcc18, 0x1002, + 0xcc19, 0x28e2, + 0xcc1a, 0x3002, + 0xcc1b, 0x1002, + 0xcc1c, 0x628f, + 0xcc1d, 0x2ac2, + 0xcc1e, 0x3012, + 0xcc1f, 0x1002, + 0xcc20, 0x5553, + 0xcc21, 0x2ae2, + 0xcc22, 0x3002, + 0xcc23, 0x1302, + 0xcc24, 0x401e, + 0xcc25, 0x2be2, + 0xcc26, 0x3012, + 0xcc27, 0x1002, + 0xcc28, 0x2da2, + 0xcc29, 0x3012, + 0xcc2a, 0x1002, + 0xcc2b, 0x2ba2, + 0xcc2c, 0x3002, + 0xcc2d, 0x1002, + 0xcc2e, 0x5ee3, + 0xcc2f, 0x305, + 0xcc30, 0x400e, + 0xcc31, 0x2bc2, + 0xcc32, 0x3002, + 0xcc33, 0x1002, + 0xcc34, 0x2b82, + 0xcc35, 0x3012, + 0xcc36, 0x1002, + 0xcc37, 0x5663, + 0xcc38, 0x302, + 0xcc39, 0x401e, + 0xcc3a, 0x6f72, + 0xcc3b, 0x1002, + 0xcc3c, 0x628f, + 0xcc3d, 0x2be2, + 0xcc3e, 0x3012, + 0xcc3f, 0x1002, + 0xcc40, 0x22cd, + 0xcc41, 0x301d, + 0xcc42, 0x2e52, + 0xcc43, 0x3012, + 0xcc44, 0x1002, + 0xcc45, 0x2522, + 0xcc46, 0x3012, + 0xcc47, 0x1002, + 0xcc48, 0x2da2, + 0xcc49, 0x3012, + 0xcc4a, 0x1002, + 0xcc4b, 0x2ca2, + 0xcc4c, 0x3012, + 0xcc4d, 0x1002, + 0xcc4e, 0x2fa4, + 0xcc4f, 0x3cd4, + 0xcc50, 0x6624, + 0xcc51, 0x410b, + 0xcc52, 0x56b3, + 0xcc53, 0x3c4, + 0xcc54, 0x2fb2, + 0xcc55, 0x3002, + 0xcc56, 0x1002, + 0xcc57, 0x220b, + 0xcc58, 0x303b, + 0xcc59, 0x56b3, + 0xcc5a, 0x3c3, + 0xcc5b, 0x866b, + 0xcc5c, 0x400c, + 0xcc5d, 0x23a2, + 0xcc5e, 0x3012, + 0xcc5f, 0x1002, + 0xcc60, 0x2da2, + 0xcc61, 0x3012, + 0xcc62, 0x1002, + 0xcc63, 0x2ca2, + 0xcc64, 0x3012, + 0xcc65, 0x1002, + 0xcc66, 0x2fb4, + 0xcc67, 0x3cd4, + 0xcc68, 0x6624, + 0xcc69, 0x56b3, + 0xcc6a, 0x3c3, + 0xcc6b, 0x866b, + 0xcc6c, 0x401c, + 0xcc6d, 0x2205, + 0xcc6e, 0x3035, + 0xcc6f, 0x5b53, + 0xcc70, 0x2c52, + 0xcc71, 0x3002, + 0xcc72, 0x13c2, + 0xcc73, 0x5cc3, + 0xcc74, 0x317, + 0xcc75, 0x2522, + 0xcc76, 0x3012, + 0xcc77, 0x1002, + 0xcc78, 0x2da2, + 0xcc79, 0x3012, + 0xcc7a, 0x1002, + 0xcc7b, 0x2b82, + 0xcc7c, 0x3012, + 0xcc7d, 0x1002, + 0xcc7e, 0x5663, + 0xcc7f, 0x303, + 0xcc80, 0x401e, + 0xcc81, 0x004, + 0xcc82, 0x2c42, + 0xcc83, 0x3012, + 0xcc84, 0x1002, + 0xcc85, 0x6f72, + 0xcc86, 0x1002, + 0xcc87, 0x628f, + 0xcc88, 0x2304, + 0xcc89, 0x3c84, + 0xcc8a, 0x6436, + 0xcc8b, 0xdff4, + 0xcc8c, 0x6436, + 0xcc8d, 0x2ff5, + 0xcc8e, 0x3005, + 0xcc8f, 0x8656, + 0xcc90, 0xdfba, + 0xcc91, 0x56a3, + 0xcc92, 0xd05a, + 0xcc93, 0x21c2, + 0xcc94, 0x3012, + 0xcc95, 0x1392, + 0xcc96, 0xd05a, + 0xcc97, 0x56a3, + 0xcc98, 0xdfba, + 0xcc99, 0x383, + 0xcc9a, 0x6f72, + 0xcc9b, 0x1002, + 0xcc9c, 0x28c5, + 0xcc9d, 0x3005, + 0xcc9e, 0x4178, + 0xcc9f, 0x5653, + 0xcca0, 0x384, + 0xcca1, 0x22b2, + 0xcca2, 0x3012, + 0xcca3, 0x1002, + 0xcca4, 0x2be5, + 0xcca5, 0x3005, + 0xcca6, 0x41e8, + 0xcca7, 0x5653, + 0xcca8, 0x382, + 0xcca9, 0x002, + 0xccaa, 0x4258, + 0xccab, 0x2474, + 0xccac, 0x3c84, + 0xccad, 0x6437, + 0xccae, 0xdff4, + 0xccaf, 0x6437, + 0xccb0, 0x2ff5, + 0xccb1, 0x3c05, + 0xccb2, 0x8757, + 0xccb3, 0xb888, + 0xccb4, 0x9787, + 0xccb5, 0xdff4, + 0xccb6, 0x6724, + 0xccb7, 0x866a, + 0xccb8, 0x6f72, + 0xccb9, 0x1002, + 0xccba, 0x2d01, + 0xccbb, 0x3011, + 0xccbc, 0x1001, + 0xccbd, 0xc620, + 0xccbe, 0x14e5, + 0xccbf, 0xc621, + 0xccc0, 0xc53d, + 0xccc1, 0xc622, + 0xccc2, 0x3cbe, + 0xccc3, 0xc623, + 0xccc4, 0x4452, + 0xccc5, 0xc624, + 0xccc6, 0xc5c5, + 0xccc7, 0xc625, + 0xccc8, 0xe01e, + 0xccc9, 0xc627, + 0xccca, 0x000, + 0xcccb, 0xc628, + 0xcccc, 0x000, + 0xcccd, 0xc62b, + 0xccce, 0x000, + 0xcccf, 0xc62c, + 0xccd0, 0x000, + 0xccd1, 0x000, + 0xccd2, 0x2d01, + 0xccd3, 0x3011, + 0xccd4, 0x1001, + 0xccd5, 0xc620, + 0xccd6, 0x000, + 0xccd7, 0xc621, + 0xccd8, 0x000, + 0xccd9, 0xc622, + 0xccda, 0x0ce, + 0xccdb, 0xc623, + 0xccdc, 0x07f, + 0xccdd, 0xc624, + 0xccde, 0x032, + 0xccdf, 0xc625, + 0xcce0, 0x000, + 0xcce1, 0xc627, + 0xcce2, 0x000, + 0xcce3, 0xc628, + 0xcce4, 0x000, + 0xcce5, 0xc62b, + 0xcce6, 0x000, + 0xcce7, 0xc62c, + 0xcce8, 0x000, + 0xcce9, 0x000, + 0xccea, 0x2d01, + 0xcceb, 0x3011, + 0xccec, 0x1001, + 0xcced, 0xc502, + 0xccee, 0x609f, + 0xccef, 0xc600, + 0xccf0, 0x2a6e, + 0xccf1, 0xc601, + 0xccf2, 0x2a2c, + 0xccf3, 0xc60c, + 0xccf4, 0x5400, + 0xccf5, 0xc710, + 0xccf6, 0x700, + 0xccf7, 0xc718, + 0xccf8, 0x700, + 0xccf9, 0xc720, + 0xccfa, 0x4700, + 0xccfb, 0xc728, + 0xccfc, 0x700, + 0xccfd, 0xc729, + 0xccfe, 0x1207, + 0xccff, 0xc801, + 0xcd00, 0x7f50, + 0xcd01, 0xc802, + 0xcd02, 0x7760, + 0xcd03, 0xc803, + 0xcd04, 0x7fce, + 0xcd05, 0xc804, + 0xcd06, 0x520e, + 0xcd07, 0xc805, + 0xcd08, 0x5c11, + 0xcd09, 0xc806, + 0xcd0a, 0x3c51, + 0xcd0b, 0xc807, + 0xcd0c, 0x4061, + 0xcd0d, 0xc808, + 0xcd0e, 0x49c1, + 0xcd0f, 0xc809, + 0xcd10, 0x3840, + 0xcd11, 0xc80a, + 0xcd12, 0x000, + 0xcd13, 0xc821, + 0xcd14, 0x002, + 0xcd15, 0xc822, + 0xcd16, 0x046, + 0xcd17, 0xc844, + 0xcd18, 0x182f, + 0xcd19, 0xc013, + 0xcd1a, 0xf341, + 0xcd1b, 0xc01a, + 0xcd1c, 0x446, + 0xcd1d, 0xc024, + 0xcd1e, 0x1000, + 0xcd1f, 0xc025, + 0xcd20, 0xa00, + 0xcd21, 0xc026, + 0xcd22, 0xc0c, + 0xcd23, 0xc027, + 0xcd24, 0xc0c, + 0xcd25, 0xc029, + 0xcd26, 0x0a0, + 0xcd27, 0xc030, + 0xcd28, 0xa00, + 0xcd29, 0xc03c, + 0xcd2a, 0x01c, + 0xcd2b, 0x000, + 0xcd2c, 0x2b84, + 0xcd2d, 0x3c74, + 0xcd2e, 0x6435, + 0xcd2f, 0xdff4, + 0xcd30, 0x6435, + 0xcd31, 0x2806, + 0xcd32, 0x3006, + 0xcd33, 0x8565, + 0xcd34, 0x2b24, + 0xcd35, 0x3c24, + 0xcd36, 0x6436, + 0xcd37, 0x1002, + 0xcd38, 0x2b24, + 0xcd39, 0x3c24, + 0xcd3a, 0x6436, + 0xcd3b, 0x4045, + 0xcd3c, 0x8656, + 0xcd3d, 0x1002, + 0xcd3e, 0x2807, + 0xcd3f, 0x31a7, + 0xcd40, 0x20c4, + 0xcd41, 0x3c24, + 0xcd42, 0x6724, + 0xcd43, 0x1002, + 0xcd44, 0x2807, + 0xcd45, 0x3187, + 0xcd46, 0x20c4, + 0xcd47, 0x3c24, + 0xcd48, 0x6724, + 0xcd49, 0x1002, + 0xcd4a, 0x2514, + 0xcd4b, 0x3c64, + 0xcd4c, 0x6436, + 0xcd4d, 0xdff4, + 0xcd4e, 0x6436, + 0xcd4f, 0x1002, + 0xcd50, 0x2806, + 0xcd51, 0x3cb6, + 0xcd52, 0xc161, + 0xcd53, 0x6134, + 0xcd54, 0x6135, + 0xcd55, 0x5443, + 0xcd56, 0x303, + 0xcd57, 0x6524, + 0xcd58, 0x00b, + 0xcd59, 0x1002, + 0xcd5a, 0xd019, + 0xcd5b, 0x2104, + 0xcd5c, 0x3c24, + 0xcd5d, 0x2105, + 0xcd5e, 0x3805, + 0xcd5f, 0x6524, + 0xcd60, 0xdff4, + 0xcd61, 0x4005, + 0xcd62, 0x6524, + 0xcd63, 0x2e8d, + 0xcd64, 0x303d, + 0xcd65, 0x5dd3, + 0xcd66, 0x306, + 0xcd67, 0x2ff7, + 0xcd68, 0x38f7, + 0xcd69, 0x60b7, + 0xcd6a, 0xdffd, + 0xcd6b, 0x00a, + 0xcd6c, 0x1002, + 0xcd6d, 0 + }; + int i, err; + err = set_phy_regs(phy, regs); + if (!err && modtype == phy_modtype_twinax_long) + err = set_phy_regs(phy, preemphasis); if (err) return err; - return (status & 1) ? cphy_cause_link_change : 0; + + msleep(50); + + for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) + err = mdio_write(phy, MDIO_DEV_PMA_PMD, twinax_edc[i], + twinax_edc[i + 1]); + if (!err) + phy->priv = edc_twinax; + return err; } -static int ael1006_power_down(struct cphy *phy, int enable) +static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) { - return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, - BMCR_PDOWN, enable ? BMCR_PDOWN : 0); + int i, err; + unsigned int stat, data; + + err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL_I2C_CTRL, + (dev_addr << 8) | (1 << 8) | word_addr); + if (err) + return err; + + for (i = 0; i < 5; i++) { + msleep(1); + err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_STAT, &stat); + if (err) + return err; + if ((stat & 3) == 1) { + err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_DATA, + &data); + if (err) + return err; + return data >> 8; + } + } + CH_WARN(phy->adapter, "PHY %u I2C read of addr %u timed out\n", + phy->addr, word_addr); + return -ETIMEDOUT; } -static struct cphy_ops ael1006_ops = { - .reset = ael1006_reset, - .intr_enable = ael1006_intr_enable, - .intr_disable = ael1006_intr_disable, - .intr_clear = ael1006_intr_clear, - .intr_handler = ael1006_intr_handler, - .get_link_status = ael100x_get_link_status, - .power_down = ael1006_power_down, +static int get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + unsigned int stat; + + v = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, &stat); + if (v) + return v; + + if (stat & (1 << 8)) /* module absent */ + return phy_modtype_none; + + if (delay_ms) + msleep(delay_ms); + + /* see SFF-8472 for below */ + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3); + if (v < 0) + return v; + + if (v == 0x10) + return phy_modtype_sr; + if (v == 0x20) + return phy_modtype_lr; + if (v == 0x40) + return phy_modtype_lrm; + + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6); + if (v < 0) + return v; + if (v != 4) + goto unknown; + + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10); + if (v < 0) + return v; + + if (v & 0x80) { + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); + if (v < 0) + return v; + return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax; + } +unknown: + return phy_modtype_unknown; +} + +static int ael2005_intr_enable(struct cphy *phy) +{ + int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x200); + return err ? err : t3_phy_lasi_intr_enable(phy); +} + +static int ael2005_intr_disable(struct cphy *phy) +{ + int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x100); + return err ? err : t3_phy_lasi_intr_disable(phy); +} + +static int ael2005_intr_clear(struct cphy *phy) +{ + int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0xd00); + return err ? err : t3_phy_lasi_intr_clear(phy); +} + +static int ael2005_reset(struct cphy *phy, int wait) +{ + static struct reg_val regs0[] = { + { MDIO_DEV_PMA_PMD, 0xc001, 0, 1 << 5 }, + { MDIO_DEV_PMA_PMD, 0xc017, 0, 1 << 5 }, + { MDIO_DEV_PMA_PMD, 0xc013, 0xffff, 0xf341 }, + { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 }, + { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8100 }, + { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 }, + { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0 }, + { 0, 0, 0, 0 } + }; + static struct reg_val regs1[] = { + { MDIO_DEV_PMA_PMD, 0xca00, 0xffff, 0x0080 }, + { MDIO_DEV_PMA_PMD, 0xca12, 0xffff, 0 }, + { 0, 0, 0, 0 } + }; + + int err, lasi_ctrl; + + err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, &lasi_ctrl); + if (err) + return err; + + err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, 0); + if (err) + return err; + + msleep(125); + phy->priv = edc_none; + err = set_phy_regs(phy, regs0); + if (err) + return err; + + msleep(50); + + err = get_module_type(phy, 0); + if (err < 0) + return err; + phy->modtype = err; + + if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) + err = ael2005_setup_twinax_edc(phy, err); + else + err = ael2005_setup_sr_edc(phy); + if (err) + return err; + + err = set_phy_regs(phy, regs1); + if (err) + return err; + + /* reset wipes out interrupts, reenable them if they were on */ + if (lasi_ctrl & 1) + err = ael2005_intr_enable(phy); + return err; +} + +static int ael2005_intr_handler(struct cphy *phy) +{ + unsigned int stat; + int ret, edc_needed, cause = 0; + + ret = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_STAT, &stat); + if (ret) + return ret; + + if (stat & AEL2005_MODDET_IRQ) { + ret = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, + 0xd00); + if (ret) + return ret; + + /* modules have max 300 ms init time after hot plug */ + ret = get_module_type(phy, 300); + if (ret < 0) + return ret; + + phy->modtype = ret; + if (ret == phy_modtype_none) + edc_needed = phy->priv; /* on unplug retain EDC */ + else if (ret == phy_modtype_twinax || + ret == phy_modtype_twinax_long) + edc_needed = edc_twinax; + else + edc_needed = edc_sr; + + if (edc_needed != phy->priv) { + ret = ael2005_reset(phy, 0); + return ret ? ret : cphy_cause_module_change; + } + cause = cphy_cause_module_change; + } + + ret = t3_phy_lasi_intr_handler(phy); + if (ret < 0) + return ret; + + ret |= cause; + return ret ? ret : cphy_cause_link_change; +} + +static struct cphy_ops ael2005_ops = { + .reset = ael2005_reset, + .intr_enable = ael2005_intr_enable, + .intr_disable = ael2005_intr_disable, + .intr_clear = ael2005_intr_clear, + .intr_handler = ael2005_intr_handler, + .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, }; -void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) +int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) { - cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops); - ael100x_txon(phy); + cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_IRQ, "10GBASE-R"); + msleep(125); + return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL_OPT_SETTINGS, 0, + 1 << 5); +} + +/* + * Get link status for a 10GBASE-X device. + */ +static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, + int *duplex, int *fc) +{ + if (link_ok) { + unsigned int stat0, stat1, stat2; + int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); + + if (!err) + err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_X, &stat1); + if (!err) + err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); + if (err) + return err; + *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1; + } + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + return 0; } static struct cphy_ops qt2045_ops = { .reset = ael1006_reset, - .intr_enable = ael1006_intr_enable, - .intr_disable = ael1006_intr_disable, - .intr_clear = ael1006_intr_clear, - .intr_handler = ael1006_intr_handler, - .get_link_status = ael100x_get_link_status, + .intr_enable = t3_phy_lasi_intr_enable, + .intr_disable = t3_phy_lasi_intr_disable, + .intr_clear = t3_phy_lasi_intr_clear, + .intr_handler = t3_phy_lasi_intr_handler, + .get_link_status = get_link_status_x, .power_down = ael1006_power_down, }; -void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) +int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) { unsigned int stat; - cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops); + cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, + "10GBASE-CX4"); /* * Some cards where the PHY is supposed to be at address 0 actually @@ -205,6 +1161,7 @@ void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) && stat == 0xffff) phy->addr = 1; + return 0; } static int xaui_direct_reset(struct cphy *phy, int wait) @@ -250,8 +1207,11 @@ static struct cphy_ops xaui_direct_ops = { .power_down = xaui_direct_power_down, }; -void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) +int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) { - cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops); + cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, + "10GBASE-CX4"); + return 0; } diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 9ecf8a6dc97..e312d315a42 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -193,22 +193,13 @@ struct mdio_ops { struct adapter_info { unsigned char nports; /* # of ports */ unsigned char phy_base_addr; /* MDIO PHY base address */ - unsigned char mdien; - unsigned char mdiinv; unsigned int gpio_out; /* GPIO output settings */ - unsigned int gpio_intr; /* GPIO IRQ enable mask */ + unsigned char gpio_intr[MAX_NPORTS]; /* GPIO PHY IRQ pins */ unsigned long caps; /* adapter capabilities */ const struct mdio_ops *mdio_ops; /* MDIO operations */ const char *desc; /* product description */ }; -struct port_type_info { - void (*phy_prep)(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *ops); - unsigned int caps; - const char *desc; -}; - struct mc5_stats { unsigned long parity_err; unsigned long active_rgn_full; @@ -358,6 +349,7 @@ struct qset_params { /* SGE queue set parameters */ unsigned int jumbo_size; /* # of entries in jumbo free list */ unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */ unsigned int cong_thres; /* FL congestion threshold */ + unsigned int vector; /* Interrupt (line or vector) number */ }; struct sge_params { @@ -525,12 +517,25 @@ enum { MAC_RXFIFO_SIZE = 32768 }; -/* IEEE 802.3ae specified MDIO devices */ +/* IEEE 802.3 specified MDIO devices */ enum { MDIO_DEV_PMA_PMD = 1, MDIO_DEV_WIS = 2, MDIO_DEV_PCS = 3, - MDIO_DEV_XGXS = 4 + MDIO_DEV_XGXS = 4, + MDIO_DEV_ANEG = 7, + MDIO_DEV_VEND1 = 30, + MDIO_DEV_VEND2 = 31 +}; + +/* LASI control and status registers */ +enum { + RX_ALARM_CTRL = 0x9000, + TX_ALARM_CTRL = 0x9001, + LASI_CTRL = 0x9002, + RX_ALARM_STAT = 0x9003, + TX_ALARM_STAT = 0x9004, + LASI_STAT = 0x9005 }; /* PHY loopback direction */ @@ -542,12 +547,23 @@ enum { /* PHY interrupt types */ enum { cphy_cause_link_change = 1, - cphy_cause_fifo_error = 2 + cphy_cause_fifo_error = 2, + cphy_cause_module_change = 4, +}; + +/* PHY module types */ +enum { + phy_modtype_none, + phy_modtype_sr, + phy_modtype_lr, + phy_modtype_lrm, + phy_modtype_twinax, + phy_modtype_twinax_long, + phy_modtype_unknown }; /* PHY operations */ struct cphy_ops { - void (*destroy)(struct cphy *phy); int (*reset)(struct cphy *phy, int wait); int (*intr_enable)(struct cphy *phy); @@ -568,8 +584,12 @@ struct cphy_ops { /* A PHY instance */ struct cphy { - int addr; /* PHY address */ + u8 addr; /* PHY address */ + u8 modtype; /* PHY module type */ + short priv; /* scratch pad */ + unsigned int caps; /* PHY capabilities */ struct adapter *adapter; /* associated adapter */ + const char *desc; /* PHY description */ unsigned long fifo_errors; /* FIFO over/under-flows */ const struct cphy_ops *ops; /* PHY operations */ int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr, @@ -594,10 +614,13 @@ static inline int mdio_write(struct cphy *phy, int mmd, int reg, /* Convenience initializer */ static inline void cphy_init(struct cphy *phy, struct adapter *adapter, int phy_addr, struct cphy_ops *phy_ops, - const struct mdio_ops *mdio_ops) + const struct mdio_ops *mdio_ops, + unsigned int caps, const char *desc) { - phy->adapter = adapter; phy->addr = phy_addr; + phy->caps = caps; + phy->adapter = adapter; + phy->desc = desc; phy->ops = phy_ops; if (mdio_ops) { phy->mdio_read = mdio_ops->read; @@ -668,7 +691,12 @@ int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, unsigned int set); int t3_phy_reset(struct cphy *phy, int mmd, int wait); int t3_phy_advertise(struct cphy *phy, unsigned int advert); +int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert); int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); +int t3_phy_lasi_intr_enable(struct cphy *phy); +int t3_phy_lasi_intr_disable(struct cphy *phy); +int t3_phy_lasi_intr_clear(struct cphy *phy); +int t3_phy_lasi_intr_handler(struct cphy *phy); void t3_intr_enable(struct adapter *adapter); void t3_intr_disable(struct adapter *adapter); @@ -698,6 +726,7 @@ int t3_check_fw_version(struct adapter *adapter, int *must_load); int t3_init_hw(struct adapter *adapter, u32 fw_params); void mac_prep(struct cmac *mac, struct adapter *adapter, int index); void early_hw_init(struct adapter *adapter, const struct adapter_info *ai); +int t3_reset_adapter(struct adapter *adapter); int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, int reset); int t3_replay_prep_adapter(struct adapter *adapter); @@ -774,14 +803,16 @@ int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]); int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, unsigned int credits); -void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, - const struct mdio_ops *mdio_ops); -void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); +int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops); +int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); #endif /* __CHELSIO_COMMON_H */ diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h index 6ad92405d9a..1d8d46eb3c9 100644 --- a/drivers/net/cxgb3/cxgb3_ctl_defs.h +++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h index 45e92164c26..47e53769af5 100644 --- a/drivers/net/cxgb3/cxgb3_defs.h +++ b/drivers/net/cxgb3/cxgb3_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h index 68200a14065..b19e4376ba7 100644 --- a/drivers/net/cxgb3/cxgb3_ioctl.h +++ b/drivers/net/cxgb3/cxgb3_ioctl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -92,6 +92,8 @@ struct ch_qset_params { int32_t polling; int32_t lro; int32_t cong_thres; + int32_t vector; + int32_t qnum; }; struct ch_pktsched_params { diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 5447f3e60f0..1ace41a13ac 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -208,6 +208,31 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, } } +/** + * t3_os_phymod_changed - handle PHY module changes + * @phy: the PHY reporting the module change + * @mod_type: new module type + * + * This is the OS-dependent handler for PHY module changes. It is + * invoked when a PHY module is removed or inserted for any OS-specific + * processing. + */ +void t3_os_phymod_changed(struct adapter *adap, int port_id) +{ + static const char *mod_str[] = { + NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown" + }; + + const struct net_device *dev = adap->port[port_id]; + const struct port_info *pi = netdev_priv(dev); + + if (pi->phy.modtype == phy_modtype_none) + printk(KERN_INFO "%s: PHY module unplugged\n", dev->name); + else + printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name, + mod_str[pi->phy.modtype]); +} + static void cxgb_set_rxmode(struct net_device *dev) { struct t3_rx_mode rm; @@ -274,10 +299,10 @@ static void name_msix_vecs(struct adapter *adap) for (i = 0; i < pi->nqsets; i++, msi_idx++) { snprintf(adap->msix_info[msi_idx].desc, n, - "%s (queue %d)", d->name, i); + "%s-%d", d->name, pi->first_qset + i); adap->msix_info[msi_idx].desc[n] = 0; } - } + } } static int request_msix_data_irqs(struct adapter *adap) @@ -306,6 +331,22 @@ static int request_msix_data_irqs(struct adapter *adap) return 0; } +static void free_irq_resources(struct adapter *adapter) +{ + if (adapter->flags & USING_MSIX) { + int i, n = 0; + + free_irq(adapter->msix_info[0].vec, adapter); + for_each_port(adapter, i) + n += adap2pinfo(adapter, i)->nqsets; + + for (i = 0; i < n; ++i) + free_irq(adapter->msix_info[i + 1].vec, + &adapter->sge.qs[i]); + } else + free_irq(adapter->pdev->irq, adapter); +} + static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt, unsigned long n) { @@ -473,12 +514,16 @@ static int setup_sge_qsets(struct adapter *adap) struct port_info *pi = netdev_priv(dev); pi->qs = &adap->sge.qs[pi->first_qset]; - for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { + for (j = pi->first_qset; j < pi->first_qset + pi->nqsets; + ++j, ++qset_idx) { + if (!pi->rx_csum_offload) + adap->params.sge.qset[qset_idx].lro = 0; err = t3_sge_alloc_qset(adap, qset_idx, 1, (adap->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, &adap->params.sge.qset[qset_idx], ntxq, dev); if (err) { + t3_stop_sge_timers(adap); t3_free_sge_resources(adap); return err; } @@ -739,11 +784,12 @@ static void init_port_mtus(struct adapter *adapter) t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); } -static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, +static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, int hi, int port) { struct sk_buff *skb; struct mngt_pktsched_wr *req; + int ret; skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); @@ -754,20 +800,28 @@ static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, req->min = lo; req->max = hi; req->binding = port; - t3_mgmt_tx(adap, skb); + ret = t3_mgmt_tx(adap, skb); + + return ret; } -static void bind_qsets(struct adapter *adap) +static int bind_qsets(struct adapter *adap) { - int i, j; + int i, j, err = 0; for_each_port(adap, i) { const struct port_info *pi = adap2pinfo(adap, i); - for (j = 0; j < pi->nqsets; ++j) - send_pktsched_cmd(adap, 1, pi->first_qset + j, -1, - -1, i); + for (j = 0; j < pi->nqsets; ++j) { + int ret = send_pktsched_cmd(adap, 1, + pi->first_qset + j, -1, + -1, i); + if (ret) + err = ret; + } } + + return err; } #define FW_FNAME "t3fw-%d.%d.%d.bin" @@ -891,6 +945,13 @@ static int cxgb_up(struct adapter *adap) goto out; } + /* + * Clear interrupts now to catch errors if t3_init_hw fails. + * We clear them again later as initialization may trigger + * conditions that can interrupt. + */ + t3_intr_clear(adap); + err = t3_init_hw(adap, 0); if (err) goto out; @@ -946,9 +1007,16 @@ static int cxgb_up(struct adapter *adap) t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff); } - if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX) - bind_qsets(adap); - adap->flags |= QUEUES_BOUND; + if (!(adap->flags & QUEUES_BOUND)) { + err = bind_qsets(adap); + if (err) { + CH_ERR(adap, "failed to bind qsets, err %d\n", err); + t3_intr_disable(adap); + free_irq_resources(adap); + goto out; + } + adap->flags |= QUEUES_BOUND; + } out: return err; @@ -967,19 +1035,7 @@ static void cxgb_down(struct adapter *adapter) t3_intr_disable(adapter); spin_unlock_irq(&adapter->work_lock); - if (adapter->flags & USING_MSIX) { - int i, n = 0; - - free_irq(adapter->msix_info[0].vec, adapter); - for_each_port(adapter, i) - n += adap2pinfo(adapter, i)->nqsets; - - for (i = 0; i < n; ++i) - free_irq(adapter->msix_info[i + 1].vec, - &adapter->sge.qs[i]); - } else - free_irq(adapter->pdev->irq, adapter); - + free_irq_resources(adapter); flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */ quiesce_rx(adapter); } @@ -1100,9 +1156,9 @@ static int cxgb_close(struct net_device *dev) netif_carrier_off(dev); t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); - spin_lock(&adapter->work_lock); /* sync with update task */ + spin_lock_irq(&adapter->work_lock); /* sync with update task */ clear_bit(pi->port_id, &adapter->open_device_map); - spin_unlock(&adapter->work_lock); + spin_unlock_irq(&adapter->work_lock); if (!(adapter->open_device_map & PORT_MASK)) cancel_rearming_delayed_workqueue(cxgb3_wq, @@ -1284,8 +1340,8 @@ static unsigned long collect_sge_port_stats(struct adapter *adapter, int i; unsigned long tot = 0; - for (i = 0; i < p->nqsets; ++i) - tot += adapter->sge.qs[i + p->first_qset].port_stats[idx]; + for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i) + tot += adapter->sge.qs[i].port_stats[idx]; return tot; } @@ -1485,11 +1541,22 @@ static int speed_duplex_to_caps(int speed, int duplex) static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { + int cap; struct port_info *p = netdev_priv(dev); struct link_config *lc = &p->link_config; - if (!(lc->supported & SUPPORTED_Autoneg)) - return -EOPNOTSUPP; /* can't change speed/duplex */ + if (!(lc->supported & SUPPORTED_Autoneg)) { + /* + * PHY offers a single speed/duplex. See if that's what's + * being requested. + */ + if (cmd->autoneg == AUTONEG_DISABLE) { + cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); + if (lc->supported & cap) + return 0; + } + return -EINVAL; + } if (cmd->autoneg == AUTONEG_DISABLE) { int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); @@ -1568,8 +1635,10 @@ static int set_rx_csum(struct net_device *dev, u32 data) struct adapter *adap = p->adapter; int i; - for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) + for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { + adap->params.sge.qset[i].lro = 0; adap->sge.qs[i].lro_enabled = 0; + } } return 0; } @@ -1775,6 +1844,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) int i; struct qset_params *q; struct ch_qset_params t; + int q1 = pi->first_qset; + int nqsets = pi->nqsets; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -1797,6 +1868,16 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES, 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_csum_offload) + 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 || @@ -1804,6 +1885,20 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) t.polling >= 0 || t.cong_thres >= 0)) return -EBUSY; + /* Allow setting of any available qset when offload enabled */ + if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { + q1 = 0; + for_each_port(adapter, i) { + pi = adap2pinfo(adapter, i); + nqsets += pi->first_qset + pi->nqsets; + } + } + + if (t.qset_idx < q1) + return -EINVAL; + if (t.qset_idx > q1 + nqsets - 1) + return -EINVAL; + q = &adapter->params.sge.qset[t.qset_idx]; if (t.rspq_size >= 0) @@ -1853,13 +1948,26 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) case CHELSIO_GET_QSET_PARAMS:{ struct qset_params *q; struct ch_qset_params t; + int q1 = pi->first_qset; + int nqsets = pi->nqsets; + int i; if (copy_from_user(&t, useraddr, sizeof(t))) return -EFAULT; - if (t.qset_idx >= SGE_QSETS) + + /* Display qsets for all ports when offload enabled */ + if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { + q1 = 0; + for_each_port(adapter, i) { + pi = adap2pinfo(adapter, i); + nqsets = pi->first_qset + pi->nqsets; + } + } + + if (t.qset_idx >= nqsets) return -EINVAL; - q = &adapter->params.sge.qset[t.qset_idx]; + q = &adapter->params.sge.qset[q1 + t.qset_idx]; t.rspq_size = q->rspq_size; t.txq_size[0] = q->txq_size[0]; t.txq_size[1] = q->txq_size[1]; @@ -1870,6 +1978,12 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) t.lro = q->lro; t.intr_lat = q->coalesce_usecs; t.cong_thres = q->cong_thres; + t.qnum = q1; + + if (adapter->flags & USING_MSIX) + t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec; + else + t.vector = adapter->pdev->irq; if (copy_to_user(useraddr, &t, sizeof(t))) return -EFAULT; @@ -2117,7 +2231,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) mmd = data->phy_id >> 8; if (!mmd) mmd = MDIO_DEV_PCS; - else if (mmd > MDIO_DEV_XGXS) + else if (mmd > MDIO_DEV_VEND2) return -EINVAL; ret = @@ -2143,7 +2257,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) mmd = data->phy_id >> 8; if (!mmd) mmd = MDIO_DEV_PCS; - else if (mmd > MDIO_DEV_XGXS) + else if (mmd > MDIO_DEV_VEND2) return -EINVAL; ret = @@ -2215,8 +2329,8 @@ static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p) { int i; - for (i = 0; i < p->nqsets; i++) { - struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq; + for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { + struct sge_rspq *q = &adap->sge.qs[i].rspq; spin_lock_irq(&q->lock); spin_unlock_irq(&q->lock); @@ -2290,7 +2404,7 @@ static void check_link_status(struct adapter *adapter) struct net_device *dev = adapter->port[i]; struct port_info *p = netdev_priv(dev); - if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev)) + if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) t3_link_changed(adapter, i); } } @@ -2355,10 +2469,10 @@ static void t3_adap_check_task(struct work_struct *work) check_t3b2_mac(adapter); /* Schedule the next check update if any port is active. */ - spin_lock(&adapter->work_lock); + spin_lock_irq(&adapter->work_lock); if (adapter->open_device_map & PORT_MASK) schedule_chk_task(adapter); - spin_unlock(&adapter->work_lock); + spin_unlock_irq(&adapter->work_lock); } /* @@ -2403,6 +2517,96 @@ void t3_os_ext_intr_handler(struct adapter *adapter) spin_unlock(&adapter->work_lock); } +static int t3_adapter_error(struct adapter *adapter, int reset) +{ + int i, ret = 0; + + /* Stop all ports */ + for_each_port(adapter, i) { + struct net_device *netdev = adapter->port[i]; + + if (netif_running(netdev)) + cxgb_close(netdev); + } + + if (is_offload(adapter) && + test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) + offload_close(&adapter->tdev); + + /* Stop SGE timers */ + t3_stop_sge_timers(adapter); + + adapter->flags &= ~FULL_INIT_DONE; + + if (reset) + ret = t3_reset_adapter(adapter); + + pci_disable_device(adapter->pdev); + + return ret; +} + +static int t3_reenable_adapter(struct adapter *adapter) +{ + if (pci_enable_device(adapter->pdev)) { + dev_err(&adapter->pdev->dev, + "Cannot re-enable PCI device after reset.\n"); + goto err; + } + pci_set_master(adapter->pdev); + pci_restore_state(adapter->pdev); + + /* Free sge resources */ + t3_free_sge_resources(adapter); + + if (t3_replay_prep_adapter(adapter)) + goto err; + + return 0; +err: + return -1; +} + +static void t3_resume_ports(struct adapter *adapter) +{ + int i; + + /* Restart the ports */ + for_each_port(adapter, i) { + struct net_device *netdev = adapter->port[i]; + + if (netif_running(netdev)) { + if (cxgb_open(netdev)) { + dev_err(&adapter->pdev->dev, + "can't bring device back up" + " after reset\n"); + continue; + } + } + } +} + +/* + * processes a fatal error. + * Bring the ports down, reset the chip, bring the ports back up. + */ +static void fatal_error_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + fatal_error_handler_task); + int err = 0; + + rtnl_lock(); + err = t3_adapter_error(adapter, 1); + if (!err) + err = t3_reenable_adapter(adapter); + if (!err) + t3_resume_ports(adapter); + + CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded"); + rtnl_unlock(); +} + void t3_fatal_err(struct adapter *adapter) { unsigned int fw_status[4]; @@ -2413,7 +2617,11 @@ void t3_fatal_err(struct adapter *adapter) t3_write_reg(adapter, A_XGM_RX_CTRL, 0); t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0); t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0); + + spin_lock(&adapter->work_lock); t3_intr_disable(adapter); + queue_work(cxgb3_wq, &adapter->fatal_error_handler_task); + spin_unlock(&adapter->work_lock); } CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status)) @@ -2435,23 +2643,9 @@ static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct adapter *adapter = pci_get_drvdata(pdev); - int i; - - /* Stop all ports */ - for_each_port(adapter, i) { - struct net_device *netdev = adapter->port[i]; - - if (netif_running(netdev)) - cxgb_close(netdev); - } - - if (is_offload(adapter) && - test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) - offload_close(&adapter->tdev); - - adapter->flags &= ~FULL_INIT_DONE; + int ret; - pci_disable_device(pdev); + ret = t3_adapter_error(adapter, 0); /* Request a slot reset. */ return PCI_ERS_RESULT_NEED_RESET; @@ -2467,22 +2661,9 @@ static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev) { struct adapter *adapter = pci_get_drvdata(pdev); - if (pci_enable_device(pdev)) { - dev_err(&pdev->dev, - "Cannot re-enable PCI device after reset.\n"); - goto err; - } - pci_set_master(pdev); - pci_restore_state(pdev); - - /* Free sge resources */ - t3_free_sge_resources(adapter); - - if (t3_replay_prep_adapter(adapter)) - goto err; + if (!t3_reenable_adapter(adapter)) + return PCI_ERS_RESULT_RECOVERED; - return PCI_ERS_RESULT_RECOVERED; -err: return PCI_ERS_RESULT_DISCONNECT; } @@ -2496,22 +2677,8 @@ err: static void t3_io_resume(struct pci_dev *pdev) { struct adapter *adapter = pci_get_drvdata(pdev); - int i; - /* Restart the ports */ - for_each_port(adapter, i) { - struct net_device *netdev = adapter->port[i]; - - if (netif_running(netdev)) { - if (cxgb_open(netdev)) { - dev_err(&pdev->dev, - "can't bring device back up" - " after reset\n"); - continue; - } - netif_device_attach(netdev); - } - } + t3_resume_ports(adapter); } static struct pci_error_handlers t3_err_handler = { @@ -2520,6 +2687,42 @@ static struct pci_error_handlers t3_err_handler = { .resume = t3_io_resume, }; +/* + * Set the number of qsets based on the number of CPUs and the number of ports, + * not to exceed the number of available qsets, assuming there are enough qsets + * per port in HW. + */ +static void set_nqsets(struct adapter *adap) +{ + int i, j = 0; + int num_cpus = num_online_cpus(); + int hwports = adap->params.nports; + int nqsets = SGE_QSETS; + + if (adap->params.rev > 0) { + if (hwports == 2 && + (hwports * nqsets > SGE_QSETS || + num_cpus >= nqsets / hwports)) + nqsets /= hwports; + if (nqsets > num_cpus) + nqsets = num_cpus; + if (nqsets < 1 || hwports == 4) + nqsets = 1; + } else + nqsets = 1; + + for_each_port(adap, i) { + struct port_info *pi = adap2pinfo(adap, i); + + pi->first_qset = j; + pi->nqsets = nqsets; + j = pi->first_qset + nqsets; + + dev_info(&adap->pdev->dev, + "Port %d using %d queue sets.\n", i, nqsets); + } +} + static int __devinit cxgb_enable_msix(struct adapter *adap) { struct msix_entry entries[SGE_QSETS + 1]; @@ -2564,7 +2767,7 @@ static void __devinit print_port_info(struct adapter *adap, if (!test_bit(i, &adap->registered_device_map)) continue; printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n", - dev->name, ai->desc, pi->port_type->desc, + dev->name, ai->desc, pi->phy.desc, is_offload(adap) ? "R" : "", adap->params.rev, buf, (adap->flags & USING_MSIX) ? " MSI-X" : (adap->flags & USING_MSI) ? " MSI" : ""); @@ -2660,6 +2863,7 @@ static int __devinit init_one(struct pci_dev *pdev, INIT_LIST_HEAD(&adapter->adapter_list); INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); + INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task); INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); for (i = 0; i < ai->nports; ++i) { @@ -2677,9 +2881,6 @@ static int __devinit init_one(struct pci_dev *pdev, pi = netdev_priv(netdev); pi->adapter = adapter; pi->rx_csum_offload = 1; - pi->nqsets = 1; - pi->first_qset = i; - pi->activity = 0; pi->port_id = i; netif_carrier_off(netdev); netdev->irq = pdev->irq; @@ -2756,6 +2957,8 @@ static int __devinit init_one(struct pci_dev *pdev, else if (msi > 0 && pci_enable_msi(pdev) == 0) adapter->flags |= USING_MSI; + set_nqsets(adapter); + err = sysfs_create_group(&adapter->port[0]->dev.kobj, &cxgb3_attr_group); @@ -2801,6 +3004,7 @@ static void __devexit remove_one(struct pci_dev *pdev) if (test_bit(i, &adapter->registered_device_map)) unregister_netdev(adapter->port[i]); + t3_stop_sge_timers(adapter); t3_free_sge_resources(adapter); cxgb_disable_msi(adapter); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index c5b3de1bb45..265aa8a15af 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -1018,7 +1018,7 @@ static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e) skb = alloc_skb(sizeof(*req), GFP_ATOMIC); if (!skb) { - printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__); + printk(KERN_ERR "%s: cannot allocate skb!\n", __func__); return; } skb->priority = CPL_PRIORITY_CONTROL; @@ -1049,14 +1049,14 @@ void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) return; if (!is_offloading(newdev)) { printk(KERN_WARNING "%s: Redirect to non-offload " - "device ignored.\n", __FUNCTION__); + "device ignored.\n", __func__); return; } tdev = dev2t3cdev(olddev); BUG_ON(!tdev); if (tdev != dev2t3cdev(newdev)) { printk(KERN_WARNING "%s: Redirect to different " - "offload device ignored.\n", __FUNCTION__); + "offload device ignored.\n", __func__); return; } @@ -1064,7 +1064,7 @@ void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) e = t3_l2t_get(tdev, new->neighbour, newdev); if (!e) { printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n", - __FUNCTION__); + __func__); return; } diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index 7a379138b5a..d514e5019df 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h index b75ddd8777f..0d9b0e6dccf 100644 --- a/drivers/net/cxgb3/firmware_exports.h +++ b/drivers/net/cxgb3/firmware_exports.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c index 825e510bd9e..4407ac9bb55 100644 --- a/drivers/net/cxgb3/l2t.c +++ b/drivers/net/cxgb3/l2t.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -86,6 +86,7 @@ static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, struct l2t_entry *e) { struct cpl_l2t_write_req *req; + struct sk_buff *tmp; if (!skb) { skb = alloc_skb(sizeof(*req), GFP_ATOMIC); @@ -103,13 +104,11 @@ static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); skb->priority = CPL_PRIORITY_CONTROL; cxgb3_ofld_send(dev, skb); - while (e->arpq_head) { - skb = e->arpq_head; - e->arpq_head = skb->next; - skb->next = NULL; + + skb_queue_walk_safe(&e->arpq, skb, tmp) { + __skb_unlink(skb, &e->arpq); cxgb3_ofld_send(dev, skb); } - e->arpq_tail = NULL; e->state = L2T_STATE_VALID; return 0; @@ -121,12 +120,7 @@ static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, */ static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) { - skb->next = NULL; - if (e->arpq_head) - e->arpq_tail->next = skb; - else - e->arpq_head = skb; - e->arpq_tail = skb; + __skb_queue_tail(&e->arpq, skb); } int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, @@ -167,7 +161,7 @@ again: break; spin_lock_bh(&e->lock); - if (e->arpq_head) + if (!skb_queue_empty(&e->arpq)) setup_l2e_send_pending(dev, skb, e); else /* we lost the race */ __kfree_skb(skb); @@ -357,14 +351,14 @@ EXPORT_SYMBOL(t3_l2t_get); * XXX: maybe we should abandon the latter behavior and just require a failure * handler. */ -static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq) +static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff_head *arpq) { - while (arpq) { - struct sk_buff *skb = arpq; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(arpq, skb, tmp) { struct l2t_skb_cb *cb = L2T_SKB_CB(skb); - arpq = skb->next; - skb->next = NULL; + __skb_unlink(skb, arpq); if (cb->arp_failure_handler) cb->arp_failure_handler(dev, skb); else @@ -378,8 +372,8 @@ static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq) */ void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh) { + struct sk_buff_head arpq; struct l2t_entry *e; - struct sk_buff *arpq = NULL; struct l2t_data *d = L2DATA(dev); u32 addr = *(u32 *) neigh->primary_key; int ifidx = neigh->dev->ifindex; @@ -395,6 +389,8 @@ void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh) return; found: + __skb_queue_head_init(&arpq); + read_unlock(&d->lock); if (atomic_read(&e->refcnt)) { if (neigh != e->neigh) @@ -402,8 +398,7 @@ found: if (e->state == L2T_STATE_RESOLVING) { if (neigh->nud_state & NUD_FAILED) { - arpq = e->arpq_head; - e->arpq_head = e->arpq_tail = NULL; + skb_queue_splice_init(&e->arpq, &arpq); } else if (neigh->nud_state & (NUD_CONNECTED|NUD_STALE)) setup_l2e_send_pending(dev, NULL, e); } else { @@ -415,8 +410,8 @@ found: } spin_unlock_bh(&e->lock); - if (arpq) - handle_failed_resolution(dev, arpq); + if (!skb_queue_empty(&arpq)) + handle_failed_resolution(dev, &arpq); } struct l2t_data *t3_init_l2t(unsigned int l2t_capacity) diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h index d79001336cf..fd3eb07e3f4 100644 --- a/drivers/net/cxgb3/l2t.h +++ b/drivers/net/cxgb3/l2t.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -64,8 +64,7 @@ struct l2t_entry { struct neighbour *neigh; /* associated neighbour */ struct l2t_entry *first; /* start of hash chain */ struct l2t_entry *next; /* next l2t_entry on chain */ - struct sk_buff *arpq_head; /* queue of packets awaiting resolution */ - struct sk_buff *arpq_tail; + struct sk_buff_head arpq; /* queue of packets awaiting resolution */ spinlock_t lock; atomic_t refcnt; /* entry reference count */ u8 dmac[6]; /* neighbour's MAC address */ diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c index 4c4d6e877ea..3b5517b8fbd 100644 --- a/drivers/net/cxgb3/mc5.c +++ b/drivers/net/cxgb3/mc5.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index 4bda27c551c..a035d5c2444 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h @@ -573,6 +573,10 @@ #define V_GPIO10(x) ((x) << S_GPIO10) #define F_GPIO10 V_GPIO10(1U) +#define S_GPIO9 9 +#define V_GPIO9(x) ((x) << S_GPIO9) +#define F_GPIO9 V_GPIO9(1U) + #define S_GPIO7 7 #define V_GPIO7(x) ((x) << S_GPIO7) #define F_GPIO7 V_GPIO7(1U) diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 1b0861d73ab..c6480be0bc1 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -351,7 +351,8 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr), q->buf_size, PCI_DMA_FROMDEVICE); if (q->use_pages) { - put_page(d->pg_chunk.page); + if (d->pg_chunk.page) + put_page(d->pg_chunk.page); d->pg_chunk.page = NULL; } else { kfree_skb(d->skb); @@ -583,7 +584,7 @@ static void t3_reset_qset(struct sge_qset *q) memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET); memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET); q->txq_stopped = 0; - memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer)); + q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */ kfree(q->lro_frag_tbl); q->lro_nfrags = q->lro_frag_len = 0; } @@ -603,9 +604,6 @@ static void t3_free_qset(struct adapter *adapter, struct sge_qset *q) int i; struct pci_dev *pdev = adapter->pdev; - if (q->tx_reclaim_timer.function) - del_timer_sync(&q->tx_reclaim_timer); - for (i = 0; i < SGE_RXQ_PER_SET; ++i) if (q->fl[i].desc) { spin_lock_irq(&adapter->sge.reg_lock); @@ -1704,16 +1702,15 @@ int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb) */ static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb) { - skb->next = skb->prev = NULL; - if (q->rx_tail) - q->rx_tail->next = skb; - else { + int was_empty = skb_queue_empty(&q->rx_queue); + + __skb_queue_tail(&q->rx_queue, skb); + + if (was_empty) { struct sge_qset *qs = rspq_to_qset(q); napi_schedule(&qs->napi); - q->rx_head = skb; } - q->rx_tail = skb; } /** @@ -1754,26 +1751,29 @@ static int ofld_poll(struct napi_struct *napi, int budget) int work_done = 0; while (work_done < budget) { - struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE]; + struct sk_buff *skb, *tmp, *skbs[RX_BUNDLE_SIZE]; + struct sk_buff_head queue; int ngathered; spin_lock_irq(&q->lock); - head = q->rx_head; - if (!head) { + __skb_queue_head_init(&queue); + skb_queue_splice_init(&q->rx_queue, &queue); + if (skb_queue_empty(&queue)) { napi_complete(napi); spin_unlock_irq(&q->lock); return work_done; } - - tail = q->rx_tail; - q->rx_head = q->rx_tail = NULL; spin_unlock_irq(&q->lock); - for (ngathered = 0; work_done < budget && head; work_done++) { - prefetch(head->data); - skbs[ngathered] = head; - head = head->next; - skbs[ngathered]->next = NULL; + ngathered = 0; + skb_queue_walk_safe(&queue, skb, tmp) { + if (work_done >= budget) + break; + work_done++; + + __skb_unlink(skb, &queue); + prefetch(skb->data); + skbs[ngathered] = skb; if (++ngathered == RX_BUNDLE_SIZE) { q->offload_bundles++; adapter->tdev.recv(&adapter->tdev, skbs, @@ -1781,12 +1781,10 @@ static int ofld_poll(struct napi_struct *napi, int budget) ngathered = 0; } } - if (head) { /* splice remaining packets back onto Rx queue */ + if (!skb_queue_empty(&queue)) { + /* splice remaining packets back onto Rx queue */ spin_lock_irq(&q->lock); - tail->next = q->rx_head; - if (!q->rx_head) - q->rx_tail = tail; - q->rx_head = head; + skb_queue_splice(&queue, &q->rx_queue); spin_unlock_irq(&q->lock); } deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered); @@ -1937,38 +1935,6 @@ static inline int lro_frame_ok(const struct cpl_rx_pkt *p) eh->h_proto == htons(ETH_P_IP) && ih->ihl == (sizeof(*ih) >> 2); } -#define TCP_FLAG_MASK (TCP_FLAG_CWR | TCP_FLAG_ECE | TCP_FLAG_URG |\ - TCP_FLAG_ACK | TCP_FLAG_PSH | TCP_FLAG_RST |\ - TCP_FLAG_SYN | TCP_FLAG_FIN) -#define TSTAMP_WORD ((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |\ - (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP) - -/** - * lro_segment_ok - check if a TCP segment is eligible for LRO - * @tcph: the TCP header of the packet - * - * Returns true if a TCP packet is eligible for LRO. This requires that - * the packet have only the ACK flag set and no TCP options besides - * time stamps. - */ -static inline int lro_segment_ok(const struct tcphdr *tcph) -{ - int optlen; - - if (unlikely((tcp_flag_word(tcph) & TCP_FLAG_MASK) != TCP_FLAG_ACK)) - return 0; - - optlen = (tcph->doff << 2) - sizeof(*tcph); - if (optlen) { - const u32 *opt = (const u32 *)(tcph + 1); - - if (optlen != TCPOLEN_TSTAMP_ALIGNED || - *opt != htonl(TSTAMP_WORD) || !opt[2]) - return 0; - } - return 1; -} - static int t3_get_lro_header(void **eh, void **iph, void **tcph, u64 *hdr_flags, void *priv) { @@ -1981,9 +1947,6 @@ static int t3_get_lro_header(void **eh, void **iph, void **tcph, *iph = (struct iphdr *)((struct ethhdr *)*eh + 1); *tcph = (struct tcphdr *)((struct iphdr *)*iph + 1); - if (!lro_segment_ok(*tcph)) - return -1; - *hdr_flags = LRO_IPV4 | LRO_TCP; return 0; } @@ -2878,9 +2841,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, struct net_lro_mgr *lro_mgr = &q->lro_mgr; init_qset_cntxt(q, id); - init_timer(&q->tx_reclaim_timer); - q->tx_reclaim_timer.data = (unsigned long)q; - q->tx_reclaim_timer.function = sge_timer_cb; + setup_timer(&q->tx_reclaim_timer, sge_timer_cb, (unsigned long)q); q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size, sizeof(struct rx_desc), @@ -2934,6 +2895,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->rspq.gen = 1; q->rspq.size = p->rspq_size; spin_lock_init(&q->rspq.lock); + skb_queue_head_init(&q->rspq.rx_queue); q->txq[TXQ_ETH].stop_thres = nports * flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3); @@ -3043,6 +3005,24 @@ err: } /** + * t3_stop_sge_timers - stop SGE timer call backs + * @adap: the adapter + * + * Stops each SGE queue set's timer call back + */ +void t3_stop_sge_timers(struct adapter *adap) +{ + int i; + + for (i = 0; i < SGE_QSETS; ++i) { + struct sge_qset *q = &adap->sge.qs[i]; + + if (q->tx_reclaim_timer.function) + del_timer_sync(&q->tx_reclaim_timer); + } +} + +/** * t3_free_sge_resources - free SGE resources * @adap: the adapter * diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h index 917970ed24a..852c399a8b0 100644 --- a/drivers/net/cxgb3/t3_cpl.h +++ b/drivers/net/cxgb3/t3_cpl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 04c0e90119a..968f64be374 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -194,21 +194,18 @@ int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, static void mi1_init(struct adapter *adap, const struct adapter_info *ai) { u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1; - u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) | - V_CLKDIV(clkdiv); + u32 val = F_PREEN | V_CLKDIV(clkdiv); - if (!(ai->caps & SUPPORTED_10000baseT_Full)) - val |= V_ST(1); t3_write_reg(adap, A_MI1_CFG, val); } -#define MDIO_ATTEMPTS 10 +#define MDIO_ATTEMPTS 20 /* - * MI1 read/write operations for direct-addressed PHYs. + * MI1 read/write operations for clause 22 PHYs. */ -static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *valp) +static int t3_mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *valp) { int ret; u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); @@ -217,16 +214,17 @@ static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr, return -EINVAL; mutex_lock(&adapter->mdio_lock); + t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); t3_write_reg(adapter, A_MI1_ADDR, addr); t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2)); - ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); if (!ret) *valp = t3_read_reg(adapter, A_MI1_DATA); mutex_unlock(&adapter->mdio_lock); return ret; } -static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, +static int t3_mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, int reg_addr, unsigned int val) { int ret; @@ -236,37 +234,51 @@ static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, return -EINVAL; mutex_lock(&adapter->mdio_lock); + t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); t3_write_reg(adapter, A_MI1_ADDR, addr); t3_write_reg(adapter, A_MI1_DATA, val); t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); - ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); mutex_unlock(&adapter->mdio_lock); return ret; } static const struct mdio_ops mi1_mdio_ops = { - mi1_read, - mi1_write + t3_mi1_read, + t3_mi1_write }; /* + * Performs the address cycle for clause 45 PHYs. + * Must be called with the MDIO_LOCK held. + */ +static int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr) +{ + u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); + + t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_DATA, reg_addr); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); + return t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, + MDIO_ATTEMPTS, 10); +} + +/* * MI1 read/write operations for indirect-addressed PHYs. */ static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr, int reg_addr, unsigned int *valp) { int ret; - u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); mutex_lock(&adapter->mdio_lock); - t3_write_reg(adapter, A_MI1_ADDR, addr); - t3_write_reg(adapter, A_MI1_DATA, reg_addr); - t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); - ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr); if (!ret) { t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3)); ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, - MDIO_ATTEMPTS, 20); + MDIO_ATTEMPTS, 10); if (!ret) *valp = t3_read_reg(adapter, A_MI1_DATA); } @@ -278,18 +290,14 @@ static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr, int reg_addr, unsigned int val) { int ret; - u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); mutex_lock(&adapter->mdio_lock); - t3_write_reg(adapter, A_MI1_ADDR, addr); - t3_write_reg(adapter, A_MI1_DATA, reg_addr); - t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); - ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr); if (!ret) { t3_write_reg(adapter, A_MI1_DATA, val); t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, - MDIO_ATTEMPTS, 20); + MDIO_ATTEMPTS, 10); } mutex_unlock(&adapter->mdio_lock); return ret; @@ -400,6 +408,29 @@ int t3_phy_advertise(struct cphy *phy, unsigned int advert) } /** + * t3_phy_advertise_fiber - set fiber PHY advertisement register + * @phy: the PHY to operate on + * @advert: bitmap of capabilities the PHY should advertise + * + * Sets a fiber PHY's advertisement register to advertise the + * requested capabilities. + */ +int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert) +{ + unsigned int val = 0; + + if (advert & ADVERTISED_1000baseT_Half) + val |= ADVERTISE_1000XHALF; + if (advert & ADVERTISED_1000baseT_Full) + val |= ADVERTISE_1000XFULL; + if (advert & ADVERTISED_Pause) + val |= ADVERTISE_1000XPAUSE; + if (advert & ADVERTISED_Asym_Pause) + val |= ADVERTISE_1000XPSE_ASYM; + return mdio_write(phy, 0, MII_ADVERTISE, val); +} + +/** * t3_set_phy_speed_duplex - force PHY speed and duplex * @phy: the PHY to operate on * @speed: requested PHY speed @@ -434,27 +465,52 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) return mdio_write(phy, 0, MII_BMCR, ctl); } +int t3_phy_lasi_intr_enable(struct cphy *phy) +{ + return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); +} + +int t3_phy_lasi_intr_disable(struct cphy *phy) +{ + return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); +} + +int t3_phy_lasi_intr_clear(struct cphy *phy) +{ + u32 val; + + return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); +} + +int t3_phy_lasi_intr_handler(struct cphy *phy) +{ + unsigned int status; + int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); + + if (err) + return err; + return (status & 1) ? cphy_cause_link_change : 0; +} + static const struct adapter_info t3_adap_info[] = { - {2, 0, 0, 0, + {2, 0, F_GPIO2_OEN | F_GPIO4_OEN | - F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, - 0, + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, &mi1_mdio_ops, "Chelsio PE9000"}, - {2, 0, 0, 0, + {2, 0, F_GPIO2_OEN | F_GPIO4_OEN | - F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, - 0, + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, &mi1_mdio_ops, "Chelsio T302"}, - {1, 0, 0, 0, + {1, 0, F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, - 0, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + { 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, &mi1_mdio_ext_ops, "Chelsio T310"}, - {2, 0, 0, 0, + {2, 0, F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL | - F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0, - SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, + { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, &mi1_mdio_ext_ops, "Chelsio T320"}, }; @@ -467,29 +523,23 @@ const struct adapter_info *t3_get_adapter_info(unsigned int id) return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL; } -#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \ - SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII) -#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI) +struct port_type_info { + int (*phy_prep)(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *ops); +}; static const struct port_type_info port_types[] = { - {NULL}, - {t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE, - "10GBASE-XR"}, - {t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, - "10/100/1000BASE-T"}, - {NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, - "10/100/1000BASE-T"}, - {t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, - {NULL, CAPS_10G, "10GBASE-KX4"}, - {t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, - {t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE, - "10GBASE-SR"}, - {NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, + { NULL }, + { t3_ael1002_phy_prep }, + { t3_vsc8211_phy_prep }, + { NULL}, + { t3_xaui_direct_phy_prep }, + { t3_ael2005_phy_prep }, + { t3_qt2045_phy_prep }, + { t3_ael1006_phy_prep }, + { NULL }, }; -#undef CAPS_1G -#undef CAPS_10G - #define VPD_ENTRY(name, len) \ u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] @@ -1132,6 +1182,15 @@ void t3_link_changed(struct adapter *adapter, int port_id) phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); + if (lc->requested_fc & PAUSE_AUTONEG) + fc &= lc->requested_fc; + else + fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + if (link_ok == lc->link_ok && speed == lc->speed && + duplex == lc->duplex && fc == lc->fc) + return; /* nothing changed */ + if (link_ok != lc->link_ok && adapter->params.rev > 0 && uses_xaui(adapter)) { if (link_ok) @@ -1142,10 +1201,6 @@ void t3_link_changed(struct adapter *adapter, int port_id) lc->link_ok = link_ok; lc->speed = speed < 0 ? SPEED_INVALID : speed; lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; - if (lc->requested_fc & PAUSE_AUTONEG) - fc &= lc->requested_fc; - else - fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { /* Set MAC speed, duplex, and flow control to match PHY. */ @@ -1191,7 +1246,6 @@ int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) fc); /* Also disables autoneg */ phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); - phy->ops->reset(phy, 0); } else phy->ops->autoneg_enable(phy); } else { @@ -1221,7 +1275,7 @@ struct intr_info { unsigned int mask; /* bits to check in interrupt status */ const char *msg; /* message to print or NULL */ short stat_idx; /* stat counter to increment or -1 */ - unsigned short fatal:1; /* whether the condition reported is fatal */ + unsigned short fatal; /* whether the condition reported is fatal */ }; /** @@ -1682,25 +1736,23 @@ static int mac_intr_handler(struct adapter *adap, unsigned int idx) */ int t3_phy_intr_handler(struct adapter *adapter) { - u32 mask, gpi = adapter_info(adapter)->gpio_intr; u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); for_each_port(adapter, i) { struct port_info *p = adap2pinfo(adapter, i); - mask = gpi - (gpi & (gpi - 1)); - gpi -= mask; - - if (!(p->port_type->caps & SUPPORTED_IRQ)) + if (!(p->phy.caps & SUPPORTED_IRQ)) continue; - if (cause & mask) { + if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) { int phy_cause = p->phy.ops->intr_handler(&p->phy); if (phy_cause & cphy_cause_link_change) t3_link_changed(adapter, i); if (phy_cause & cphy_cause_fifo_error) p->phy.fifo_errors++; + if (phy_cause & cphy_cause_module_change) + t3_os_phymod_changed(adapter, i); } } @@ -1763,6 +1815,17 @@ int t3_slow_intr_handler(struct adapter *adapter) return 1; } +static unsigned int calc_gpio_intr(struct adapter *adap) +{ + unsigned int i, gpi_intr = 0; + + for_each_port(adap, i) + if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) && + adapter_info(adap)->gpio_intr[i]) + gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i]; + return gpi_intr; +} + /** * t3_intr_enable - enable interrupts * @adapter: the adapter whose interrupts should be enabled @@ -1805,10 +1868,8 @@ void t3_intr_enable(struct adapter *adapter) t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK); } - t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, - adapter_info(adapter)->gpio_intr); - t3_write_reg(adapter, A_T3DBG_INT_ENABLE, - adapter_info(adapter)->gpio_intr); + t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter)); + if (is_pcie(adapter)) t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); else @@ -3329,6 +3390,8 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params) init_hw_for_avail_ports(adapter, adapter->params.nports); t3_sge_init(adapter, &adapter->params.sge); + t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter)); + t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); t3_write_reg(adapter, A_CIM_BOOT_CFG, V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); @@ -3488,7 +3551,7 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai) * Older PCIe cards lose their config space during reset, PCI-X * ones don't. */ -static int t3_reset_adapter(struct adapter *adapter) +int t3_reset_adapter(struct adapter *adapter) { int i, save_and_restore_pcie = adapter->params.rev < T3_REV_B2 && is_pcie(adapter); @@ -3556,7 +3619,7 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, int reset) { int ret; - unsigned int i, j = 0; + unsigned int i, j = -1; get_pci_mode(adapter, &adapter->params.pci); @@ -3620,16 +3683,18 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, for_each_port(adapter, i) { u8 hw_addr[6]; + const struct port_type_info *pti; struct port_info *p = adap2pinfo(adapter, i); - while (!adapter->params.vpd.port_type[j]) - ++j; + while (!adapter->params.vpd.port_type[++j]) + ; - p->port_type = &port_types[adapter->params.vpd.port_type[j]]; - p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, - ai->mdio_ops); + pti = &port_types[adapter->params.vpd.port_type[j]]; + ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, + ai->mdio_ops); + if (ret) + return ret; mac_prep(&p->mac, adapter, j); - ++j; /* * The VPD EEPROM stores the base Ethernet address for the @@ -3643,9 +3708,9 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, ETH_ALEN); memcpy(adapter->port[i]->perm_addr, hw_addr, ETH_ALEN); - init_link_config(&p->link_config, p->port_type->caps); + init_link_config(&p->link_config, p->phy.caps); p->phy.ops->power_down(&p->phy, 1); - if (!(p->port_type->caps & SUPPORTED_IRQ)) + if (!(p->phy.caps & SUPPORTED_IRQ)) adapter->params.linkpoll_period = 10; } @@ -3661,7 +3726,7 @@ void t3_led_ready(struct adapter *adapter) int t3_replay_prep_adapter(struct adapter *adapter) { const struct adapter_info *ai = adapter->params.info; - unsigned int i, j = 0; + unsigned int i, j = -1; int ret; early_hw_init(adapter, ai); @@ -3670,15 +3735,17 @@ int t3_replay_prep_adapter(struct adapter *adapter) return ret; for_each_port(adapter, i) { + const struct port_type_info *pti; struct port_info *p = adap2pinfo(adapter, i); - while (!adapter->params.vpd.port_type[j]) - ++j; - p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, - ai->mdio_ops); + while (!adapter->params.vpd.port_type[++j]) + ; + pti = &port_types[adapter->params.vpd.port_type[j]]; + ret = pti->phy_prep(&p->phy, adapter, p->phy.addr, NULL); + if (ret) + return ret; p->phy.ops->power_down(&p->phy, 1); - ++j; } return 0; diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h index 0a21cfbd2b2..be55e9ae74d 100644 --- a/drivers/net/cxgb3/t3cdev.h +++ b/drivers/net/cxgb3/t3cdev.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved. + * Copyright (C) 2006-2008 Chelsio Communications. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index 29db711303b..bb8698a8675 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -35,7 +35,7 @@ #define DRV_DESC "Chelsio T3 Network Driver" #define DRV_NAME "cxgb3" /* Driver version */ -#define DRV_VERSION "1.0-ko" +#define DRV_VERSION "1.1.0-ko" /* Firmware version */ #define FW_VERSION_MAJOR 7 diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c index eee4285b31b..33f956bd6b5 100644 --- a/drivers/net/cxgb3/vsc8211.c +++ b/drivers/net/cxgb3/vsc8211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -33,28 +33,40 @@ /* VSC8211 PHY specific registers. */ enum { + VSC8211_SIGDET_CTRL = 19, + VSC8211_EXT_CTRL = 23, VSC8211_INTR_ENABLE = 25, VSC8211_INTR_STATUS = 26, + VSC8211_LED_CTRL = 27, VSC8211_AUX_CTRL_STAT = 28, + VSC8211_EXT_PAGE_AXS = 31, }; enum { VSC_INTR_RX_ERR = 1 << 0, - VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ - VSC_INTR_CABLE = 1 << 2, /* cable impairment */ - VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ - VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ - VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ - VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ - VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ - VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ - VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ - VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ - VSC_INTR_LINK_CHG = 1 << 13, /* link change */ - VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ + VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ + VSC_INTR_CABLE = 1 << 2, /* cable impairment */ + VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ + VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ + VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ + VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ + VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ + VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ + VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ + VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ + VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */ + VSC_INTR_LINK_CHG = 1 << 13, /* link change */ + VSC_INTR_SPD_CHG = 1 << 14, /* speed change */ + VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ +}; + +enum { + VSC_CTRL_CLAUSE37_VIEW = 1 << 4, /* Switch to Clause 37 view */ + VSC_CTRL_MEDIA_MODE_HI = 0xf000 /* High part of media mode select */ }; #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ + VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \ VSC_INTR_NEG_DONE) #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ VSC_INTR_ENABLE) @@ -184,6 +196,112 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, return 0; } +static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + unsigned int bmcr, status, lpa, adv; + int err, sp = -1, dplx = -1, pause = 0; + + err = mdio_read(cphy, 0, MII_BMCR, &bmcr); + if (!err) + err = mdio_read(cphy, 0, MII_BMSR, &status); + if (err) + return err; + + if (link_ok) { + /* + * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it + * once more to get the current link state. + */ + if (!(status & BMSR_LSTATUS)) + err = mdio_read(cphy, 0, MII_BMSR, &status); + if (err) + return err; + *link_ok = (status & BMSR_LSTATUS) != 0; + } + if (!(bmcr & BMCR_ANENABLE)) { + dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + if (bmcr & BMCR_SPEED1000) + sp = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + sp = SPEED_100; + else + sp = SPEED_10; + } else if (status & BMSR_ANEGCOMPLETE) { + err = mdio_read(cphy, 0, MII_LPA, &lpa); + if (!err) + err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); + if (err) + return err; + + if (adv & lpa & ADVERTISE_1000XFULL) { + dplx = DUPLEX_FULL; + sp = SPEED_1000; + } else if (adv & lpa & ADVERTISE_1000XHALF) { + dplx = DUPLEX_HALF; + sp = SPEED_1000; + } + + if (fc && dplx == DUPLEX_FULL) { + if (lpa & adv & ADVERTISE_1000XPAUSE) + pause = PAUSE_RX | PAUSE_TX; + else if ((lpa & ADVERTISE_1000XPAUSE) && + (adv & lpa & ADVERTISE_1000XPSE_ASYM)) + pause = PAUSE_TX; + else if ((lpa & ADVERTISE_1000XPSE_ASYM) && + (adv & ADVERTISE_1000XPAUSE)) + pause = PAUSE_RX; + } + } + if (speed) + *speed = sp; + if (duplex) + *duplex = dplx; + if (fc) + *fc = pause; + return 0; +} + +/* + * Enable/disable auto MDI/MDI-X in forced link speed mode. + */ +static int vsc8211_set_automdi(struct cphy *phy, int enable) +{ + int err; + + err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0x52b5); + if (err) + return err; + + err = mdio_write(phy, 0, 18, 0x12); + if (err) + return err; + + err = mdio_write(phy, 0, 17, enable ? 0x2803 : 0x3003); + if (err) + return err; + + err = mdio_write(phy, 0, 16, 0x87fa); + if (err) + return err; + + err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0); + if (err) + return err; + + return 0; +} + +int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + int err; + + err = t3_set_phy_speed_duplex(phy, speed, duplex); + if (!err) + err = vsc8211_set_automdi(phy, 1); + return err; +} + static int vsc8211_power_down(struct cphy *cphy, int enable) { return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN, @@ -221,8 +339,66 @@ static struct cphy_ops vsc8211_ops = { .power_down = vsc8211_power_down, }; -void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) +static struct cphy_ops vsc8211_fiber_ops = { + .reset = vsc8211_reset, + .intr_enable = vsc8211_intr_enable, + .intr_disable = vsc8211_intr_disable, + .intr_clear = vsc8211_intr_clear, + .intr_handler = vsc8211_intr_handler, + .autoneg_enable = vsc8211_autoneg_enable, + .autoneg_restart = vsc8211_autoneg_restart, + .advertise = t3_phy_advertise_fiber, + .set_speed_duplex = t3_set_phy_speed_duplex, + .get_link_status = vsc8211_get_link_status_fiber, + .power_down = vsc8211_power_down, +}; + +int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) { - cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops); + int err; + unsigned int val; + + cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops, + SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | + SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); + msleep(20); /* PHY needs ~10ms to start responding to MDIO */ + + err = mdio_read(phy, 0, VSC8211_EXT_CTRL, &val); + if (err) + return err; + if (val & VSC_CTRL_MEDIA_MODE_HI) { + /* copper interface, just need to configure the LEDs */ + return mdio_write(phy, 0, VSC8211_LED_CTRL, 0x100); + } + + phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | + SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ; + phy->desc = "1000BASE-X"; + phy->ops = &vsc8211_fiber_ops; + + err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 1); + if (err) + return err; + + err = mdio_write(phy, 0, VSC8211_SIGDET_CTRL, 1); + if (err) + return err; + + err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0); + if (err) + return err; + + err = mdio_write(phy, 0, VSC8211_EXT_CTRL, + val | VSC_CTRL_CLAUSE37_VIEW); + if (err) + return err; + + err = vsc8211_reset(phy, 0); + if (err) + return err; + + udelay(5); /* delay after reset before next SMI */ + return 0; } diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index ffdc0a1892b..9d7786937aa 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 453115acaad..3d69fae781c 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -191,7 +191,7 @@ MODULE_PARM_DESC(use_io, "Force use of i/o access mode"); #define DPRINTK(nlevel, klevel, fmt, args...) \ (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \ printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \ - __FUNCTION__ , ## args)) + __func__ , ## args)) #define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\ PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \ @@ -2738,9 +2738,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, nic->flags |= wol_magic; /* ack any pending wake events, disable PME */ - err = pci_enable_wake(pdev, 0, 0); - if (err) - DPRINTK(PROBE, ERR, "Error clearing wake event\n"); + pci_pme_active(pdev, false); strcpy(netdev->name, "eth%d"); if((err = register_netdev(netdev))) { diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 19e317eaf5b..62f62970f97 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -155,8 +155,6 @@ do { \ #endif #define E1000_MNG_VLAN_NONE (-1) -/* Number of packet split data buffers (not including the header buffer) */ -#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ @@ -168,14 +166,6 @@ struct e1000_buffer { u16 next_to_watch; }; -struct e1000_ps_page { - struct page *ps_page[PS_PAGE_BUFFERS]; -}; - -struct e1000_ps_page_dma { - u64 ps_page_dma[PS_PAGE_BUFFERS]; -}; - struct e1000_tx_ring { /* pointer to the descriptor ring memory */ void *desc; @@ -213,9 +203,6 @@ struct e1000_rx_ring { unsigned int next_to_clean; /* array of buffer information structs */ struct e1000_buffer *buffer_info; - /* arrays of page information for packet split */ - struct e1000_ps_page *ps_page; - struct e1000_ps_page_dma *ps_page_dma; /* cpu for rx queue */ int cpu; @@ -228,8 +215,6 @@ struct e1000_rx_ring { ((((R)->next_to_clean > (R)->next_to_use) \ ? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1) -#define E1000_RX_DESC_PS(R, i) \ - (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) #define E1000_RX_DESC_EXT(R, i) \ (&(((union e1000_rx_desc_extended *)((R).desc))[i])) #define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) @@ -311,10 +296,8 @@ struct e1000_adapter { u32 rx_int_delay; u32 rx_abs_int_delay; bool rx_csum; - unsigned int rx_ps_pages; u32 gorcl; u64 gorcl_old; - u16 rx_ps_bsize0; /* OS defined structs */ struct net_device *netdev; diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 9d6edf3e73f..d04eef53571 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -144,6 +144,8 @@ static s32 e1000_host_if_read_cookie(struct e1000_hw *hw, u8 *buffer); static u8 e1000_calculate_mng_checksum(char *buffer, u32 length); static s32 e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, u16 duplex); static s32 e1000_configure_kmrn_for_1000(struct e1000_hw *hw); +static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); /* IGP cable length table */ static const @@ -168,6 +170,8 @@ u16 e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] = 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121, 124}; +static DEFINE_SPINLOCK(e1000_eeprom_lock); + /****************************************************************************** * Set the phy type member in the hw struct. * @@ -4904,6 +4908,15 @@ static s32 e1000_spi_eeprom_ready(struct e1000_hw *hw) *****************************************************************************/ s32 e1000_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) { + s32 ret; + spin_lock(&e1000_eeprom_lock); + ret = e1000_do_read_eeprom(hw, offset, words, data); + spin_unlock(&e1000_eeprom_lock); + return ret; +} + +static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ struct e1000_eeprom_info *eeprom = &hw->eeprom; u32 i = 0; @@ -5236,6 +5249,16 @@ s32 e1000_update_eeprom_checksum(struct e1000_hw *hw) *****************************************************************************/ s32 e1000_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) { + s32 ret; + spin_lock(&e1000_eeprom_lock); + ret = e1000_do_write_eeprom(hw, offset, words, data); + spin_unlock(&e1000_eeprom_lock); + return ret; +} + + +static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ struct e1000_eeprom_info *eeprom = &hw->eeprom; s32 status = 0; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ad6da7b67e5..fac82152e4c 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -137,15 +137,9 @@ static int e1000_clean(struct napi_struct *napi, int budget); static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); -static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, - int *work_done, int work_to_do); static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int cleaned_count); -static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, - int cleaned_count); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); @@ -1053,6 +1047,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_LLTX; + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_HW_CSUM; + netdev->vlan_features |= NETIF_F_SG; + adapter->en_mng_pt = e1000_enable_mng_pass_thru(hw); /* initialize eeprom parameters */ @@ -1331,7 +1330,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; - adapter->rx_ps_bsize0 = E1000_RXBUFFER_128; hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE; @@ -1815,26 +1813,6 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter, } memset(rxdr->buffer_info, 0, size); - rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page), - GFP_KERNEL); - if (!rxdr->ps_page) { - vfree(rxdr->buffer_info); - DPRINTK(PROBE, ERR, - "Unable to allocate memory for the receive descriptor ring\n"); - return -ENOMEM; - } - - rxdr->ps_page_dma = kcalloc(rxdr->count, - sizeof(struct e1000_ps_page_dma), - GFP_KERNEL); - if (!rxdr->ps_page_dma) { - vfree(rxdr->buffer_info); - kfree(rxdr->ps_page); - DPRINTK(PROBE, ERR, - "Unable to allocate memory for the receive descriptor ring\n"); - return -ENOMEM; - } - if (hw->mac_type <= e1000_82547_rev_2) desc_len = sizeof(struct e1000_rx_desc); else @@ -1852,8 +1830,6 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter, "Unable to allocate memory for the receive descriptor ring\n"); setup_rx_desc_die: vfree(rxdr->buffer_info); - kfree(rxdr->ps_page); - kfree(rxdr->ps_page_dma); return -ENOMEM; } @@ -1932,11 +1908,7 @@ int e1000_setup_all_rx_resources(struct e1000_adapter *adapter) static void e1000_setup_rctl(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; - u32 rctl, rfctl; - u32 psrctl = 0; -#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT - u32 pages = 0; -#endif + u32 rctl; rctl = er32(RCTL); @@ -1988,55 +1960,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) break; } -#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT - /* 82571 and greater support packet-split where the protocol - * header is placed in skb->data and the packet data is - * placed in pages hanging off of skb_shinfo(skb)->nr_frags. - * In the case of a non-split, skb->data is linearly filled, - * followed by the page buffers. Therefore, skb->data is - * sized to hold the largest protocol header. - */ - /* allocations using alloc_page take too long for regular MTU - * so only enable packet split for jumbo frames */ - pages = PAGE_USE_COUNT(adapter->netdev->mtu); - if ((hw->mac_type >= e1000_82571) && (pages <= 3) && - PAGE_SIZE <= 16384 && (rctl & E1000_RCTL_LPE)) - adapter->rx_ps_pages = pages; - else - adapter->rx_ps_pages = 0; -#endif - if (adapter->rx_ps_pages) { - /* Configure extra packet-split registers */ - rfctl = er32(RFCTL); - rfctl |= E1000_RFCTL_EXTEN; - /* disable packet split support for IPv6 extension headers, - * because some malformed IPv6 headers can hang the RX */ - rfctl |= (E1000_RFCTL_IPV6_EX_DIS | - E1000_RFCTL_NEW_IPV6_EXT_DIS); - - ew32(RFCTL, rfctl); - - rctl |= E1000_RCTL_DTYP_PS; - - psrctl |= adapter->rx_ps_bsize0 >> - E1000_PSRCTL_BSIZE0_SHIFT; - - switch (adapter->rx_ps_pages) { - case 3: - psrctl |= PAGE_SIZE << - E1000_PSRCTL_BSIZE3_SHIFT; - case 2: - psrctl |= PAGE_SIZE << - E1000_PSRCTL_BSIZE2_SHIFT; - case 1: - psrctl |= PAGE_SIZE >> - E1000_PSRCTL_BSIZE1_SHIFT; - break; - } - - ew32(PSRCTL, psrctl); - } - ew32(RCTL, rctl); } @@ -2053,18 +1976,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 rdlen, rctl, rxcsum, ctrl_ext; - if (adapter->rx_ps_pages) { - /* this is a 32 byte descriptor */ - rdlen = adapter->rx_ring[0].count * - sizeof(union e1000_rx_desc_packet_split); - adapter->clean_rx = e1000_clean_rx_irq_ps; - adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; - } else { - rdlen = adapter->rx_ring[0].count * - sizeof(struct e1000_rx_desc); - adapter->clean_rx = e1000_clean_rx_irq; - adapter->alloc_rx_buf = e1000_alloc_rx_buffers; - } + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers; /* disable receives while setting up the descriptors */ rctl = er32(RCTL); @@ -2109,28 +2024,14 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) /* Enable 82543 Receive Checksum Offload for TCP and UDP */ if (hw->mac_type >= e1000_82543) { rxcsum = er32(RXCSUM); - if (adapter->rx_csum) { + if (adapter->rx_csum) rxcsum |= E1000_RXCSUM_TUOFL; - - /* Enable 82571 IPv4 payload checksum for UDP fragments - * Must be used in conjunction with packet-split. */ - if ((hw->mac_type >= e1000_82571) && - (adapter->rx_ps_pages)) { - rxcsum |= E1000_RXCSUM_IPPCSE; - } - } else { - rxcsum &= ~E1000_RXCSUM_TUOFL; + else /* don't need to clear IPPCSE as it defaults to 0 */ - } + rxcsum &= ~E1000_RXCSUM_TUOFL; ew32(RXCSUM, rxcsum); } - /* enable early receives on 82573, only takes effect if using > 2048 - * byte total frame size. for example only for jumbo frames */ -#define E1000_ERT_2048 0x100 - if (hw->mac_type == e1000_82573) - ew32(ERT, E1000_ERT_2048); - /* Enable Receives */ ew32(RCTL, rctl); } @@ -2256,10 +2157,6 @@ static void e1000_free_rx_resources(struct e1000_adapter *adapter, vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; - kfree(rx_ring->ps_page); - rx_ring->ps_page = NULL; - kfree(rx_ring->ps_page_dma); - rx_ring->ps_page_dma = NULL; pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); @@ -2292,11 +2189,9 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter, { struct e1000_hw *hw = &adapter->hw; struct e1000_buffer *buffer_info; - struct e1000_ps_page *ps_page; - struct e1000_ps_page_dma *ps_page_dma; struct pci_dev *pdev = adapter->pdev; unsigned long size; - unsigned int i, j; + unsigned int i; /* Free all the Rx ring sk_buffs */ for (i = 0; i < rx_ring->count; i++) { @@ -2310,25 +2205,10 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter, dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; } - ps_page = &rx_ring->ps_page[i]; - ps_page_dma = &rx_ring->ps_page_dma[i]; - for (j = 0; j < adapter->rx_ps_pages; j++) { - if (!ps_page->ps_page[j]) break; - pci_unmap_page(pdev, - ps_page_dma->ps_page_dma[j], - PAGE_SIZE, PCI_DMA_FROMDEVICE); - ps_page_dma->ps_page_dma[j] = 0; - put_page(ps_page->ps_page[j]); - ps_page->ps_page[j] = NULL; - } } size = sizeof(struct e1000_buffer) * rx_ring->count; memset(rx_ring->buffer_info, 0, size); - size = sizeof(struct e1000_ps_page) * rx_ring->count; - memset(rx_ring->ps_page, 0, size); - size = sizeof(struct e1000_ps_page_dma) * rx_ring->count; - memset(rx_ring->ps_page_dma, 0, size); /* Zero out the descriptor ring */ @@ -2998,32 +2878,49 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info; unsigned int i; u8 css; + u32 cmd_len = E1000_TXD_CMD_DEXT; - if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { - css = skb_transport_offset(skb); + if (skb->ip_summed != CHECKSUM_PARTIAL) + return false; - i = tx_ring->next_to_use; - buffer_info = &tx_ring->buffer_info[i]; - context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + cmd_len |= E1000_TXD_CMD_TCP; + break; + case __constant_htons(ETH_P_IPV6): + /* XXX not handling all IPV6 headers */ + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + cmd_len |= E1000_TXD_CMD_TCP; + break; + default: + if (unlikely(net_ratelimit())) + DPRINTK(DRV, WARNING, + "checksum_partial proto=%x!\n", skb->protocol); + break; + } - context_desc->lower_setup.ip_config = 0; - context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = - css + skb->csum_offset; - context_desc->upper_setup.tcp_fields.tucse = 0; - context_desc->tcp_seg_setup.data = 0; - context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); + css = skb_transport_offset(skb); - buffer_info->time_stamp = jiffies; - buffer_info->next_to_watch = i; + i = tx_ring->next_to_use; + buffer_info = &tx_ring->buffer_info[i]; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); - if (unlikely(++i == tx_ring->count)) i = 0; - tx_ring->next_to_use = i; + context_desc->lower_setup.ip_config = 0; + context_desc->upper_setup.tcp_fields.tucss = css; + context_desc->upper_setup.tcp_fields.tucso = + css + skb->csum_offset; + context_desc->upper_setup.tcp_fields.tucse = 0; + context_desc->tcp_seg_setup.data = 0; + context_desc->cmd_and_length = cpu_to_le32(cmd_len); - return true; - } + buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; - return false; + if (unlikely(++i == tx_ring->count)) i = 0; + tx_ring->next_to_use = i; + + return true; } #define E1000_MAX_TXD_PWR 12 @@ -4235,181 +4132,6 @@ next_desc: } /** - * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split - * @adapter: board private structure - **/ - -static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, - int *work_done, int work_to_do) -{ - union e1000_rx_desc_packet_split *rx_desc, *next_rxd; - struct net_device *netdev = adapter->netdev; - struct pci_dev *pdev = adapter->pdev; - struct e1000_buffer *buffer_info, *next_buffer; - struct e1000_ps_page *ps_page; - struct e1000_ps_page_dma *ps_page_dma; - struct sk_buff *skb; - unsigned int i, j; - u32 length, staterr; - int cleaned_count = 0; - bool cleaned = false; - unsigned int total_rx_bytes=0, total_rx_packets=0; - - i = rx_ring->next_to_clean; - rx_desc = E1000_RX_DESC_PS(*rx_ring, i); - staterr = le32_to_cpu(rx_desc->wb.middle.status_error); - buffer_info = &rx_ring->buffer_info[i]; - - while (staterr & E1000_RXD_STAT_DD) { - ps_page = &rx_ring->ps_page[i]; - ps_page_dma = &rx_ring->ps_page_dma[i]; - - if (unlikely(*work_done >= work_to_do)) - break; - (*work_done)++; - - skb = buffer_info->skb; - - /* in the packet split case this is header only */ - prefetch(skb->data - NET_IP_ALIGN); - - if (++i == rx_ring->count) i = 0; - next_rxd = E1000_RX_DESC_PS(*rx_ring, i); - prefetch(next_rxd); - - next_buffer = &rx_ring->buffer_info[i]; - - cleaned = true; - cleaned_count++; - pci_unmap_single(pdev, buffer_info->dma, - buffer_info->length, - PCI_DMA_FROMDEVICE); - - if (unlikely(!(staterr & E1000_RXD_STAT_EOP))) { - E1000_DBG("%s: Packet Split buffers didn't pick up" - " the full packet\n", netdev->name); - dev_kfree_skb_irq(skb); - goto next_desc; - } - - if (unlikely(staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK)) { - dev_kfree_skb_irq(skb); - goto next_desc; - } - - length = le16_to_cpu(rx_desc->wb.middle.length0); - - if (unlikely(!length)) { - E1000_DBG("%s: Last part of the packet spanning" - " multiple descriptors\n", netdev->name); - dev_kfree_skb_irq(skb); - goto next_desc; - } - - /* Good Receive */ - skb_put(skb, length); - - { - /* this looks ugly, but it seems compiler issues make it - more efficient than reusing j */ - int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]); - - /* page alloc/put takes too long and effects small packet - * throughput, so unsplit small packets and save the alloc/put*/ - if (l1 && (l1 <= copybreak) && ((length + l1) <= adapter->rx_ps_bsize0)) { - u8 *vaddr; - /* there is no documentation about how to call - * kmap_atomic, so we can't hold the mapping - * very long */ - pci_dma_sync_single_for_cpu(pdev, - ps_page_dma->ps_page_dma[0], - PAGE_SIZE, - PCI_DMA_FROMDEVICE); - vaddr = kmap_atomic(ps_page->ps_page[0], - KM_SKB_DATA_SOFTIRQ); - memcpy(skb_tail_pointer(skb), vaddr, l1); - kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); - pci_dma_sync_single_for_device(pdev, - ps_page_dma->ps_page_dma[0], - PAGE_SIZE, PCI_DMA_FROMDEVICE); - /* remove the CRC */ - l1 -= 4; - skb_put(skb, l1); - goto copydone; - } /* if */ - } - - for (j = 0; j < adapter->rx_ps_pages; j++) { - length = le16_to_cpu(rx_desc->wb.upper.length[j]); - if (!length) - break; - pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j], - PAGE_SIZE, PCI_DMA_FROMDEVICE); - ps_page_dma->ps_page_dma[j] = 0; - skb_fill_page_desc(skb, j, ps_page->ps_page[j], 0, - length); - ps_page->ps_page[j] = NULL; - skb->len += length; - skb->data_len += length; - skb->truesize += length; - } - - /* strip the ethernet crc, problem is we're using pages now so - * this whole operation can get a little cpu intensive */ - pskb_trim(skb, skb->len - 4); - -copydone: - total_rx_bytes += skb->len; - total_rx_packets++; - - e1000_rx_checksum(adapter, staterr, - le16_to_cpu(rx_desc->wb.lower.hi_dword.csum_ip.csum), skb); - skb->protocol = eth_type_trans(skb, netdev); - - if (likely(rx_desc->wb.upper.header_status & - cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))) - adapter->rx_hdr_split++; - - if (unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->wb.middle.vlan)); - } else { - netif_receive_skb(skb); - } - - netdev->last_rx = jiffies; - -next_desc: - rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF); - buffer_info->skb = NULL; - - /* return some buffers to hardware, one at a time is too slow */ - if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) { - adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); - cleaned_count = 0; - } - - /* use prefetched values */ - rx_desc = next_rxd; - buffer_info = next_buffer; - - staterr = le32_to_cpu(rx_desc->wb.middle.status_error); - } - rx_ring->next_to_clean = i; - - cleaned_count = E1000_DESC_UNUSED(rx_ring); - if (cleaned_count) - adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); - - adapter->total_rx_packets += total_rx_packets; - adapter->total_rx_bytes += total_rx_bytes; - adapter->net_stats.rx_bytes += total_rx_bytes; - adapter->net_stats.rx_packets += total_rx_packets; - return cleaned; -} - -/** * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended * @adapter: address of board private structure **/ @@ -4521,104 +4243,6 @@ map_skb: } /** - * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split - * @adapter: address of board private structure - **/ - -static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, - int cleaned_count) -{ - struct e1000_hw *hw = &adapter->hw; - struct net_device *netdev = adapter->netdev; - struct pci_dev *pdev = adapter->pdev; - union e1000_rx_desc_packet_split *rx_desc; - struct e1000_buffer *buffer_info; - struct e1000_ps_page *ps_page; - struct e1000_ps_page_dma *ps_page_dma; - struct sk_buff *skb; - unsigned int i, j; - - i = rx_ring->next_to_use; - buffer_info = &rx_ring->buffer_info[i]; - ps_page = &rx_ring->ps_page[i]; - ps_page_dma = &rx_ring->ps_page_dma[i]; - - while (cleaned_count--) { - rx_desc = E1000_RX_DESC_PS(*rx_ring, i); - - for (j = 0; j < PS_PAGE_BUFFERS; j++) { - if (j < adapter->rx_ps_pages) { - if (likely(!ps_page->ps_page[j])) { - ps_page->ps_page[j] = - alloc_page(GFP_ATOMIC); - if (unlikely(!ps_page->ps_page[j])) { - adapter->alloc_rx_buff_failed++; - goto no_buffers; - } - ps_page_dma->ps_page_dma[j] = - pci_map_page(pdev, - ps_page->ps_page[j], - 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); - } - /* Refresh the desc even if buffer_addrs didn't - * change because each write-back erases - * this info. - */ - rx_desc->read.buffer_addr[j+1] = - cpu_to_le64(ps_page_dma->ps_page_dma[j]); - } else - rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0); - } - - skb = netdev_alloc_skb(netdev, - adapter->rx_ps_bsize0 + NET_IP_ALIGN); - - if (unlikely(!skb)) { - adapter->alloc_rx_buff_failed++; - break; - } - - /* Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - - buffer_info->skb = skb; - buffer_info->length = adapter->rx_ps_bsize0; - buffer_info->dma = pci_map_single(pdev, skb->data, - adapter->rx_ps_bsize0, - PCI_DMA_FROMDEVICE); - - rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma); - - if (unlikely(++i == rx_ring->count)) i = 0; - buffer_info = &rx_ring->buffer_info[i]; - ps_page = &rx_ring->ps_page[i]; - ps_page_dma = &rx_ring->ps_page_dma[i]; - } - -no_buffers: - if (likely(rx_ring->next_to_use != i)) { - rx_ring->next_to_use = i; - if (unlikely(i-- == 0)) i = (rx_ring->count - 1); - - /* Force memory writes to complete before letting h/w - * know there are new descriptors to fetch. (Only - * applicable for weak-ordered memory model archs, - * such as IA-64). */ - wmb(); - /* Hardware increments by 16 bytes, but packet split - * descriptors are 32 bytes...so we increment tail - * twice as much. - */ - writel(i<<1, hw->hw_addr + rx_ring->rdt); - } -} - -/** * e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers. * @adapter: **/ diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 462351ca2c8..b2c910c52df 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -38,6 +38,7 @@ * 82573V Gigabit Ethernet Controller (Copper) * 82573E Gigabit Ethernet Controller (Copper) * 82573L Gigabit Ethernet Controller + * 82574L Gigabit Network Connection */ #include <linux/netdevice.h> @@ -54,6 +55,8 @@ #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 +#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */ + static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); @@ -63,6 +66,8 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw); static s32 e1000_setup_link_82571(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); +static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); +static s32 e1000_led_on_82574(struct e1000_hw *hw); /** * e1000_init_phy_params_82571 - Init PHY func ptrs. @@ -92,6 +97,9 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) case e1000_82573: phy->type = e1000_phy_m88; break; + case e1000_82574: + phy->type = e1000_phy_bm; + break; default: return -E1000_ERR_PHY; break; @@ -111,6 +119,10 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) if (phy->id != M88E1111_I_PHY_ID) return -E1000_ERR_PHY; break; + case e1000_82574: + if (phy->id != BME1000_E_PHY_ID_R2) + return -E1000_ERR_PHY; + break; default: return -E1000_ERR_PHY; break; @@ -150,6 +162,7 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw) switch (hw->mac.type) { case e1000_82573: + case e1000_82574: if (((eecd >> 15) & 0x3) == 0x3) { nvm->type = e1000_nvm_flash_hw; nvm->word_size = 2048; @@ -245,6 +258,17 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) break; } + switch (hw->mac.type) { + case e1000_82574: + func->check_mng_mode = e1000_check_mng_mode_82574; + func->led_on = e1000_led_on_82574; + break; + default: + func->check_mng_mode = e1000e_check_mng_mode_generic; + func->led_on = e1000e_led_on_generic; + break; + } + return 0; } @@ -330,6 +354,8 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_id = 0; switch (hw->mac.type) { case e1000_82571: @@ -345,6 +371,20 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) case e1000_82573: return e1000e_get_phy_id(hw); break; + case e1000_82574: + ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); + if (ret_val) + return ret_val; + + phy->id = (u32)(phy_id << 16); + udelay(20); + ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); + if (ret_val) + return ret_val; + + phy->id |= (u32)(phy_id); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + break; default: return -E1000_ERR_PHY; break; @@ -421,7 +461,7 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw) if (ret_val) return ret_val; - if (hw->mac.type != e1000_82573) + if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574) ret_val = e1000e_acquire_nvm(hw); if (ret_val) @@ -461,6 +501,7 @@ static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words, switch (hw->mac.type) { case e1000_82573: + case e1000_82574: ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data); break; case e1000_82571: @@ -735,7 +776,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) * Must acquire the MDIO ownership before MAC reset. * Ownership defaults to firmware after a reset. */ - if (hw->mac.type == e1000_82573) { + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { extcnf_ctrl = er32(EXTCNF_CTRL); extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; @@ -776,7 +817,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) * Need to wait for Phy configuration completion before accessing * NVM and Phy. */ - if (hw->mac.type == e1000_82573) + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) msleep(25); /* Clear any pending interrupt events. */ @@ -843,7 +884,7 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw) ew32(TXDCTL(0), reg_data); /* ...for both queues. */ - if (mac->type != e1000_82573) { + if (mac->type != e1000_82573 && mac->type != e1000_82574) { reg_data = er32(TXDCTL(1)); reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB | @@ -918,19 +959,28 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) } /* Device Control */ - if (hw->mac.type == e1000_82573) { + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { reg = er32(CTRL); reg &= ~(1 << 29); ew32(CTRL, reg); } /* Extended Device Control */ - if (hw->mac.type == e1000_82573) { + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { reg = er32(CTRL_EXT); reg &= ~(1 << 23); reg |= (1 << 22); ew32(CTRL_EXT, reg); } + + /* PCI-Ex Control Register */ + if (hw->mac.type == e1000_82574) { + reg = er32(GCR); + reg |= (1 << 22); + ew32(GCR, reg); + } + + return; } /** @@ -947,7 +997,7 @@ void e1000e_clear_vfta(struct e1000_hw *hw) u32 vfta_offset = 0; u32 vfta_bit_in_reg = 0; - if (hw->mac.type == e1000_82573) { + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { if (hw->mng_cookie.vlan_id != 0) { /* * The VFTA is a 4096b bit-field, each identifying @@ -976,6 +1026,48 @@ void e1000e_clear_vfta(struct e1000_hw *hw) } /** + * e1000_check_mng_mode_82574 - Check manageability is enabled + * @hw: pointer to the HW structure + * + * Reads the NVM Initialization Control Word 2 and returns true + * (>0) if any manageability is enabled, else false (0). + **/ +static bool e1000_check_mng_mode_82574(struct e1000_hw *hw) +{ + u16 data; + + e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data); + return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0; +} + +/** + * e1000_led_on_82574 - Turn LED on + * @hw: pointer to the HW structure + * + * Turn LED on. + **/ +static s32 e1000_led_on_82574(struct e1000_hw *hw) +{ + u32 ctrl; + u32 i; + + ctrl = hw->mac.ledctl_mode2; + if (!(E1000_STATUS_LU & er32(STATUS))) { + /* + * If no link, then turn LED on by setting the invert bit + * for each LED that's "on" (0x0E) in ledctl_mode2. + */ + for (i = 0; i < 4; i++) + if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == + E1000_LEDCTL_MODE_LED_ON) + ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8)); + } + ew32(LEDCTL, ctrl); + + return 0; +} + +/** * e1000_update_mc_addr_list_82571 - Update Multicast addresses * @hw: pointer to the HW structure * @mc_addr_list: array of multicast addresses to program @@ -1018,7 +1110,8 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw) * the default flow control setting, so we explicitly * set it to full. */ - if (hw->mac.type == e1000_82573) + if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && + hw->fc.type == e1000_fc_default) hw->fc.type = e1000_fc_full; return e1000e_setup_link(hw); @@ -1045,6 +1138,7 @@ static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw) switch (hw->phy.type) { case e1000_phy_m88: + case e1000_phy_bm: ret_val = e1000e_copper_link_setup_m88(hw); break; case e1000_phy_igp_2: @@ -1114,11 +1208,10 @@ static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data) return ret_val; } - if (hw->mac.type == e1000_82573 && + if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && *data == ID_LED_RESERVED_F746) *data = ID_LED_DEFAULT_82573; - else if (*data == ID_LED_RESERVED_0000 || - *data == ID_LED_RESERVED_FFFF) + else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) *data = ID_LED_DEFAULT; return 0; @@ -1265,13 +1358,13 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw) } static struct e1000_mac_operations e82571_mac_ops = { - .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, + /* .check_mng_mode: mac type dependent */ /* .check_for_link: media type dependent */ .cleanup_led = e1000e_cleanup_led_generic, .clear_hw_cntrs = e1000_clear_hw_cntrs_82571, .get_bus_info = e1000e_get_bus_info_pcie, /* .get_link_up_info: media type dependent */ - .led_on = e1000e_led_on_generic, + /* .led_on: mac type dependent */ .led_off = e1000e_led_off_generic, .update_mc_addr_list = e1000_update_mc_addr_list_82571, .reset_hw = e1000_reset_hw_82571, @@ -1312,6 +1405,22 @@ static struct e1000_phy_operations e82_phy_ops_m88 = { .write_phy_reg = e1000e_write_phy_reg_m88, }; +static struct e1000_phy_operations e82_phy_ops_bm = { + .acquire_phy = e1000_get_hw_semaphore_82571, + .check_reset_block = e1000e_check_reset_block_generic, + .commit_phy = e1000e_phy_sw_reset, + .force_speed_duplex = e1000e_phy_force_speed_duplex_m88, + .get_cfg_done = e1000e_get_cfg_done, + .get_cable_length = e1000e_get_cable_length_m88, + .get_phy_info = e1000e_get_phy_info_m88, + .read_phy_reg = e1000e_read_phy_reg_bm2, + .release_phy = e1000_put_hw_semaphore_82571, + .reset_phy = e1000e_phy_hw_reset_generic, + .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, + .set_d3_lplu_state = e1000e_set_d3_lplu_state, + .write_phy_reg = e1000e_write_phy_reg_bm2, +}; + static struct e1000_nvm_operations e82571_nvm_ops = { .acquire_nvm = e1000_acquire_nvm_82571, .read_nvm = e1000e_read_nvm_eerd, @@ -1375,3 +1484,21 @@ struct e1000_info e1000_82573_info = { .nvm_ops = &e82571_nvm_ops, }; +struct e1000_info e1000_82574_info = { + .mac = e1000_82574, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_MSIX + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_SMART_POWER_DOWN + | FLAG_HAS_AMT + | FLAG_HAS_CTRLEXT_ON_LOAD, + .pba = 20, + .get_variants = e1000_get_variants_82571, + .mac_ops = &e82571_mac_ops, + .phy_ops = &e82_phy_ops_bm, + .nvm_ops = &e82571_nvm_ops, +}; + diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 14b0e6cd3b8..48f79ecb82a 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -71,9 +71,11 @@ #define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 #define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 +#define E1000_CTRL_EXT_EIAME 0x01000000 #define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ +#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ /* Receive Descriptor bit definitions */ #define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ @@ -299,6 +301,7 @@ #define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ /* Header split receive */ +#define E1000_RFCTL_ACK_DIS 0x00001000 #define E1000_RFCTL_EXTEN 0x00008000 #define E1000_RFCTL_IPV6_EX_DIS 0x00010000 #define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 @@ -363,6 +366,11 @@ #define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */ #define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */ #define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ +#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */ +#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */ +#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */ +#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ +#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ /* * This defines the bits that are set in the Interrupt Mask @@ -386,6 +394,11 @@ #define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* Rx sequence error */ #define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* Rx desc min. threshold */ #define E1000_IMS_RXT0 E1000_ICR_RXT0 /* Rx timer intr */ +#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */ +#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */ +#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */ +#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */ +#define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */ /* Interrupt Cause Set */ #define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ @@ -505,6 +518,7 @@ #define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ /* Autoneg Expansion Register */ +#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ /* 1000BASE-T Control Register */ #define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ @@ -540,6 +554,7 @@ #define E1000_EECD_DO 0x00000008 /* NVM Data Out */ #define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ #define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ +#define E1000_EECD_PRES 0x00000100 /* NVM Present */ #define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ /* NVM Addressing bits based on type (0-small, 1-large) */ #define E1000_EECD_ADDR_BITS 0x00000400 diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index ac4e506b4f8..c55de1c027a 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -62,6 +62,11 @@ struct e1000_info; e_printk(KERN_NOTICE, adapter, format, ## arg) +/* Interrupt modes, as used by the IntMode paramter */ +#define E1000E_INT_MODE_LEGACY 0 +#define E1000E_INT_MODE_MSI 1 +#define E1000E_INT_MODE_MSIX 2 + /* Tx/Rx descriptor defines */ #define E1000_DEFAULT_TXD 256 #define E1000_MAX_TXD 4096 @@ -95,9 +100,11 @@ enum e1000_boards { board_82571, board_82572, board_82573, + board_82574, board_80003es2lan, board_ich8lan, board_ich9lan, + board_ich10lan, }; struct e1000_queue_stats { @@ -146,6 +153,12 @@ struct e1000_ring { /* array of buffer information structs */ struct e1000_buffer *buffer_info; + char name[IFNAMSIZ + 5]; + u32 ims_val; + u32 itr_val; + u16 itr_register; + int set_itr; + struct sk_buff *rx_skb_top; struct e1000_queue_stats stats; @@ -257,7 +270,6 @@ struct e1000_adapter { struct net_device *netdev; struct pci_dev *pdev; struct net_device_stats net_stats; - spinlock_t stats_lock; /* prevent concurrent stats updates */ /* structs defined in e1000_hw.h */ struct e1000_hw hw; @@ -274,6 +286,9 @@ struct e1000_adapter { u32 test_icr; u32 msg_enable; + struct msix_entry *msix_entries; + int int_mode; + u32 eiac_mask; u32 eeprom_wol; u32 wol; @@ -284,6 +299,8 @@ struct e1000_adapter { unsigned long led_status; unsigned int flags; + struct work_struct downshift_task; + struct work_struct update_phy_task; }; struct e1000_info { @@ -305,7 +322,9 @@ struct e1000_info { #define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) #define FLAG_HAS_SWSM_ON_LOAD (1 << 6) #define FLAG_HAS_JUMBO_FRAMES (1 << 7) +#define FLAG_READ_ONLY_NVM (1 << 8) #define FLAG_IS_ICH (1 << 9) +#define FLAG_HAS_MSIX (1 << 10) #define FLAG_HAS_SMART_POWER_DOWN (1 << 11) #define FLAG_IS_QUAD_PORT_A (1 << 12) #define FLAG_IS_QUAD_PORT (1 << 13) @@ -364,6 +383,8 @@ extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter); extern void e1000e_free_rx_resources(struct e1000_adapter *adapter); extern void e1000e_free_tx_resources(struct e1000_adapter *adapter); extern void e1000e_update_stats(struct e1000_adapter *adapter); +extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); +extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); extern unsigned int copybreak; @@ -372,8 +393,10 @@ extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw); extern struct e1000_info e1000_82571_info; extern struct e1000_info e1000_82572_info; extern struct e1000_info e1000_82573_info; +extern struct e1000_info e1000_82574_info; extern struct e1000_info e1000_ich8_info; extern struct e1000_info e1000_ich9_info; +extern struct e1000_info e1000_ich10_info; extern struct e1000_info e1000_es2_info; extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num); @@ -385,6 +408,7 @@ extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw); extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw); extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state); +extern void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw); extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, bool state); extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); @@ -446,10 +470,13 @@ extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw); extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw); extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); +extern s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw); extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id); extern s32 e1000e_determine_phy_address(struct e1000_hw *hw); extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data); extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data); extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data); extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data); @@ -520,7 +547,12 @@ static inline s32 e1000_get_phy_info(struct e1000_hw *hw) return hw->phy.ops.get_phy_info(hw); } -extern bool e1000e_check_mng_mode(struct e1000_hw *hw); +static inline s32 e1000e_check_mng_mode(struct e1000_hw *hw) +{ + return hw->mac.ops.check_mng_mode(hw); +} + +extern bool e1000e_check_mng_mode_generic(struct e1000_hw *hw); extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw); extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length); diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index dc552d7d6fa..da9c09c248e 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -1247,7 +1247,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) } static struct e1000_mac_operations es2_mac_ops = { - .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, + .check_mng_mode = e1000e_check_mng_mode_generic, /* check_for_link dependent on media type */ .cleanup_led = e1000e_cleanup_led_generic, .clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan, diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index e21c9e0f373..70c11c811a0 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -432,6 +432,10 @@ static void e1000_get_regs(struct net_device *netdev, regs_buff[11] = er32(TIDV); regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */ + + /* ethtool doesn't use anything past this point, so all this + * code is likely legacy junk for apps that may or may not + * exist */ if (hw->phy.type == e1000_phy_m88) { e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); regs_buff[13] = (u32)phy_data; /* cable length */ @@ -447,7 +451,7 @@ static void e1000_get_regs(struct net_device *netdev, regs_buff[22] = adapter->phy_stats.receive_errors; regs_buff[23] = regs_buff[13]; /* mdix mode */ } - regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */ + regs_buff[21] = 0; /* was idle_errors */ e1e_rphy(hw, PHY_1000T_STATUS, &phy_data); regs_buff[24] = (u32)phy_data; /* phy local receiver status */ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ @@ -529,6 +533,9 @@ static int e1000_set_eeprom(struct net_device *netdev, if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16))) return -EFAULT; + if (adapter->flags & FLAG_READ_ONLY_NVM) + return -EINVAL; + max_len = hw->nvm.word_size * 2; first_word = eeprom->offset >> 1; @@ -568,6 +575,7 @@ static int e1000_set_eeprom(struct net_device *netdev, * and flush shadow RAM for 82573 controllers */ if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) || + (hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82573))) e1000e_update_nvm_checksum(hw); @@ -779,8 +787,10 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) toggle = 0x7FFFF3FF; break; case e1000_82573: + case e1000_82574: case e1000_ich8lan: case e1000_ich9lan: + case e1000_ich10lan: toggle = 0x7FFFF033; break; default: @@ -833,7 +843,9 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); for (i = 0; i < mac->rar_entry_count; i++) REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), - 0x8003FFFF, 0xFFFFFFFF); + ((mac->type == e1000_ich10lan) ? + 0x8007FFFF : 0x8003FFFF), + 0xFFFFFFFF); for (i = 0; i < mac->mta_reg_count; i++) REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); @@ -884,10 +896,18 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) u32 shared_int = 1; u32 irq = adapter->pdev->irq; int i; + int ret_val = 0; + int int_mode = E1000E_INT_MODE_LEGACY; *data = 0; - /* NOTE: we don't test MSI interrupts here, yet */ + /* NOTE: we don't test MSI/MSI-X interrupts here, yet */ + if (adapter->int_mode == E1000E_INT_MODE_MSIX) { + int_mode = adapter->int_mode; + e1000e_reset_interrupt_capability(adapter); + adapter->int_mode = E1000E_INT_MODE_LEGACY; + e1000e_set_interrupt_capability(adapter); + } /* Hook up test interrupt handler just for this test */ if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, netdev)) { @@ -895,7 +915,8 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, netdev->name, netdev)) { *data = 1; - return -1; + ret_val = -1; + goto out; } e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared")); @@ -905,12 +926,23 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Test each interrupt */ for (i = 0; i < 10; i++) { - if ((adapter->flags & FLAG_IS_ICH) && (i == 8)) - continue; - /* Interrupt to test */ mask = 1 << i; + if (adapter->flags & FLAG_IS_ICH) { + switch (mask) { + case E1000_ICR_RXSEQ: + continue; + case 0x00000100: + if (adapter->hw.mac.type == e1000_ich8lan || + adapter->hw.mac.type == e1000_ich9lan) + continue; + break; + default: + break; + } + } + if (!shared_int) { /* * Disable the interrupt to be reported in @@ -974,7 +1006,14 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Unhook test interrupt handler */ free_irq(irq, netdev); - return *data; +out: + if (int_mode == E1000E_INT_MODE_MSIX) { + e1000e_reset_interrupt_capability(adapter); + adapter->int_mode = int_mode; + e1000e_set_interrupt_capability(adapter); + } + + return ret_val; } static void e1000_free_desc_rings(struct e1000_adapter *adapter) @@ -1755,11 +1794,13 @@ static void e1000_led_blink_callback(unsigned long data) static int e1000_phys_id(struct net_device *netdev, u32 data) { struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; if (!data) data = INT_MAX; - if (adapter->hw.phy.type == e1000_phy_ife) { + if ((hw->phy.type == e1000_phy_ife) || + (hw->mac.type == e1000_82574)) { if (!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = @@ -1769,16 +1810,16 @@ static int e1000_phys_id(struct net_device *netdev, u32 data) mod_timer(&adapter->blink_timer, jiffies); msleep_interruptible(data * 1000); del_timer_sync(&adapter->blink_timer); - e1e_wphy(&adapter->hw, - IFE_PHY_SPECIAL_CONTROL_LED, 0); + if (hw->phy.type == e1000_phy_ife) + e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); } else { - e1000e_blink_led(&adapter->hw); + e1000e_blink_led(hw); msleep_interruptible(data * 1000); } - adapter->hw.mac.ops.led_off(&adapter->hw); + hw->mac.ops.led_off(hw); clear_bit(E1000_LED_ON, &adapter->led_status); - adapter->hw.mac.ops.cleanup_led(&adapter->hw); + hw->mac.ops.cleanup_led(hw); return 0; } diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 74f263acb17..f66ed37a7f7 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -65,7 +65,11 @@ enum e1e_registers { E1000_ICS = 0x000C8, /* Interrupt Cause Set - WO */ E1000_IMS = 0x000D0, /* Interrupt Mask Set - RW */ E1000_IMC = 0x000D8, /* Interrupt Mask Clear - WO */ + E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */ E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */ + E1000_IVAR = 0x000E4, /* Interrupt Vector Allocation - RW */ + E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */ +#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2)) E1000_RCTL = 0x00100, /* Rx Control - RW */ E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */ E1000_TXCW = 0x00178, /* Tx Configuration Word - RW */ @@ -332,6 +336,7 @@ enum e1e_registers { #define E1000_DEV_ID_82573E 0x108B #define E1000_DEV_ID_82573E_IAMT 0x108C #define E1000_DEV_ID_82573L 0x109A +#define E1000_DEV_ID_82574L 0x10D3 #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 @@ -346,6 +351,7 @@ enum e1e_registers { #define E1000_DEV_ID_ICH8_IFE_G 0x10C5 #define E1000_DEV_ID_ICH8_IGP_M 0x104D #define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD +#define E1000_DEV_ID_ICH9_BM 0x10E5 #define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5 #define E1000_DEV_ID_ICH9_IGP_M 0x10BF #define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB @@ -356,6 +362,10 @@ enum e1e_registers { #define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC #define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD #define E1000_DEV_ID_ICH10_R_BM_V 0x10CE +#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE +#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF + +#define E1000_REVISION_4 4 #define E1000_FUNC_1 1 @@ -363,9 +373,11 @@ enum e1000_mac_type { e1000_82571, e1000_82572, e1000_82573, + e1000_82574, e1000_80003es2lan, e1000_ich8lan, e1000_ich9lan, + e1000_ich10lan, }; enum e1000_media_type { @@ -696,8 +708,7 @@ struct e1000_host_mng_command_info { /* Function pointers and static data for the MAC. */ struct e1000_mac_operations { - u32 mng_mode_enab; - + bool (*check_mng_mode)(struct e1000_hw *); s32 (*check_for_link)(struct e1000_hw *); s32 (*cleanup_led)(struct e1000_hw *); void (*clear_hw_cntrs)(struct e1000_hw *); diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 9e38452a738..523b9716a54 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -43,7 +43,9 @@ * 82567LM-2 Gigabit Network Connection * 82567LF-2 Gigabit Network Connection * 82567V-2 Gigabit Network Connection - * 82562GT-3 10/100 Network Connection + * 82567LF-3 Gigabit Network Connection + * 82567LM-3 Gigabit Network Connection + * 82567LM-4 Gigabit Network Connection */ #include <linux/netdevice.h> @@ -58,6 +60,7 @@ #define ICH_FLASH_HSFCTL 0x0006 #define ICH_FLASH_FADDR 0x0008 #define ICH_FLASH_FDATA0 0x0010 +#define ICH_FLASH_PR0 0x0074 #define ICH_FLASH_READ_COMMAND_TIMEOUT 500 #define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500 @@ -150,6 +153,19 @@ union ich8_hws_flash_regacc { u16 regval; }; +/* ICH Flash Protected Region */ +union ich8_flash_protected_range { + struct ich8_pr { + u32 base:13; /* 0:12 Protected Range Base */ + u32 reserved1:2; /* 13:14 Reserved */ + u32 rpe:1; /* 15 Read Protection Enable */ + u32 limit:13; /* 16:28 Protected Range Limit */ + u32 reserved2:2; /* 29:30 Reserved */ + u32 wpe:1; /* 31 Write Protection Enable */ + } range; + u32 regval; +}; + static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); @@ -157,12 +173,15 @@ static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw); static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, u8 byte); +static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, + u8 *data); static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, u16 *data); static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, u8 size, u16 *data); static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); +static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) { @@ -366,6 +385,9 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) return 0; } +static DEFINE_MUTEX(nvm_mutex); +static pid_t nvm_owner = -1; + /** * e1000_acquire_swflag_ich8lan - Acquire software control flag * @hw: pointer to the HW structure @@ -379,6 +401,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) u32 extcnf_ctrl; u32 timeout = PHY_CFG_TIMEOUT; + might_sleep(); + + if (!mutex_trylock(&nvm_mutex)) { + WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n", + nvm_owner); + mutex_lock(&nvm_mutex); + } + nvm_owner = current->pid; + while (timeout) { extcnf_ctrl = er32(EXTCNF_CTRL); extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; @@ -393,6 +424,10 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) if (!timeout) { hw_dbg(hw, "FW or HW has locked the resource for too long.\n"); + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; + ew32(EXTCNF_CTRL, extcnf_ctrl); + nvm_owner = -1; + mutex_unlock(&nvm_mutex); return -E1000_ERR_CONFIG; } @@ -414,6 +449,25 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) extcnf_ctrl = er32(EXTCNF_CTRL); extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; ew32(EXTCNF_CTRL, extcnf_ctrl); + + nvm_owner = -1; + mutex_unlock(&nvm_mutex); +} + +/** + * e1000_check_mng_mode_ich8lan - Checks management mode + * @hw: pointer to the HW structure + * + * This checks if the adapter has manageability enabled. + * This is a function pointer entry point only called by read/write + * routines for the PHY and NVM parts. + **/ +static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) +{ + u32 fwsm = er32(FWSM); + + return (fwsm & E1000_FWSM_MODE_MASK) == + (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); } /** @@ -897,6 +951,56 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) } /** + * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 + * @hw: pointer to the HW structure + * @bank: pointer to the variable that returns the active bank + * + * Reads signature byte from the NVM using the flash access registers. + **/ +static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + /* flash bank size is in words */ + u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); + u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; + u8 bank_high_byte = 0; + + if (hw->mac.type != e1000_ich10lan) { + if (er32(EECD) & E1000_EECD_SEC1VAL) + *bank = 1; + else + *bank = 0; + } else { + /* + * Make sure the signature for bank 0 is valid, + * if not check for bank1 + */ + e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte); + if ((bank_high_byte & 0xC0) == 0x80) { + *bank = 0; + } else { + /* + * find if segment 1 is valid by verifying + * bit 15:14 = 10b in word 0x13 + */ + e1000_read_flash_byte_ich8lan(hw, + act_offset + bank1_offset, + &bank_high_byte); + + /* bank1 has a valid signature equivalent to SEC1V */ + if ((bank_high_byte & 0xC0) == 0x80) { + *bank = 1; + } else { + hw_dbg(hw, "ERROR: EEPROM not present\n"); + return -E1000_ERR_NVM; + } + } + } + + return 0; +} + +/** * e1000_read_nvm_ich8lan - Read word(s) from the NVM * @hw: pointer to the HW structure * @offset: The offset (in bytes) of the word(s) to read. @@ -912,6 +1016,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; u32 act_offset; s32 ret_val; + u32 bank = 0; u16 i, word; if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || @@ -924,10 +1029,11 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, if (ret_val) return ret_val; - /* Start with the bank offset, then add the relative offset. */ - act_offset = (er32(EECD) & E1000_EECD_SEC1VAL) - ? nvm->flash_bank_size - : 0; + ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); + if (ret_val) + return ret_val; + + act_offset = (bank) ? nvm->flash_bank_size : 0; act_offset += offset; for (i = 0; i < words; i++) { @@ -1075,6 +1181,29 @@ static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, } /** + * e1000_read_flash_byte_ich8lan - Read byte from flash + * @hw: pointer to the HW structure + * @offset: The offset of the byte to read. + * @data: Pointer to a byte to store the value read. + * + * Reads a single byte from the NVM using the flash access registers. + **/ +static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, + u8 *data) +{ + s32 ret_val; + u16 word = 0; + + ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); + if (ret_val) + return ret_val; + + *data = (u8)word; + + return 0; +} + +/** * e1000_read_flash_data_ich8lan - Read byte or word from NVM * @hw: pointer to the HW structure * @offset: The offset (in bytes) of the byte or word to read. @@ -1205,7 +1334,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) { struct e1000_nvm_info *nvm = &hw->nvm; struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; - u32 i, act_offset, new_bank_offset, old_bank_offset; + u32 i, act_offset, new_bank_offset, old_bank_offset, bank; s32 ret_val; u16 data; @@ -1225,7 +1354,11 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) * write to bank 0 etc. We also need to erase the segment that * is going to be written */ - if (!(er32(EECD) & E1000_EECD_SEC1VAL)) { + ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); + if (ret_val) + return ret_val; + + if (bank == 0) { new_bank_offset = nvm->flash_bank_size; old_bank_offset = 0; e1000_erase_flash_bank_ich8lan(hw, 1); @@ -1284,6 +1417,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) * programming failed. */ if (ret_val) { + /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */ hw_dbg(hw, "Flash commit failed.\n"); e1000_release_swflag_ich8lan(hw); return ret_val; @@ -1374,6 +1508,49 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) } /** + * e1000e_write_protect_nvm_ich8lan - Make the NVM read-only + * @hw: pointer to the HW structure + * + * To prevent malicious write/erase of the NVM, set it to be read-only + * so that the hardware ignores all write/erase cycles of the NVM via + * the flash control registers. The shadow-ram copy of the NVM will + * still be updated, however any updates to this copy will not stick + * across driver reloads. + **/ +void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw) +{ + union ich8_flash_protected_range pr0; + union ich8_hws_flash_status hsfsts; + u32 gfpreg; + s32 ret_val; + + ret_val = e1000_acquire_swflag_ich8lan(hw); + if (ret_val) + return; + + gfpreg = er32flash(ICH_FLASH_GFPREG); + + /* Write-protect GbE Sector of NVM */ + pr0.regval = er32flash(ICH_FLASH_PR0); + pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK; + pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK); + pr0.range.wpe = true; + ew32flash(ICH_FLASH_PR0, pr0.regval); + + /* + * Lock down a subset of GbE Flash Control Registers, e.g. + * PR0 to prevent the write-protection from being lifted. + * Once FLOCKDN is set, the registers protected by it cannot + * be written until FLOCKDN is cleared by a hardware reset. + */ + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + hsfsts.hsf_status.flockdn = true; + ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval); + + e1000_release_swflag_ich8lan(hw); +} + +/** * e1000_write_flash_data_ich8lan - Writes bytes to the NVM * @hw: pointer to the HW structure * @offset: The offset (in bytes) of the byte/word to read. @@ -1720,6 +1897,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ew32(CTRL, (ctrl | E1000_CTRL_RST)); msleep(20); + /* release the swflag because it is not reset by hardware reset */ + e1000_release_swflag_ich8lan(hw); + ret_val = e1000e_get_auto_rd_done(hw); if (ret_val) { /* @@ -2189,13 +2369,14 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation * to a lower speed. * - * Should only be called for ICH9 devices. + * Should only be called for ICH9 and ICH10 devices. **/ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) { u32 phy_ctrl; - if (hw->mac.type == e1000_ich9lan) { + if ((hw->mac.type == e1000_ich10lan) || + (hw->mac.type == e1000_ich9lan)) { phy_ctrl = er32(PHY_CTRL); phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE; @@ -2253,6 +2434,39 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) } /** + * e1000_get_cfg_done_ich8lan - Read config done bit + * @hw: pointer to the HW structure + * + * Read the management control register for the config done bit for + * completion status. NOTE: silicon which is EEPROM-less will fail trying + * to read the config done bit, so an error is *ONLY* logged and returns + * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon + * would not be able to be reset or change link. + **/ +static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) +{ + u32 bank = 0; + + e1000e_get_cfg_done(hw); + + /* If EEPROM is not marked present, init the IGP 3 PHY manually */ + if (hw->mac.type != e1000_ich10lan) { + if (((er32(EECD) & E1000_EECD_PRES) == 0) && + (hw->phy.type == e1000_phy_igp_3)) { + e1000e_phy_init_script_igp3(hw); + } + } else { + if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) { + /* Maybe we should do a basic PHY config */ + hw_dbg(hw, "EEPROM not present\n"); + return -E1000_ERR_CONFIG; + } + } + + return 0; +} + +/** * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters * @hw: pointer to the HW structure * @@ -2282,7 +2496,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) } static struct e1000_mac_operations ich8_mac_ops = { - .mng_mode_enab = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, + .check_mng_mode = e1000_check_mng_mode_ich8lan, .check_for_link = e1000e_check_for_copper_link, .cleanup_led = e1000_cleanup_led_ich8lan, .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, @@ -2302,7 +2516,7 @@ static struct e1000_phy_operations ich8_phy_ops = { .check_reset_block = e1000_check_reset_block_ich8lan, .commit_phy = NULL, .force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan, - .get_cfg_done = e1000e_get_cfg_done, + .get_cfg_done = e1000_get_cfg_done_ich8lan, .get_cable_length = e1000e_get_cable_length_igp_2, .get_phy_info = e1000_get_phy_info_ich8lan, .read_phy_reg = e1000e_read_phy_reg_igp, @@ -2357,3 +2571,20 @@ struct e1000_info e1000_ich9_info = { .nvm_ops = &ich8_nvm_ops, }; +struct e1000_info e1000_ich10_info = { + .mac = e1000_ich10lan, + .flags = FLAG_HAS_JUMBO_FRAMES + | FLAG_IS_ICH + | FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_ERT + | FLAG_HAS_FLASH + | FLAG_APME_IN_WUC, + .pba = 10, + .get_variants = e1000_get_variants_ich8lan, + .mac_ops = &ich8_mac_ops, + .phy_ops = &ich8_phy_ops, + .nvm_ops = &ich8_nvm_ops, +}; diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index f1f4e9dfd0a..089578f6855 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -2012,6 +2012,7 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) } msleep(10); + nvm->ops.release_nvm(hw); return 0; } @@ -2222,17 +2223,18 @@ static s32 e1000_mng_enable_host_if(struct e1000_hw *hw) } /** - * e1000e_check_mng_mode - check management mode + * e1000e_check_mng_mode_generic - check management mode * @hw: pointer to the HW structure * * Reads the firmware semaphore register and returns true (>0) if * manageability is enabled, else false (0). **/ -bool e1000e_check_mng_mode(struct e1000_hw *hw) +bool e1000e_check_mng_mode_generic(struct e1000_hw *hw) { u32 fwsm = er32(FWSM); - return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab; + return (fwsm & E1000_FWSM_MODE_MASK) == + (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); } /** diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index d266510c8a9..abd492b7336 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -47,7 +47,7 @@ #include "e1000.h" -#define DRV_VERSION "0.3.3.3-k2" +#define DRV_VERSION "0.3.3.3-k6" char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; @@ -55,9 +55,11 @@ static const struct e1000_info *e1000_info_tbl[] = { [board_82571] = &e1000_82571_info, [board_82572] = &e1000_82572_info, [board_82573] = &e1000_82573_info, + [board_82574] = &e1000_82574_info, [board_80003es2lan] = &e1000_es2_info, [board_ich8lan] = &e1000_ich8_info, [board_ich9lan] = &e1000_ich9_info, + [board_ich10lan] = &e1000_ich10_info, }; #ifdef DEBUG @@ -1115,6 +1117,14 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter) writel(0, adapter->hw.hw_addr + rx_ring->tail); } +static void e1000e_downshift_workaround(struct work_struct *work) +{ + struct e1000_adapter *adapter = container_of(work, + struct e1000_adapter, downshift_task); + + e1000e_gig_downshift_workaround_ich8lan(&adapter->hw); +} + /** * e1000_intr_msi - Interrupt Handler * @irq: interrupt number @@ -1139,7 +1149,7 @@ static irqreturn_t e1000_intr_msi(int irq, void *data) */ if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && (!(er32(STATUS) & E1000_STATUS_LU))) - e1000e_gig_downshift_workaround_ich8lan(hw); + schedule_work(&adapter->downshift_task); /* * 80003ES2LAN workaround-- For packet buffer work-around on @@ -1179,8 +1189,8 @@ static irqreturn_t e1000_intr(int irq, void *data) struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - u32 rctl, icr = er32(ICR); + if (!icr) return IRQ_NONE; /* Not our interrupt */ @@ -1205,7 +1215,7 @@ static irqreturn_t e1000_intr(int irq, void *data) */ if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && (!(er32(STATUS) & E1000_STATUS_LU))) - e1000e_gig_downshift_workaround_ich8lan(hw); + schedule_work(&adapter->downshift_task); /* * 80003ES2LAN workaround-- @@ -1236,6 +1246,263 @@ static irqreturn_t e1000_intr(int irq, void *data) return IRQ_HANDLED; } +static irqreturn_t e1000_msix_other(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 icr = er32(ICR); + + if (!(icr & E1000_ICR_INT_ASSERTED)) { + ew32(IMS, E1000_IMS_OTHER); + return IRQ_NONE; + } + + if (icr & adapter->eiac_mask) + ew32(ICS, (icr & adapter->eiac_mask)); + + if (icr & E1000_ICR_OTHER) { + if (!(icr & E1000_ICR_LSC)) + goto no_link_interrupt; + hw->mac.get_link_status = 1; + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + +no_link_interrupt: + ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER); + + return IRQ_HANDLED; +} + + +static irqreturn_t e1000_intr_msix_tx(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *tx_ring = adapter->tx_ring; + + + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + + if (!e1000_clean_tx_irq(adapter)) + /* Ring was not completely cleaned, so fire another interrupt */ + ew32(ICS, tx_ring->ims_val); + + return IRQ_HANDLED; +} + +static irqreturn_t e1000_intr_msix_rx(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* Write the ITR value calculated at the end of the + * previous interrupt. + */ + if (adapter->rx_ring->set_itr) { + writel(1000000000 / (adapter->rx_ring->itr_val * 256), + adapter->hw.hw_addr + adapter->rx_ring->itr_register); + adapter->rx_ring->set_itr = 0; + } + + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; + __netif_rx_schedule(netdev, &adapter->napi); + } + return IRQ_HANDLED; +} + +/** + * e1000_configure_msix - Configure MSI-X hardware + * + * e1000_configure_msix sets up the hardware to properly + * generate MSI-X interrupts. + **/ +static void e1000_configure_msix(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_ring *tx_ring = adapter->tx_ring; + int vector = 0; + u32 ctrl_ext, ivar = 0; + + adapter->eiac_mask = 0; + + /* Workaround issue with spurious interrupts on 82574 in MSI-X mode */ + if (hw->mac.type == e1000_82574) { + u32 rfctl = er32(RFCTL); + rfctl |= E1000_RFCTL_ACK_DIS; + ew32(RFCTL, rfctl); + } + +#define E1000_IVAR_INT_ALLOC_VALID 0x8 + /* Configure Rx vector */ + rx_ring->ims_val = E1000_IMS_RXQ0; + adapter->eiac_mask |= rx_ring->ims_val; + if (rx_ring->itr_val) + writel(1000000000 / (rx_ring->itr_val * 256), + hw->hw_addr + rx_ring->itr_register); + else + writel(1, hw->hw_addr + rx_ring->itr_register); + ivar = E1000_IVAR_INT_ALLOC_VALID | vector; + + /* Configure Tx vector */ + tx_ring->ims_val = E1000_IMS_TXQ0; + vector++; + if (tx_ring->itr_val) + writel(1000000000 / (tx_ring->itr_val * 256), + hw->hw_addr + tx_ring->itr_register); + else + writel(1, hw->hw_addr + tx_ring->itr_register); + adapter->eiac_mask |= tx_ring->ims_val; + ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8); + + /* set vector for Other Causes, e.g. link changes */ + vector++; + ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16); + if (rx_ring->itr_val) + writel(1000000000 / (rx_ring->itr_val * 256), + hw->hw_addr + E1000_EITR_82574(vector)); + else + writel(1, hw->hw_addr + E1000_EITR_82574(vector)); + + /* Cause Tx interrupts on every write back */ + ivar |= (1 << 31); + + ew32(IVAR, ivar); + + /* enable MSI-X PBA support */ + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_PBA_CLR; + + /* Auto-Mask Other interrupts upon ICR read */ +#define E1000_EIAC_MASK_82574 0x01F00000 + ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER); + ctrl_ext |= E1000_CTRL_EXT_EIAME; + ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); +} + +void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter) +{ + if (adapter->msix_entries) { + pci_disable_msix(adapter->pdev); + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + } else if (adapter->flags & FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~FLAG_MSI_ENABLED; + } + + return; +} + +/** + * e1000e_set_interrupt_capability - set MSI or MSI-X if supported + * + * Attempt to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +void e1000e_set_interrupt_capability(struct e1000_adapter *adapter) +{ + int err; + int numvecs, i; + + + switch (adapter->int_mode) { + case E1000E_INT_MODE_MSIX: + if (adapter->flags & FLAG_HAS_MSIX) { + numvecs = 3; /* RxQ0, TxQ0 and other */ + adapter->msix_entries = kcalloc(numvecs, + sizeof(struct msix_entry), + GFP_KERNEL); + if (adapter->msix_entries) { + for (i = 0; i < numvecs; i++) + adapter->msix_entries[i].entry = i; + + err = pci_enable_msix(adapter->pdev, + adapter->msix_entries, + numvecs); + if (err == 0) + return; + } + /* MSI-X failed, so fall through and try MSI */ + e_err("Failed to initialize MSI-X interrupts. " + "Falling back to MSI interrupts.\n"); + e1000e_reset_interrupt_capability(adapter); + } + adapter->int_mode = E1000E_INT_MODE_MSI; + /* Fall through */ + case E1000E_INT_MODE_MSI: + if (!pci_enable_msi(adapter->pdev)) { + adapter->flags |= FLAG_MSI_ENABLED; + } else { + adapter->int_mode = E1000E_INT_MODE_LEGACY; + e_err("Failed to initialize MSI interrupts. Falling " + "back to legacy interrupts.\n"); + } + /* Fall through */ + case E1000E_INT_MODE_LEGACY: + /* Don't do anything; this is the system default */ + break; + } + + return; +} + +/** + * e1000_request_msix - Initialize MSI-X interrupts + * + * e1000_request_msix allocates MSI-X vectors and requests interrupts from the + * kernel. + **/ +static int e1000_request_msix(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int err = 0, vector = 0; + + if (strlen(netdev->name) < (IFNAMSIZ - 5)) + sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name); + else + memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ); + err = request_irq(adapter->msix_entries[vector].vector, + &e1000_intr_msix_rx, 0, adapter->rx_ring->name, + netdev); + if (err) + goto out; + adapter->rx_ring->itr_register = E1000_EITR_82574(vector); + adapter->rx_ring->itr_val = adapter->itr; + vector++; + + if (strlen(netdev->name) < (IFNAMSIZ - 5)) + sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name); + else + memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ); + err = request_irq(adapter->msix_entries[vector].vector, + &e1000_intr_msix_tx, 0, adapter->tx_ring->name, + netdev); + if (err) + goto out; + adapter->tx_ring->itr_register = E1000_EITR_82574(vector); + adapter->tx_ring->itr_val = adapter->itr; + vector++; + + err = request_irq(adapter->msix_entries[vector].vector, + &e1000_msix_other, 0, netdev->name, netdev); + if (err) + goto out; + + e1000_configure_msix(adapter); + return 0; +out: + return err; +} + /** * e1000_request_irq - initialize interrupts * @@ -1245,29 +1512,33 @@ static irqreturn_t e1000_intr(int irq, void *data) static int e1000_request_irq(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - int irq_flags = IRQF_SHARED; int err; - if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) { - err = pci_enable_msi(adapter->pdev); - if (!err) { - adapter->flags |= FLAG_MSI_ENABLED; - irq_flags = 0; - } + if (adapter->msix_entries) { + err = e1000_request_msix(adapter); + if (!err) + return err; + /* fall back to MSI */ + e1000e_reset_interrupt_capability(adapter); + adapter->int_mode = E1000E_INT_MODE_MSI; + e1000e_set_interrupt_capability(adapter); } + if (adapter->flags & FLAG_MSI_ENABLED) { + err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0, + netdev->name, netdev); + if (!err) + return err; - err = request_irq(adapter->pdev->irq, - ((adapter->flags & FLAG_MSI_ENABLED) ? - &e1000_intr_msi : &e1000_intr), - irq_flags, netdev->name, netdev); - if (err) { - if (adapter->flags & FLAG_MSI_ENABLED) { - pci_disable_msi(adapter->pdev); - adapter->flags &= ~FLAG_MSI_ENABLED; - } - e_err("Unable to allocate interrupt, Error: %d\n", err); + /* fall back to legacy interrupt */ + e1000e_reset_interrupt_capability(adapter); + adapter->int_mode = E1000E_INT_MODE_LEGACY; } + err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED, + netdev->name, netdev); + if (err) + e_err("Unable to allocate interrupt, Error: %d\n", err); + return err; } @@ -1275,11 +1546,21 @@ static void e1000_free_irq(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - free_irq(adapter->pdev->irq, netdev); - if (adapter->flags & FLAG_MSI_ENABLED) { - pci_disable_msi(adapter->pdev); - adapter->flags &= ~FLAG_MSI_ENABLED; + if (adapter->msix_entries) { + int vector = 0; + + free_irq(adapter->msix_entries[vector].vector, netdev); + vector++; + + free_irq(adapter->msix_entries[vector].vector, netdev); + vector++; + + /* Other Causes interrupt vector */ + free_irq(adapter->msix_entries[vector].vector, netdev); + return; } + + free_irq(adapter->pdev->irq, netdev); } /** @@ -1290,6 +1571,8 @@ static void e1000_irq_disable(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; ew32(IMC, ~0); + if (adapter->msix_entries) + ew32(EIAC_82574, 0); e1e_flush(); synchronize_irq(adapter->pdev->irq); } @@ -1301,7 +1584,12 @@ static void e1000_irq_enable(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; - ew32(IMS, IMS_ENABLE_MASK); + if (adapter->msix_entries) { + ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); + ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC); + } else { + ew32(IMS, IMS_ENABLE_MASK); + } e1e_flush(); } @@ -1551,9 +1839,8 @@ void e1000e_free_rx_resources(struct e1000_adapter *adapter) * traffic pattern. Constants in this function were computed * based on theoretical maximum wire speed and thresholds were set based * on testing data as well as attempting to minimize response time - * while increasing bulk throughput. - * this functionality is controlled by the InterruptThrottleRate module - * parameter (see e1000_param.c) + * while increasing bulk throughput. This functionality is controlled + * by the InterruptThrottleRate module parameter. **/ static unsigned int e1000_update_itr(struct e1000_adapter *adapter, u16 itr_setting, int packets, @@ -1661,11 +1948,37 @@ set_itr_now: min(adapter->itr + (new_itr >> 2), new_itr) : new_itr; adapter->itr = new_itr; - ew32(ITR, 1000000000 / (new_itr * 256)); + adapter->rx_ring->itr_val = new_itr; + if (adapter->msix_entries) + adapter->rx_ring->set_itr = 1; + else + ew32(ITR, 1000000000 / (new_itr * 256)); } } /** + * e1000_alloc_queues - Allocate memory for all rings + * @adapter: board private structure to initialize + **/ +static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) +{ + adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!adapter->tx_ring) + goto err; + + adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!adapter->rx_ring) + goto err; + + return 0; +err: + e_err("Unable to allocate memory for queues\n"); + kfree(adapter->rx_ring); + kfree(adapter->tx_ring); + return -ENOMEM; +} + +/** * e1000_clean - NAPI Rx polling callback * @napi: struct associated with this polling callback * @budget: amount of packets driver is allowed to process this poll @@ -1673,12 +1986,17 @@ set_itr_now: static int e1000_clean(struct napi_struct *napi, int budget) { struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi); + struct e1000_hw *hw = &adapter->hw; struct net_device *poll_dev = adapter->netdev; int tx_cleaned = 0, work_done = 0; /* Must NOT use netdev_priv macro here. */ adapter = poll_dev->priv; + if (adapter->msix_entries && + !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val)) + goto clean_rx; + /* * e1000_clean is called per-cpu. This lock protects * tx_ring from being cleaned by multiple cpus @@ -1690,6 +2008,7 @@ static int e1000_clean(struct napi_struct *napi, int budget) spin_unlock(&adapter->tx_queue_lock); } +clean_rx: adapter->clean_rx(adapter, &work_done, budget); if (tx_cleaned) @@ -1700,7 +2019,10 @@ static int e1000_clean(struct napi_struct *napi, int budget) if (adapter->itr_setting & 3) e1000_set_itr(adapter); netif_rx_complete(poll_dev, napi); - e1000_irq_enable(adapter); + if (adapter->msix_entries) + ew32(IMS, adapter->rx_ring->ims_val); + else + e1000_irq_enable(adapter); } return work_done; @@ -2496,6 +2818,8 @@ int e1000e_up(struct e1000_adapter *adapter) clear_bit(__E1000_DOWN, &adapter->state); napi_enable(&adapter->napi); + if (adapter->msix_entries) + e1000_configure_msix(adapter); e1000_irq_enable(adapter); /* fire a link change interrupt to start the watchdog */ @@ -2579,29 +2903,18 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; - adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); - if (!adapter->tx_ring) - goto err; + e1000e_set_interrupt_capability(adapter); - adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); - if (!adapter->rx_ring) - goto err; + if (e1000_alloc_queues(adapter)) + return -ENOMEM; spin_lock_init(&adapter->tx_queue_lock); /* Explicitly disable IRQ since the NIC can be in any state. */ e1000_irq_disable(adapter); - spin_lock_init(&adapter->stats_lock); - set_bit(__E1000_DOWN, &adapter->state); return 0; - -err: - e_err("Unable to allocate memory for queues\n"); - kfree(adapter->rx_ring); - kfree(adapter->tx_ring); - return -ENOMEM; } /** @@ -2643,6 +2956,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter) /* free the real vector and request a test handler */ e1000_free_irq(adapter); + e1000e_reset_interrupt_capability(adapter); /* Assume that the test fails, if it succeeds then the test * MSI irq handler will unset this flag */ @@ -2673,6 +2987,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter) rmb(); if (adapter->flags & FLAG_MSI_TEST_FAILED) { + adapter->int_mode = E1000E_INT_MODE_LEGACY; err = -EIO; e_info("MSI interrupt test failed!\n"); } @@ -2686,7 +3001,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter) /* okay so the test worked, restore settings */ e_dbg("%s: MSI interrupt test succeeded!\n", netdev->name); msi_test_failed: - /* restore the original vector, even if it failed */ + e1000e_set_interrupt_capability(adapter); e1000_request_irq(adapter); return err; } @@ -2796,7 +3111,7 @@ static int e1000_open(struct net_device *netdev) * ignore e1000e MSI messages, which means we need to test our MSI * interrupt now */ - { + if (adapter->int_mode != E1000E_INT_MODE_LEGACY) { err = e1000_test_msi(adapter); if (err) { e_err("Interrupt allocation failed\n"); @@ -2912,6 +3227,21 @@ static int e1000_set_mac(struct net_device *netdev, void *p) return 0; } +/** + * e1000e_update_phy_task - work thread to update phy + * @work: pointer to our work struct + * + * this worker thread exists because we must acquire a + * semaphore to read the phy, which we could msleep while + * waiting for it, and we can't msleep in a timer. + **/ +static void e1000e_update_phy_task(struct work_struct *work) +{ + struct e1000_adapter *adapter = container_of(work, + struct e1000_adapter, update_phy_task); + e1000_get_phy_info(&adapter->hw); +} + /* * Need to wait a few seconds after link up to get diagnostic information from * the phy @@ -2919,7 +3249,7 @@ static int e1000_set_mac(struct net_device *netdev, void *p) static void e1000_update_phy_info(unsigned long data) { struct e1000_adapter *adapter = (struct e1000_adapter *) data; - e1000_get_phy_info(&adapter->hw); + schedule_work(&adapter->update_phy_task); } /** @@ -2930,10 +3260,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; - unsigned long irq_flags; - u16 phy_tmp; - -#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF /* * Prevent stats update while adapter is being reset, or if the pci @@ -2944,14 +3270,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter) if (pci_channel_offline(pdev)) return; - spin_lock_irqsave(&adapter->stats_lock, irq_flags); - - /* - * these counters are modified from e1000_adjust_tbi_stats, - * called from the interrupt context, so they must only - * be written while holding adapter->stats_lock - */ - adapter->stats.crcerrs += er32(CRCERRS); adapter->stats.gprc += er32(GPRC); adapter->stats.gorc += er32(GORCL); @@ -2988,7 +3306,8 @@ void e1000e_update_stats(struct e1000_adapter *adapter) adapter->stats.algnerrc += er32(ALGNERRC); adapter->stats.rxerrc += er32(RXERRC); - adapter->stats.tncrs += er32(TNCRS); + if (hw->mac.type != e1000_82574) + adapter->stats.tncrs += er32(TNCRS); adapter->stats.cexterr += er32(CEXTERR); adapter->stats.tsctc += er32(TSCTC); adapter->stats.tsctfc += er32(TSCTFC); @@ -3022,21 +3341,10 @@ void e1000e_update_stats(struct e1000_adapter *adapter) /* Tx Dropped needs to be maintained elsewhere */ - /* Phy Stats */ - if (hw->phy.media_type == e1000_media_type_copper) { - if ((adapter->link_speed == SPEED_1000) && - (!e1e_rphy(hw, PHY_1000T_STATUS, &phy_tmp))) { - phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; - adapter->phy_stats.idle_errors += phy_tmp; - } - } - /* Management Stats */ adapter->stats.mgptc += er32(MGTPTC); adapter->stats.mgprc += er32(MGTPRC); adapter->stats.mgpdc += er32(MGTPDC); - - spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); } /** @@ -3048,10 +3356,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct e1000_phy_regs *phy = &adapter->phy_regs; int ret_val; - unsigned long irq_flags; - - - spin_lock_irqsave(&adapter->stats_lock, irq_flags); if ((er32(STATUS) & E1000_STATUS_LU) && (adapter->hw.phy.media_type == e1000_media_type_copper)) { @@ -3082,8 +3386,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter) phy->stat1000 = 0; phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF); } - - spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); } static void e1000_print_link_info(struct e1000_adapter *adapter) @@ -3201,6 +3503,27 @@ static void e1000_watchdog_task(struct work_struct *work) &adapter->link_duplex); e1000_print_link_info(adapter); /* + * On supported PHYs, check for duplex mismatch only + * if link has autonegotiated at 10/100 half + */ + if ((hw->phy.type == e1000_phy_igp_3 || + hw->phy.type == e1000_phy_bm) && + (hw->mac.autoneg == true) && + (adapter->link_speed == SPEED_10 || + adapter->link_speed == SPEED_100) && + (adapter->link_duplex == HALF_DUPLEX)) { + u16 autoneg_exp; + + e1e_rphy(hw, PHY_AUTONEG_EXP, &autoneg_exp); + + if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS)) + e_info("Autonegotiated half duplex but" + " link partner cannot autoneg. " + " Try forcing full duplex if " + "link gets many collisions.\n"); + } + + /* * tweak tx_queue_len according to speed/duplex * and adjust the timeout factor */ @@ -3315,7 +3638,10 @@ link_up: } /* Cause software interrupt to ensure Rx ring is cleaned */ - ew32(ICS, E1000_ICS_RXDMT0); + if (adapter->msix_entries) + ew32(ICS, adapter->rx_ring->ims_val); + else + ew32(ICS, E1000_ICS_RXDMT0); /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = 1; @@ -3423,34 +3749,50 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) struct e1000_buffer *buffer_info; unsigned int i; u8 css; + u32 cmd_len = E1000_TXD_CMD_DEXT; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - css = skb_transport_offset(skb); - - i = tx_ring->next_to_use; - buffer_info = &tx_ring->buffer_info[i]; - context_desc = E1000_CONTEXT_DESC(*tx_ring, i); - - context_desc->lower_setup.ip_config = 0; - context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = - css + skb->csum_offset; - context_desc->upper_setup.tcp_fields.tucse = 0; - context_desc->tcp_seg_setup.data = 0; - context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); + if (skb->ip_summed != CHECKSUM_PARTIAL) + return 0; - buffer_info->time_stamp = jiffies; - buffer_info->next_to_watch = i; + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + cmd_len |= E1000_TXD_CMD_TCP; + break; + case __constant_htons(ETH_P_IPV6): + /* XXX not handling all IPV6 headers */ + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + cmd_len |= E1000_TXD_CMD_TCP; + break; + default: + if (unlikely(net_ratelimit())) + e_warn("checksum_partial proto=%x!\n", skb->protocol); + break; + } - i++; - if (i == tx_ring->count) - i = 0; - tx_ring->next_to_use = i; + css = skb_transport_offset(skb); - return 1; - } + i = tx_ring->next_to_use; + buffer_info = &tx_ring->buffer_info[i]; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + + context_desc->lower_setup.ip_config = 0; + context_desc->upper_setup.tcp_fields.tucss = css; + context_desc->upper_setup.tcp_fields.tucso = + css + skb->csum_offset; + context_desc->upper_setup.tcp_fields.tucse = 0; + context_desc->tcp_seg_setup.data = 0; + context_desc->cmd_and_length = cpu_to_le32(cmd_len); + + buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; - return 0; + return 1; } #define E1000_MAX_PER_TXD 8192 @@ -4032,6 +4374,7 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) e1000e_down(adapter); e1000_free_irq(adapter); } + e1000e_reset_interrupt_capability(adapter); retval = pci_save_state(pdev); if (retval) @@ -4158,6 +4501,7 @@ static int e1000_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); + e1000e_set_interrupt_capability(adapter); if (netif_running(netdev)) { err = e1000_request_irq(adapter); if (err) @@ -4335,13 +4679,15 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter) ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &buf); if (!(le16_to_cpu(buf) & (1 << 0))) { /* Deep Smart Power Down (DSPD) */ - e_warn("Warning: detected DSPD enabled in EEPROM\n"); + dev_warn(&adapter->pdev->dev, + "Warning: detected DSPD enabled in EEPROM\n"); } ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf); if (le16_to_cpu(buf) & (3 << 2)) { /* ASPM enable */ - e_warn("Warning: detected ASPM enabled in EEPROM\n"); + dev_warn(&adapter->pdev->dev, + "Warning: detected ASPM enabled in EEPROM\n"); } } @@ -4467,6 +4813,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->bd_number = cards_found++; + e1000e_check_options(adapter); + /* setup adapter struct */ err = e1000_sw_init(adapter); if (err) @@ -4482,6 +4830,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev, if (err) goto err_hw_init; + if ((adapter->flags & FLAG_IS_ICH) && + (adapter->flags & FLAG_READ_ONLY_NVM)) + e1000e_write_protect_nvm_ich8lan(&adapter->hw); + hw->mac.ops.get_bus_info(&adapter->hw); adapter->hw.phy.autoneg_wait_to_complete = 0; @@ -4572,8 +4924,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, INIT_WORK(&adapter->reset_task, e1000_reset_task); INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); - - e1000e_check_options(adapter); + INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround); + INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task); /* Initialize link parameters. User can change them with ethtool */ adapter->hw.mac.autoneg = 1; @@ -4704,6 +5056,7 @@ static void __devexit e1000_remove(struct pci_dev *pdev) if (!e1000_check_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); + e1000e_reset_interrupt_capability(adapter); kfree(adapter->tx_ring); kfree(adapter->rx_ring); @@ -4745,6 +5098,8 @@ static struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT), board_80003es2lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT), @@ -4767,6 +5122,7 @@ static struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_BM), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan }, @@ -4775,6 +5131,9 @@ static struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan }, + { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c index ed912e023a7..77a3d7207a5 100644 --- a/drivers/net/e1000e/param.c +++ b/drivers/net/e1000e/param.c @@ -114,6 +114,15 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); #define DEFAULT_ITR 3 #define MAX_ITR 100000 #define MIN_ITR 100 +/* IntMode (Interrupt Mode) + * + * Valid Range: 0 - 2 + * + * Default Value: 2 (MSI-X) + */ +E1000_PARAM(IntMode, "Interrupt Mode"); +#define MAX_INTMODE 2 +#define MIN_INTMODE 0 /* * Enable Smart Power Down of the PHY @@ -133,6 +142,15 @@ E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); */ E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); +/* + * Write Protect NVM + * + * Valid Range: 0, 1 + * + * Default Value: 1 (enabled) + */ +E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]"); + struct e1000_option { enum { enable_option, range_option, list_option } type; const char *name; @@ -352,6 +370,24 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) adapter->itr = 20000; } } + { /* Interrupt Mode */ + struct e1000_option opt = { + .type = range_option, + .name = "Interrupt Mode", + .err = "defaulting to 2 (MSI-X)", + .def = E1000E_INT_MODE_MSIX, + .arg = { .r = { .min = MIN_INTMODE, + .max = MAX_INTMODE } } + }; + + if (num_IntMode > bd) { + unsigned int int_mode = IntMode[bd]; + e1000_validate_option(&int_mode, &opt, adapter); + adapter->int_mode = int_mode; + } else { + adapter->int_mode = opt.def; + } + } { /* Smart Power Down */ const struct e1000_option opt = { .type = enable_option, @@ -388,4 +424,25 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) opt.def); } } + { /* Write-protect NVM */ + const struct e1000_option opt = { + .type = enable_option, + .name = "Write-protect NVM", + .err = "defaulting to Enabled", + .def = OPTION_ENABLED + }; + + if (adapter->flags & FLAG_IS_ICH) { + if (num_WriteProtectNVM > bd) { + unsigned int write_protect_nvm = WriteProtectNVM[bd]; + e1000_validate_option(&write_protect_nvm, &opt, + adapter); + if (write_protect_nvm) + adapter->flags |= FLAG_READ_ONLY_NVM; + } else { + if (opt.def) + adapter->flags |= FLAG_READ_ONLY_NVM; + } + } + } } diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index b133dcf0e95..6cd333ae61d 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -476,7 +476,9 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) if (ret_val) return ret_val; - if ((phy->type == e1000_phy_m88) && (phy->revision < 4)) { + if ((phy->type == e1000_phy_m88) && + (phy->revision < E1000_REVISION_4) && + (phy->id != BME1000_E_PHY_ID_R2)) { /* * Force TX_CLK in the Extended PHY Specific Control Register * to 25MHz clock. @@ -504,6 +506,18 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) return ret_val; } + if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) { + /* Set PHY page 0, register 29 to 0x0003 */ + ret_val = e1e_wphy(hw, 29, 0x0003); + if (ret_val) + return ret_val; + + /* Set PHY page 0, register 30 to 0x0000 */ + ret_val = e1e_wphy(hw, 30, 0x0000); + if (ret_val) + return ret_val; + } + /* Commit the changes. */ ret_val = e1000e_commit_phy(hw); if (ret_val) @@ -1720,6 +1734,91 @@ s32 e1000e_get_cfg_done(struct e1000_hw *hw) return 0; } +/** + * e1000e_phy_init_script_igp3 - Inits the IGP3 PHY + * @hw: pointer to the HW structure + * + * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. + **/ +s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw) +{ + hw_dbg(hw, "Running IGP 3 PHY init script\n"); + + /* PHY init IGP 3 */ + /* Enable rise/fall, 10-mode work in class-A */ + e1e_wphy(hw, 0x2F5B, 0x9018); + /* Remove all caps from Replica path filter */ + e1e_wphy(hw, 0x2F52, 0x0000); + /* Bias trimming for ADC, AFE and Driver (Default) */ + e1e_wphy(hw, 0x2FB1, 0x8B24); + /* Increase Hybrid poly bias */ + e1e_wphy(hw, 0x2FB2, 0xF8F0); + /* Add 4% to Tx amplitude in Gig mode */ + e1e_wphy(hw, 0x2010, 0x10B0); + /* Disable trimming (TTT) */ + e1e_wphy(hw, 0x2011, 0x0000); + /* Poly DC correction to 94.6% + 2% for all channels */ + e1e_wphy(hw, 0x20DD, 0x249A); + /* ABS DC correction to 95.9% */ + e1e_wphy(hw, 0x20DE, 0x00D3); + /* BG temp curve trim */ + e1e_wphy(hw, 0x28B4, 0x04CE); + /* Increasing ADC OPAMP stage 1 currents to max */ + e1e_wphy(hw, 0x2F70, 0x29E4); + /* Force 1000 ( required for enabling PHY regs configuration) */ + e1e_wphy(hw, 0x0000, 0x0140); + /* Set upd_freq to 6 */ + e1e_wphy(hw, 0x1F30, 0x1606); + /* Disable NPDFE */ + e1e_wphy(hw, 0x1F31, 0xB814); + /* Disable adaptive fixed FFE (Default) */ + e1e_wphy(hw, 0x1F35, 0x002A); + /* Enable FFE hysteresis */ + e1e_wphy(hw, 0x1F3E, 0x0067); + /* Fixed FFE for short cable lengths */ + e1e_wphy(hw, 0x1F54, 0x0065); + /* Fixed FFE for medium cable lengths */ + e1e_wphy(hw, 0x1F55, 0x002A); + /* Fixed FFE for long cable lengths */ + e1e_wphy(hw, 0x1F56, 0x002A); + /* Enable Adaptive Clip Threshold */ + e1e_wphy(hw, 0x1F72, 0x3FB0); + /* AHT reset limit to 1 */ + e1e_wphy(hw, 0x1F76, 0xC0FF); + /* Set AHT master delay to 127 msec */ + e1e_wphy(hw, 0x1F77, 0x1DEC); + /* Set scan bits for AHT */ + e1e_wphy(hw, 0x1F78, 0xF9EF); + /* Set AHT Preset bits */ + e1e_wphy(hw, 0x1F79, 0x0210); + /* Change integ_factor of channel A to 3 */ + e1e_wphy(hw, 0x1895, 0x0003); + /* Change prop_factor of channels BCD to 8 */ + e1e_wphy(hw, 0x1796, 0x0008); + /* Change cg_icount + enable integbp for channels BCD */ + e1e_wphy(hw, 0x1798, 0xD008); + /* + * Change cg_icount + enable integbp + change prop_factor_master + * to 8 for channel A + */ + e1e_wphy(hw, 0x1898, 0xD918); + /* Disable AHT in Slave mode on channel A */ + e1e_wphy(hw, 0x187A, 0x0800); + /* + * Enable LPLU and disable AN to 1000 in non-D0a states, + * Enable SPD+B2B + */ + e1e_wphy(hw, 0x0019, 0x008D); + /* Enable restart AN on an1000_dis change */ + e1e_wphy(hw, 0x001B, 0x2080); + /* Enable wh_fifo read clock in 10/100 modes */ + e1e_wphy(hw, 0x0014, 0x0045); + /* Restart AN, Speed selection is 1000 */ + e1e_wphy(hw, 0x0000, 0x1340); + + return 0; +} + /* Internal function pointers */ /** @@ -1969,6 +2068,99 @@ out: } /** + * e1000e_read_phy_reg_bm2 - Read BM PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + u16 page = (u16)(offset >> IGP_PAGE_SHIFT); + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, + true); + return ret_val; + } + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + hw->phy.addr = 1; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, + page); + + if (ret_val) { + hw->phy.ops.release_phy(hw); + return ret_val; + } + } + + ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, + data); + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_write_phy_reg_bm2 - Write BM PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + u16 page = (u16)(offset >> IGP_PAGE_SHIFT); + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, + false); + return ret_val; + } + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + hw->phy.addr = 1; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, + page); + + if (ret_val) { + hw->phy.ops.release_phy(hw); + return ret_val; + } + } + + ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** * e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register * @hw: pointer to the HW structure * @offset: register offset to be read or written diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 795c594a4b7..b751c1b96cf 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -8,7 +8,7 @@ * * Many modifications, and currently maintained, by * Philip Blundell <philb@gnu.org> - * Added the Compaq LTE Alan Cox <alan@redhat.com> + * Added the Compaq LTE Alan Cox <alan@lxorguk.ukuu.org.uk> * Added MCA support Adam Fritzler * * Note - this driver is experimental still - it has problems on faster diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index e01926b7b5b..5524271eedc 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,13 +40,13 @@ #include <asm/io.h> #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0092" +#define DRV_VERSION "EHEA_0093" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 #define DLPAR_MEM_ADD 2 #define DLPAR_MEM_REM 4 -#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD) +#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD | DLPAR_MEM_REM) #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index 156eb6320b4..2a33a613d9e 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c @@ -535,7 +535,7 @@ u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr) cb_logaddr, /* R5 */ 0, 0, 0, 0, 0); /* R6-R10 */ #ifdef DEBUG - ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea"); + ehea_dump(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea"); #endif return hret; } diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 140f05baafd..db8a9257e68 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -595,7 +595,8 @@ static int ehea_create_busmap_callback(unsigned long pfn, end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE); mr_len = *(unsigned long *)arg; - ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL); + if (!ehea_bmap) + ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL); if (!ehea_bmap) return -ENOMEM; diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index aa0bf6e1c69..e1b441effbb 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -110,7 +110,7 @@ spi_read_buf(struct enc28j60_net *priv, int len, u8 *data) } if (ret && netif_msg_drv(priv)) printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n", - __FUNCTION__, ret); + __func__, ret); return ret; } @@ -131,7 +131,7 @@ static int spi_write_buf(struct enc28j60_net *priv, int len, ret = spi_write(priv->spi, priv->spi_transfer_buf, len + 1); if (ret && netif_msg_drv(priv)) printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n", - __FUNCTION__, ret); + __func__, ret); } return ret; } @@ -156,7 +156,7 @@ static u8 spi_read_op(struct enc28j60_net *priv, u8 op, ret = spi_write_then_read(priv->spi, tx_buf, 1, rx_buf, slen); if (ret) printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n", - __FUNCTION__, ret); + __func__, ret); else val = rx_buf[slen - 1]; @@ -176,14 +176,14 @@ static int spi_write_op(struct enc28j60_net *priv, u8 op, ret = spi_write(priv->spi, priv->spi_transfer_buf, 2); if (ret && netif_msg_drv(priv)) printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n", - __FUNCTION__, ret); + __func__, ret); return ret; } static void enc28j60_soft_reset(struct enc28j60_net *priv) { if (netif_msg_hw(priv)) - printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__); spi_write_op(priv, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); /* Errata workaround #1, CLKRDY check is unreliable, @@ -357,7 +357,7 @@ static void enc28j60_mem_read(struct enc28j60_net *priv, reg = nolock_regw_read(priv, ERDPTL); if (reg != addr) printk(KERN_DEBUG DRV_NAME ": %s() error writing ERDPT " - "(0x%04x - 0x%04x)\n", __FUNCTION__, reg, addr); + "(0x%04x - 0x%04x)\n", __func__, reg, addr); } #endif spi_read_buf(priv, len, data); @@ -380,7 +380,7 @@ enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data) if (reg != TXSTART_INIT) printk(KERN_DEBUG DRV_NAME ": %s() ERWPT:0x%04x != 0x%04x\n", - __FUNCTION__, reg, TXSTART_INIT); + __func__, reg, TXSTART_INIT); } #endif /* Set the TXND pointer to correspond to the packet size given */ @@ -390,13 +390,13 @@ enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data) if (netif_msg_hw(priv)) printk(KERN_DEBUG DRV_NAME ": %s() after control byte ERWPT:0x%04x\n", - __FUNCTION__, nolock_regw_read(priv, EWRPTL)); + __func__, nolock_regw_read(priv, EWRPTL)); /* copy the packet into the transmit buffer */ spi_write_buf(priv, len, data); if (netif_msg_hw(priv)) printk(KERN_DEBUG DRV_NAME ": %s() after write packet ERWPT:0x%04x, len=%d\n", - __FUNCTION__, nolock_regw_read(priv, EWRPTL), len); + __func__, nolock_regw_read(priv, EWRPTL), len); mutex_unlock(&priv->lock); } @@ -495,7 +495,7 @@ static int enc28j60_set_hw_macaddr(struct net_device *ndev) if (netif_msg_drv(priv)) printk(KERN_DEBUG DRV_NAME ": %s() Hardware must be disabled to set " - "Mac address\n", __FUNCTION__); + "Mac address\n", __func__); ret = -EBUSY; } mutex_unlock(&priv->lock); @@ -575,7 +575,7 @@ static void nolock_rxfifo_init(struct enc28j60_net *priv, u16 start, u16 end) if (start > 0x1FFF || end > 0x1FFF || start > end) { if (netif_msg_drv(priv)) printk(KERN_ERR DRV_NAME ": %s(%d, %d) RXFIFO " - "bad parameters!\n", __FUNCTION__, start, end); + "bad parameters!\n", __func__, start, end); return; } /* set receive buffer start + end */ @@ -591,7 +591,7 @@ static void nolock_txfifo_init(struct enc28j60_net *priv, u16 start, u16 end) if (start > 0x1FFF || end > 0x1FFF || start > end) { if (netif_msg_drv(priv)) printk(KERN_ERR DRV_NAME ": %s(%d, %d) TXFIFO " - "bad parameters!\n", __FUNCTION__, start, end); + "bad parameters!\n", __func__, start, end); return; } /* set transmit buffer start + end */ @@ -630,7 +630,7 @@ static int enc28j60_hw_init(struct enc28j60_net *priv) u8 reg; if (netif_msg_drv(priv)) - printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __FUNCTION__, + printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __func__, priv->full_duplex ? "FullDuplex" : "HalfDuplex"); mutex_lock(&priv->lock); @@ -661,7 +661,7 @@ static int enc28j60_hw_init(struct enc28j60_net *priv) if (reg == 0x00 || reg == 0xff) { if (netif_msg_drv(priv)) printk(KERN_DEBUG DRV_NAME ": %s() Invalid RevId %d\n", - __FUNCTION__, reg); + __func__, reg); return 0; } @@ -724,7 +724,7 @@ static void enc28j60_hw_enable(struct enc28j60_net *priv) /* enable interrupts */ if (netif_msg_hw(priv)) printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n", - __FUNCTION__); + __func__); enc28j60_phy_write(priv, PHIE, PHIE_PGEIE | PHIE_PLNKIE); @@ -888,7 +888,7 @@ static void enc28j60_hw_rx(struct net_device *ndev) if (netif_msg_rx_err(priv)) dev_err(&ndev->dev, "%s() Invalid packet address!! 0x%04x\n", - __FUNCTION__, priv->next_pk_ptr); + __func__, priv->next_pk_ptr); /* packet address corrupted: reset RX logic */ mutex_lock(&priv->lock); nolock_reg_bfclr(priv, ECON1, ECON1_RXEN); @@ -917,7 +917,7 @@ static void enc28j60_hw_rx(struct net_device *ndev) rxstat |= rsv[4]; if (netif_msg_rx_status(priv)) - enc28j60_dump_rsv(priv, __FUNCTION__, next_packet, len, rxstat); + enc28j60_dump_rsv(priv, __func__, next_packet, len, rxstat); if (!RSV_GETBIT(rxstat, RSV_RXOK)) { if (netif_msg_rx_err(priv)) @@ -941,7 +941,7 @@ static void enc28j60_hw_rx(struct net_device *ndev) enc28j60_mem_read(priv, priv->next_pk_ptr + sizeof(rsv), len, skb_put(skb, len)); if (netif_msg_pktdata(priv)) - dump_packet(__FUNCTION__, skb->len, skb->data); + dump_packet(__func__, skb->len, skb->data); skb->protocol = eth_type_trans(skb, ndev); /* update statistics */ ndev->stats.rx_packets++; @@ -958,7 +958,7 @@ static void enc28j60_hw_rx(struct net_device *ndev) erxrdpt = erxrdpt_workaround(next_packet, RXSTART_INIT, RXEND_INIT); if (netif_msg_hw(priv)) printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT:0x%04x\n", - __FUNCTION__, erxrdpt); + __func__, erxrdpt); mutex_lock(&priv->lock); nolock_regw_write(priv, ERXRDPTL, erxrdpt); @@ -968,7 +968,7 @@ static void enc28j60_hw_rx(struct net_device *ndev) reg = nolock_regw_read(priv, ERXRDPTL); if (reg != erxrdpt) printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT verify " - "error (0x%04x - 0x%04x)\n", __FUNCTION__, + "error (0x%04x - 0x%04x)\n", __func__, reg, erxrdpt); } #endif @@ -1006,7 +1006,7 @@ static int enc28j60_get_free_rxfifo(struct enc28j60_net *priv) mutex_unlock(&priv->lock); if (netif_msg_rx_status(priv)) printk(KERN_DEBUG DRV_NAME ": %s() free_space = %d\n", - __FUNCTION__, free_space); + __func__, free_space); return free_space; } @@ -1022,7 +1022,7 @@ static void enc28j60_check_link_status(struct net_device *ndev) reg = enc28j60_phy_read(priv, PHSTAT2); if (netif_msg_hw(priv)) printk(KERN_DEBUG DRV_NAME ": %s() PHSTAT1: %04x, " - "PHSTAT2: %04x\n", __FUNCTION__, + "PHSTAT2: %04x\n", __func__, enc28j60_phy_read(priv, PHSTAT1), reg); duplex = reg & PHSTAT2_DPXSTAT; @@ -1095,7 +1095,7 @@ static void enc28j60_irq_work_handler(struct work_struct *work) int intflags, loop; if (netif_msg_intr(priv)) - printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__); /* disable further interrupts */ locked_reg_bfclr(priv, EIE, EIE_INTIE); @@ -1198,7 +1198,7 @@ static void enc28j60_irq_work_handler(struct work_struct *work) /* re-enable interrupts */ locked_reg_bfset(priv, EIE, EIE_INTIE); if (netif_msg_intr(priv)) - printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __FUNCTION__); + printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __func__); } /* @@ -1213,7 +1213,7 @@ static void enc28j60_hw_tx(struct enc28j60_net *priv) ": Tx Packet Len:%d\n", priv->tx_skb->len); if (netif_msg_pktdata(priv)) - dump_packet(__FUNCTION__, + dump_packet(__func__, priv->tx_skb->len, priv->tx_skb->data); enc28j60_packet_write(priv, priv->tx_skb->len, priv->tx_skb->data); @@ -1254,7 +1254,7 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev) struct enc28j60_net *priv = netdev_priv(dev); if (netif_msg_tx_queued(priv)) - printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__); /* If some error occurs while trying to transmit this * packet, you should return '1' from this function. @@ -1325,7 +1325,7 @@ static int enc28j60_net_open(struct net_device *dev) struct enc28j60_net *priv = netdev_priv(dev); if (netif_msg_drv(priv)) - printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__); if (!is_valid_ether_addr(dev->dev_addr)) { if (netif_msg_ifup(priv)) { @@ -1363,7 +1363,7 @@ static int enc28j60_net_close(struct net_device *dev) struct enc28j60_net *priv = netdev_priv(dev); if (netif_msg_drv(priv)) - printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__); enc28j60_hw_disable(priv); enc28j60_lowpower(priv, true); diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile new file mode 100644 index 00000000000..391c3bce5b7 --- /dev/null +++ b/drivers/net/enic/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_ENIC) := enic.o + +enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ + enic_res.o vnic_dev.o vnic_rq.o + diff --git a/drivers/net/enic/cq_desc.h b/drivers/net/enic/cq_desc.h new file mode 100644 index 00000000000..c036a8bfd04 --- /dev/null +++ b/drivers/net/enic/cq_desc.h @@ -0,0 +1,79 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _CQ_DESC_H_ +#define _CQ_DESC_H_ + +/* + * Completion queue descriptor types + */ +enum cq_desc_types { + CQ_DESC_TYPE_WQ_ENET = 0, + CQ_DESC_TYPE_DESC_COPY = 1, + CQ_DESC_TYPE_WQ_EXCH = 2, + CQ_DESC_TYPE_RQ_ENET = 3, + CQ_DESC_TYPE_RQ_FCP = 4, +}; + +/* Completion queue descriptor: 16B + * + * All completion queues have this basic layout. The + * type_specfic area is unique for each completion + * queue type. + */ +struct cq_desc { + __le16 completed_index; + __le16 q_number; + u8 type_specfic[11]; + u8 type_color; +}; + +#define CQ_DESC_TYPE_BITS 7 +#define CQ_DESC_TYPE_MASK ((1 << CQ_DESC_TYPE_BITS) - 1) +#define CQ_DESC_COLOR_MASK 1 +#define CQ_DESC_Q_NUM_BITS 10 +#define CQ_DESC_Q_NUM_MASK ((1 << CQ_DESC_Q_NUM_BITS) - 1) +#define CQ_DESC_COMP_NDX_BITS 12 +#define CQ_DESC_COMP_NDX_MASK ((1 << CQ_DESC_COMP_NDX_BITS) - 1) + +static inline void cq_desc_dec(const struct cq_desc *desc_arg, + u8 *type, u8 *color, u16 *q_number, u16 *completed_index) +{ + const struct cq_desc *desc = desc_arg; + const u8 type_color = desc->type_color; + + *color = (type_color >> CQ_DESC_TYPE_BITS) & CQ_DESC_COLOR_MASK; + + /* + * Make sure color bit is read from desc *before* other fields + * are read from desc. Hardware guarantees color bit is last + * bit (byte) written. Adding the rmb() prevents the compiler + * and/or CPU from reordering the reads which would potentially + * result in reading stale values. + */ + + rmb(); + + *type = type_color & CQ_DESC_TYPE_MASK; + *q_number = le16_to_cpu(desc->q_number) & CQ_DESC_Q_NUM_MASK; + *completed_index = le16_to_cpu(desc->completed_index) & + CQ_DESC_COMP_NDX_MASK; +} + +#endif /* _CQ_DESC_H_ */ diff --git a/drivers/net/enic/cq_enet_desc.h b/drivers/net/enic/cq_enet_desc.h new file mode 100644 index 00000000000..03dce9ed612 --- /dev/null +++ b/drivers/net/enic/cq_enet_desc.h @@ -0,0 +1,169 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _CQ_ENET_DESC_H_ +#define _CQ_ENET_DESC_H_ + +#include "cq_desc.h" + +/* Ethernet completion queue descriptor: 16B */ +struct cq_enet_wq_desc { + __le16 completed_index; + __le16 q_number; + u8 reserved[11]; + u8 type_color; +}; + +static inline void cq_enet_wq_desc_dec(struct cq_enet_wq_desc *desc, + u8 *type, u8 *color, u16 *q_number, u16 *completed_index) +{ + cq_desc_dec((struct cq_desc *)desc, type, + color, q_number, completed_index); +} + +/* Completion queue descriptor: Ethernet receive queue, 16B */ +struct cq_enet_rq_desc { + __le16 completed_index_flags; + __le16 q_number_rss_type_flags; + __le32 rss_hash; + __le16 bytes_written_flags; + __le16 vlan; + __le16 checksum_fcoe; + u8 flags; + u8 type_color; +}; + +#define CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT (0x1 << 12) +#define CQ_ENET_RQ_DESC_FLAGS_FCOE (0x1 << 13) +#define CQ_ENET_RQ_DESC_FLAGS_EOP (0x1 << 14) +#define CQ_ENET_RQ_DESC_FLAGS_SOP (0x1 << 15) + +#define CQ_ENET_RQ_DESC_RSS_TYPE_BITS 4 +#define CQ_ENET_RQ_DESC_RSS_TYPE_MASK \ + ((1 << CQ_ENET_RQ_DESC_RSS_TYPE_BITS) - 1) +#define CQ_ENET_RQ_DESC_RSS_TYPE_NONE 0 +#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv4 1 +#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv4 2 +#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6 3 +#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6 4 +#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6_EX 5 +#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6_EX 6 + +#define CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC (0x1 << 14) + +#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS 14 +#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK \ + ((1 << CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS) - 1) +#define CQ_ENET_RQ_DESC_FLAGS_TRUNCATED (0x1 << 14) +#define CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED (0x1 << 15) + +#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS 4 +#define CQ_ENET_RQ_DESC_FCOE_SOF_MASK \ + ((1 << CQ_ENET_RQ_DESC_FCOE_SOF_BITS) - 1) +#define CQ_ENET_RQ_DESC_FCOE_EOF_BITS 8 +#define CQ_ENET_RQ_DESC_FCOE_EOF_MASK \ + ((1 << CQ_ENET_RQ_DESC_FCOE_EOF_BITS) - 1) +#define CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT 8 + +#define CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK (0x1 << 0) +#define CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK (0x1 << 0) +#define CQ_ENET_RQ_DESC_FLAGS_UDP (0x1 << 1) +#define CQ_ENET_RQ_DESC_FCOE_ENC_ERROR (0x1 << 1) +#define CQ_ENET_RQ_DESC_FLAGS_TCP (0x1 << 2) +#define CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK (0x1 << 3) +#define CQ_ENET_RQ_DESC_FLAGS_IPV6 (0x1 << 4) +#define CQ_ENET_RQ_DESC_FLAGS_IPV4 (0x1 << 5) +#define CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT (0x1 << 6) +#define CQ_ENET_RQ_DESC_FLAGS_FCS_OK (0x1 << 7) + +static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc, + u8 *type, u8 *color, u16 *q_number, u16 *completed_index, + u8 *ingress_port, u8 *fcoe, u8 *eop, u8 *sop, u8 *rss_type, + u8 *csum_not_calc, u32 *rss_hash, u16 *bytes_written, u8 *packet_error, + u8 *vlan_stripped, u16 *vlan, u16 *checksum, u8 *fcoe_sof, + u8 *fcoe_fc_crc_ok, u8 *fcoe_enc_error, u8 *fcoe_eof, + u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok, + u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok) +{ + u16 completed_index_flags = le16_to_cpu(desc->completed_index_flags); + u16 q_number_rss_type_flags = + le16_to_cpu(desc->q_number_rss_type_flags); + u16 bytes_written_flags = le16_to_cpu(desc->bytes_written_flags); + + cq_desc_dec((struct cq_desc *)desc, type, + color, q_number, completed_index); + + *ingress_port = (completed_index_flags & + CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT) ? 1 : 0; + *fcoe = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_FCOE) ? + 1 : 0; + *eop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_EOP) ? + 1 : 0; + *sop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_SOP) ? + 1 : 0; + + *rss_type = (u8)((q_number_rss_type_flags >> CQ_DESC_Q_NUM_BITS) & + CQ_ENET_RQ_DESC_RSS_TYPE_MASK); + *csum_not_calc = (q_number_rss_type_flags & + CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC) ? 1 : 0; + + *rss_hash = le32_to_cpu(desc->rss_hash); + + *bytes_written = bytes_written_flags & + CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK; + *packet_error = (bytes_written_flags & + CQ_ENET_RQ_DESC_FLAGS_TRUNCATED) ? 1 : 0; + *vlan_stripped = (bytes_written_flags & + CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED) ? 1 : 0; + + *vlan = le16_to_cpu(desc->vlan); + + if (*fcoe) { + *fcoe_sof = (u8)(le16_to_cpu(desc->checksum_fcoe) & + CQ_ENET_RQ_DESC_FCOE_SOF_MASK); + *fcoe_fc_crc_ok = (desc->flags & + CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK) ? 1 : 0; + *fcoe_enc_error = (desc->flags & + CQ_ENET_RQ_DESC_FCOE_ENC_ERROR) ? 1 : 0; + *fcoe_eof = (u8)((desc->checksum_fcoe >> + CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT) & + CQ_ENET_RQ_DESC_FCOE_EOF_MASK); + *checksum = 0; + } else { + *fcoe_sof = 0; + *fcoe_fc_crc_ok = 0; + *fcoe_enc_error = 0; + *fcoe_eof = 0; + *checksum = le16_to_cpu(desc->checksum_fcoe); + } + + *tcp_udp_csum_ok = + (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK) ? 1 : 0; + *udp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_UDP) ? 1 : 0; + *tcp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP) ? 1 : 0; + *ipv4_csum_ok = + (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK) ? 1 : 0; + *ipv6 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV6) ? 1 : 0; + *ipv4 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4) ? 1 : 0; + *ipv4_fragment = + (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT) ? 1 : 0; + *fcs_ok = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_FCS_OK) ? 1 : 0; +} + +#endif /* _CQ_ENET_DESC_H_ */ diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h new file mode 100644 index 00000000000..7f677e89a78 --- /dev/null +++ b/drivers/net/enic/enic.h @@ -0,0 +1,114 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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_H_ +#define _ENIC_H_ + +#include <linux/inet_lro.h> + +#include "vnic_enet.h" +#include "vnic_dev.h" +#include "vnic_wq.h" +#include "vnic_rq.h" +#include "vnic_cq.h" +#include "vnic_intr.h" +#include "vnic_stats.h" +#include "vnic_rss.h" + +#define DRV_NAME "enic" +#define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" +#define DRV_VERSION "0.0.1-18163.472-k1" +#define DRV_COPYRIGHT "Copyright 2008 Cisco Systems, Inc" +#define PFX DRV_NAME ": " + +#define ENIC_LRO_MAX_DESC 8 +#define ENIC_LRO_MAX_AGGR 64 + +enum enic_cq_index { + ENIC_CQ_RQ, + ENIC_CQ_WQ, + ENIC_CQ_MAX, +}; + +enum enic_intx_intr_index { + ENIC_INTX_WQ_RQ, + ENIC_INTX_ERR, + ENIC_INTX_NOTIFY, + ENIC_INTX_MAX, +}; + +enum enic_msix_intr_index { + ENIC_MSIX_RQ, + ENIC_MSIX_WQ, + ENIC_MSIX_ERR, + ENIC_MSIX_NOTIFY, + ENIC_MSIX_MAX, +}; + +struct enic_msix_entry { + int requested; + char devname[IFNAMSIZ]; + irqreturn_t (*isr)(int, void *); + void *devid; +}; + +/* Per-instance private data structure */ +struct enic { + struct net_device *netdev; + struct pci_dev *pdev; + struct vnic_enet_config config; + struct vnic_dev_bar bar0; + struct vnic_dev *vdev; + struct timer_list notify_timer; + struct work_struct reset; + struct msix_entry msix_entry[ENIC_MSIX_MAX]; + struct enic_msix_entry msix[ENIC_MSIX_MAX]; + u32 msg_enable; + spinlock_t devcmd_lock; + u8 mac_addr[ETH_ALEN]; + u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN]; + unsigned int mc_count; + int csum_rx_enabled; + u32 port_mtu; + + /* work queue cache line section */ + ____cacheline_aligned struct vnic_wq wq[1]; + spinlock_t wq_lock[1]; + unsigned int wq_count; + struct vlan_group *vlan_group; + + /* receive queue cache line section */ + ____cacheline_aligned struct vnic_rq rq[1]; + unsigned int rq_count; + int (*rq_alloc_buf)(struct vnic_rq *rq); + struct napi_struct napi; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[ENIC_LRO_MAX_DESC]; + + /* interrupt resource cache line section */ + ____cacheline_aligned struct vnic_intr intr[ENIC_MSIX_MAX]; + unsigned int intr_count; + u32 __iomem *legacy_pba; /* memory-mapped */ + + /* completion queue cache line section */ + ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX]; + unsigned int cq_count; +}; + +#endif /* _ENIC_H_ */ diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c new file mode 100644 index 00000000000..180e968dc54 --- /dev/null +++ b/drivers/net/enic/enic_main.c @@ -0,0 +1,1935 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/workqueue.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/if_ether.h> +#include <linux/if_vlan.h> +#include <linux/ethtool.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/tcp.h> +#include <net/ip6_checksum.h> + +#include "cq_enet_desc.h" +#include "vnic_dev.h" +#include "vnic_intr.h" +#include "vnic_stats.h" +#include "enic_res.h" +#include "enic.h" + +#define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) + +/* Supported devices */ +static struct pci_device_id enic_id_table[] = { + { PCI_VDEVICE(CISCO, 0x0043) }, + { 0, } /* end of table */ +}; + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR("Scott Feldman <scofeldm@cisco.com>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_DEVICE_TABLE(pci, enic_id_table); + +struct enic_stat { + char name[ETH_GSTRING_LEN]; + unsigned int offset; +}; + +#define ENIC_TX_STAT(stat) \ + { .name = #stat, .offset = offsetof(struct vnic_tx_stats, stat) / 8 } +#define ENIC_RX_STAT(stat) \ + { .name = #stat, .offset = offsetof(struct vnic_rx_stats, stat) / 8 } + +static const struct enic_stat enic_tx_stats[] = { + ENIC_TX_STAT(tx_frames_ok), + ENIC_TX_STAT(tx_unicast_frames_ok), + ENIC_TX_STAT(tx_multicast_frames_ok), + ENIC_TX_STAT(tx_broadcast_frames_ok), + ENIC_TX_STAT(tx_bytes_ok), + ENIC_TX_STAT(tx_unicast_bytes_ok), + ENIC_TX_STAT(tx_multicast_bytes_ok), + ENIC_TX_STAT(tx_broadcast_bytes_ok), + ENIC_TX_STAT(tx_drops), + ENIC_TX_STAT(tx_errors), + ENIC_TX_STAT(tx_tso), +}; + +static const struct enic_stat enic_rx_stats[] = { + ENIC_RX_STAT(rx_frames_ok), + ENIC_RX_STAT(rx_frames_total), + ENIC_RX_STAT(rx_unicast_frames_ok), + ENIC_RX_STAT(rx_multicast_frames_ok), + ENIC_RX_STAT(rx_broadcast_frames_ok), + ENIC_RX_STAT(rx_bytes_ok), + ENIC_RX_STAT(rx_unicast_bytes_ok), + ENIC_RX_STAT(rx_multicast_bytes_ok), + ENIC_RX_STAT(rx_broadcast_bytes_ok), + ENIC_RX_STAT(rx_drop), + ENIC_RX_STAT(rx_no_bufs), + ENIC_RX_STAT(rx_errors), + ENIC_RX_STAT(rx_rss), + ENIC_RX_STAT(rx_crc_errors), + ENIC_RX_STAT(rx_frames_64), + ENIC_RX_STAT(rx_frames_127), + ENIC_RX_STAT(rx_frames_255), + ENIC_RX_STAT(rx_frames_511), + ENIC_RX_STAT(rx_frames_1023), + ENIC_RX_STAT(rx_frames_1518), + ENIC_RX_STAT(rx_frames_to_max), +}; + +static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); +static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); + +static int enic_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct enic *enic = netdev_priv(netdev); + + ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); + ecmd->port = PORT_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; + + if (netif_carrier_ok(netdev)) { + ecmd->speed = vnic_dev_port_speed(enic->vdev); + ecmd->duplex = DUPLEX_FULL; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = AUTONEG_DISABLE; + + return 0; +} + +static void enic_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct enic *enic = netdev_priv(netdev); + struct vnic_devcmd_fw_info *fw_info; + + spin_lock(&enic->devcmd_lock); + vnic_dev_fw_info(enic->vdev, &fw_info); + spin_unlock(&enic->devcmd_lock); + + strncpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); + strncpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); + strncpy(drvinfo->fw_version, fw_info->fw_version, + sizeof(drvinfo->fw_version)); + strncpy(drvinfo->bus_info, pci_name(enic->pdev), + sizeof(drvinfo->bus_info)); +} + +static void enic_get_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + unsigned int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < enic_n_tx_stats; i++) { + memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } + for (i = 0; i < enic_n_rx_stats; i++) { + memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } + break; + } +} + +static int enic_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return enic_n_tx_stats + enic_n_rx_stats; + default: + return -EOPNOTSUPP; + } +} + +static void enic_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct enic *enic = netdev_priv(netdev); + struct vnic_stats *vstats; + unsigned int i; + + spin_lock(&enic->devcmd_lock); + vnic_dev_stats_dump(enic->vdev, &vstats); + spin_unlock(&enic->devcmd_lock); + + for (i = 0; i < enic_n_tx_stats; i++) + *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].offset]; + for (i = 0; i < enic_n_rx_stats; i++) + *(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); + return enic->msg_enable; +} + +static void enic_set_msglevel(struct net_device *netdev, u32 value) +{ + struct enic *enic = netdev_priv(netdev); + enic->msg_enable = value; +} + +static struct ethtool_ops enic_ethtool_ops = { + .get_settings = enic_get_settings, + .get_drvinfo = enic_get_drvinfo, + .get_msglevel = enic_get_msglevel, + .set_msglevel = enic_set_msglevel, + .get_link = ethtool_op_get_link, + .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, +}; + +static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) +{ + struct enic *enic = vnic_dev_priv(wq->vdev); + + if (buf->sop) + pci_unmap_single(enic->pdev, buf->dma_addr, + buf->len, PCI_DMA_TODEVICE); + else + pci_unmap_page(enic->pdev, buf->dma_addr, + buf->len, PCI_DMA_TODEVICE); + + if (buf->os_buf) + dev_kfree_skb_any(buf->os_buf); +} + +static void enic_wq_free_buf(struct vnic_wq *wq, + struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque) +{ + enic_free_wq_buf(wq, buf); +} + +static int enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, + u8 type, u16 q_number, u16 completed_index, void *opaque) +{ + struct enic *enic = vnic_dev_priv(vdev); + + spin_lock(&enic->wq_lock[q_number]); + + vnic_wq_service(&enic->wq[q_number], cq_desc, + completed_index, enic_wq_free_buf, + opaque); + + if (netif_queue_stopped(enic->netdev) && + vnic_wq_desc_avail(&enic->wq[q_number]) >= MAX_SKB_FRAGS + 1) + netif_wake_queue(enic->netdev); + + spin_unlock(&enic->wq_lock[q_number]); + + return 0; +} + +static void enic_log_q_error(struct enic *enic) +{ + unsigned int i; + u32 error_status; + + for (i = 0; i < enic->wq_count; i++) { + error_status = vnic_wq_error_status(&enic->wq[i]); + if (error_status) + printk(KERN_ERR PFX "%s: WQ[%d] error_status %d\n", + enic->netdev->name, i, error_status); + } + + for (i = 0; i < enic->rq_count; i++) { + error_status = vnic_rq_error_status(&enic->rq[i]); + if (error_status) + printk(KERN_ERR PFX "%s: RQ[%d] error_status %d\n", + enic->netdev->name, i, error_status); + } +} + +static void enic_link_check(struct enic *enic) +{ + int link_status = vnic_dev_link_status(enic->vdev); + int carrier_ok = netif_carrier_ok(enic->netdev); + + if (link_status && !carrier_ok) { + printk(KERN_INFO PFX "%s: Link UP\n", enic->netdev->name); + netif_carrier_on(enic->netdev); + } else if (!link_status && carrier_ok) { + printk(KERN_INFO PFX "%s: Link DOWN\n", enic->netdev->name); + netif_carrier_off(enic->netdev); + } +} + +static void enic_mtu_check(struct enic *enic) +{ + u32 mtu = vnic_dev_mtu(enic->vdev); + + if (mtu != enic->port_mtu) { + if (mtu < enic->netdev->mtu) + printk(KERN_WARNING PFX + "%s: interface MTU (%d) set higher " + "than switch port MTU (%d)\n", + enic->netdev->name, enic->netdev->mtu, mtu); + enic->port_mtu = mtu; + } +} + +static void enic_msglvl_check(struct enic *enic) +{ + u32 msg_enable = vnic_dev_msg_lvl(enic->vdev); + + if (msg_enable != enic->msg_enable) { + printk(KERN_INFO PFX "%s: msg lvl changed from 0x%x to 0x%x\n", + enic->netdev->name, enic->msg_enable, msg_enable); + enic->msg_enable = msg_enable; + } +} + +static void enic_notify_check(struct enic *enic) +{ + enic_msglvl_check(enic); + enic_mtu_check(enic); + enic_link_check(enic); +} + +#define ENIC_TEST_INTR(pba, i) (pba & (1 << i)) + +static irqreturn_t enic_isr_legacy(int irq, void *data) +{ + struct net_device *netdev = data; + struct enic *enic = netdev_priv(netdev); + u32 pba; + + vnic_intr_mask(&enic->intr[ENIC_INTX_WQ_RQ]); + + pba = vnic_intr_legacy_pba(enic->legacy_pba); + if (!pba) { + vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]); + return IRQ_NONE; /* not our interrupt */ + } + + if (ENIC_TEST_INTR(pba, ENIC_INTX_NOTIFY)) + enic_notify_check(enic); + + if (ENIC_TEST_INTR(pba, ENIC_INTX_ERR)) { + enic_log_q_error(enic); + /* schedule recovery from WQ/RQ error */ + schedule_work(&enic->reset); + return IRQ_HANDLED; + } + + if (ENIC_TEST_INTR(pba, ENIC_INTX_WQ_RQ)) { + if (netif_rx_schedule_prep(netdev, &enic->napi)) + __netif_rx_schedule(netdev, &enic->napi); + } else { + vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]); + } + + return IRQ_HANDLED; +} + +static irqreturn_t enic_isr_msi(int irq, void *data) +{ + struct enic *enic = data; + + /* With MSI, there is no sharing of interrupts, so this is + * our interrupt and there is no need to ack it. The device + * is not providing per-vector masking, so the OS will not + * write to PCI config space to mask/unmask the interrupt. + * We're using mask_on_assertion for MSI, so the device + * automatically masks the interrupt when the interrupt is + * generated. Later, when exiting polling, the interrupt + * will be unmasked (see enic_poll). + * + * Also, the device uses the same PCIe Traffic Class (TC) + * for Memory Write data and MSI, so there are no ordering + * issues; the MSI will always arrive at the Root Complex + * _after_ corresponding Memory Writes (i.e. descriptor + * writes). + */ + + netif_rx_schedule(enic->netdev, &enic->napi); + + return IRQ_HANDLED; +} + +static irqreturn_t enic_isr_msix_rq(int irq, void *data) +{ + struct enic *enic = data; + + /* schedule NAPI polling for RQ cleanup */ + netif_rx_schedule(enic->netdev, &enic->napi); + + return IRQ_HANDLED; +} + +static irqreturn_t enic_isr_msix_wq(int irq, void *data) +{ + struct enic *enic = data; + unsigned int wq_work_to_do = -1; /* no limit */ + unsigned int wq_work_done; + + wq_work_done = vnic_cq_service(&enic->cq[ENIC_CQ_WQ], + wq_work_to_do, enic_wq_service, NULL); + + vnic_intr_return_credits(&enic->intr[ENIC_MSIX_WQ], + wq_work_done, + 1 /* unmask intr */, + 1 /* reset intr timer */); + + return IRQ_HANDLED; +} + +static irqreturn_t enic_isr_msix_err(int irq, void *data) +{ + struct enic *enic = data; + + enic_log_q_error(enic); + + /* schedule recovery from WQ/RQ error */ + schedule_work(&enic->reset); + + return IRQ_HANDLED; +} + +static irqreturn_t enic_isr_msix_notify(int irq, void *data) +{ + struct enic *enic = data; + + enic_notify_check(enic); + vnic_intr_unmask(&enic->intr[ENIC_MSIX_NOTIFY]); + + return IRQ_HANDLED; +} + +static inline void enic_queue_wq_skb_cont(struct enic *enic, + struct vnic_wq *wq, struct sk_buff *skb, + unsigned int len_left) +{ + skb_frag_t *frag; + + /* Queue additional data fragments */ + for (frag = skb_shinfo(skb)->frags; len_left; frag++) { + len_left -= frag->size; + enic_queue_wq_desc_cont(wq, skb, + pci_map_page(enic->pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE), + frag->size, + (len_left == 0)); /* EOP? */ + } +} + +static inline void enic_queue_wq_skb_vlan(struct enic *enic, + struct vnic_wq *wq, struct sk_buff *skb, + int vlan_tag_insert, unsigned int vlan_tag) +{ + unsigned int head_len = skb_headlen(skb); + unsigned int len_left = skb->len - head_len; + int eop = (len_left == 0); + + /* Queue the main skb fragment */ + enic_queue_wq_desc(wq, skb, + pci_map_single(enic->pdev, skb->data, + head_len, PCI_DMA_TODEVICE), + head_len, + vlan_tag_insert, vlan_tag, + eop); + + if (!eop) + enic_queue_wq_skb_cont(enic, wq, skb, len_left); +} + +static inline void enic_queue_wq_skb_csum_l4(struct enic *enic, + struct vnic_wq *wq, struct sk_buff *skb, + int vlan_tag_insert, unsigned int vlan_tag) +{ + unsigned int head_len = skb_headlen(skb); + unsigned int len_left = skb->len - head_len; + unsigned int hdr_len = skb_transport_offset(skb); + unsigned int csum_offset = hdr_len + skb->csum_offset; + int eop = (len_left == 0); + + /* Queue the main skb fragment */ + enic_queue_wq_desc_csum_l4(wq, skb, + pci_map_single(enic->pdev, skb->data, + head_len, PCI_DMA_TODEVICE), + head_len, + csum_offset, + hdr_len, + vlan_tag_insert, vlan_tag, + eop); + + if (!eop) + enic_queue_wq_skb_cont(enic, wq, skb, len_left); +} + +static inline void enic_queue_wq_skb_tso(struct enic *enic, + struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss, + int vlan_tag_insert, unsigned int vlan_tag) +{ + unsigned int head_len = skb_headlen(skb); + unsigned int len_left = skb->len - head_len; + unsigned int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + int eop = (len_left == 0); + + /* Preload TCP csum field with IP pseudo hdr calculated + * with IP length set to zero. HW will later add in length + * to each TCP segment resulting from the TSO. + */ + + if (skb->protocol == __constant_htons(ETH_P_IP)) { + ip_hdr(skb)->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); + } else if (skb->protocol == __constant_htons(ETH_P_IPV6)) { + tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); + } + + /* Queue the main skb fragment */ + enic_queue_wq_desc_tso(wq, skb, + pci_map_single(enic->pdev, skb->data, + head_len, PCI_DMA_TODEVICE), + head_len, + mss, hdr_len, + vlan_tag_insert, vlan_tag, + eop); + + if (!eop) + enic_queue_wq_skb_cont(enic, wq, skb, len_left); +} + +static inline void enic_queue_wq_skb(struct enic *enic, + struct vnic_wq *wq, struct sk_buff *skb) +{ + unsigned int mss = skb_shinfo(skb)->gso_size; + unsigned int vlan_tag = 0; + int vlan_tag_insert = 0; + + if (enic->vlan_group && vlan_tx_tag_present(skb)) { + /* VLAN tag from trunking driver */ + vlan_tag_insert = 1; + vlan_tag = vlan_tx_tag_get(skb); + } + + if (mss) + enic_queue_wq_skb_tso(enic, wq, skb, mss, + vlan_tag_insert, vlan_tag); + else if (skb->ip_summed == CHECKSUM_PARTIAL) + enic_queue_wq_skb_csum_l4(enic, wq, skb, + vlan_tag_insert, vlan_tag); + else + enic_queue_wq_skb_vlan(enic, wq, skb, + vlan_tag_insert, vlan_tag); +} + +/* netif_tx_lock held, process context with BHs disabled */ +static int enic_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct enic *enic = netdev_priv(netdev); + struct vnic_wq *wq = &enic->wq[0]; + unsigned long flags; + + if (skb->len <= 0) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + /* Non-TSO sends must fit within ENIC_NON_TSO_MAX_DESC descs, + * which is very likely. In the off chance it's going to take + * more than * ENIC_NON_TSO_MAX_DESC, linearize the skb. + */ + + if (skb_shinfo(skb)->gso_size == 0 && + skb_shinfo(skb)->nr_frags + 1 > ENIC_NON_TSO_MAX_DESC && + skb_linearize(skb)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + spin_lock_irqsave(&enic->wq_lock[0], flags); + + if (vnic_wq_desc_avail(wq) < skb_shinfo(skb)->nr_frags + 1) { + netif_stop_queue(netdev); + /* This is a hard error, log it */ + printk(KERN_ERR PFX "%s: BUG! Tx ring full when " + "queue awake!\n", netdev->name); + spin_unlock_irqrestore(&enic->wq_lock[0], flags); + return NETDEV_TX_BUSY; + } + + enic_queue_wq_skb(enic, wq, skb); + + if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + 1) + netif_stop_queue(netdev); + + netdev->trans_start = jiffies; + + spin_unlock_irqrestore(&enic->wq_lock[0], flags); + + return NETDEV_TX_OK; +} + +/* dev_base_lock rwlock held, nominally process context */ +static struct net_device_stats *enic_get_stats(struct net_device *netdev) +{ + struct enic *enic = netdev_priv(netdev); + struct net_device_stats *net_stats = &netdev->stats; + struct vnic_stats *stats; + + spin_lock(&enic->devcmd_lock); + vnic_dev_stats_dump(enic->vdev, &stats); + spin_unlock(&enic->devcmd_lock); + + net_stats->tx_packets = stats->tx.tx_frames_ok; + net_stats->tx_bytes = stats->tx.tx_bytes_ok; + net_stats->tx_errors = stats->tx.tx_errors; + net_stats->tx_dropped = stats->tx.tx_drops; + + net_stats->rx_packets = stats->rx.rx_frames_ok; + net_stats->rx_bytes = stats->rx.rx_bytes_ok; + net_stats->rx_errors = stats->rx.rx_errors; + net_stats->multicast = stats->rx.rx_multicast_frames_ok; + net_stats->rx_crc_errors = stats->rx.rx_crc_errors; + net_stats->rx_dropped = stats->rx.rx_no_bufs; + + return net_stats; +} + +static void enic_reset_mcaddrs(struct enic *enic) +{ + enic->mc_count = 0; +} + +static int enic_set_mac_addr(struct net_device *netdev, char *addr) +{ + if (!is_valid_ether_addr(addr)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr, netdev->addr_len); + + return 0; +} + +/* netif_tx_lock held, BHs disabled */ +static void enic_set_multicast_list(struct net_device *netdev) +{ + struct enic *enic = netdev_priv(netdev); + struct dev_mc_list *list = netdev->mc_list; + int directed = 1; + int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0; + int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0; + int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0; + int allmulti = (netdev->flags & IFF_ALLMULTI) || + (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS); + u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN]; + unsigned int mc_count = netdev->mc_count; + unsigned int i, j; + + if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS) + mc_count = ENIC_MULTICAST_PERFECT_FILTERS; + + spin_lock(&enic->devcmd_lock); + + vnic_dev_packet_filter(enic->vdev, directed, + multicast, broadcast, promisc, allmulti); + + /* Is there an easier way? Trying to minimize to + * calls to add/del multicast addrs. We keep the + * addrs from the last call in enic->mc_addr and + * look for changes to add/del. + */ + + for (i = 0; list && i < mc_count; i++) { + memcpy(mc_addr[i], list->dmi_addr, ETH_ALEN); + list = list->next; + } + + for (i = 0; i < enic->mc_count; i++) { + for (j = 0; j < mc_count; j++) + if (compare_ether_addr(enic->mc_addr[i], + mc_addr[j]) == 0) + break; + if (j == mc_count) + enic_del_multicast_addr(enic, enic->mc_addr[i]); + } + + for (i = 0; i < mc_count; i++) { + for (j = 0; j < enic->mc_count; j++) + if (compare_ether_addr(mc_addr[i], + enic->mc_addr[j]) == 0) + break; + if (j == enic->mc_count) + enic_add_multicast_addr(enic, mc_addr[i]); + } + + /* Save the list to compare against next time + */ + + for (i = 0; i < mc_count; i++) + memcpy(enic->mc_addr[i], mc_addr[i], ETH_ALEN); + + enic->mc_count = mc_count; + + spin_unlock(&enic->devcmd_lock); +} + +/* rtnl lock is held */ +static void enic_vlan_rx_register(struct net_device *netdev, + struct vlan_group *vlan_group) +{ + struct enic *enic = netdev_priv(netdev); + enic->vlan_group = vlan_group; +} + +/* rtnl lock is held */ +static void enic_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + struct enic *enic = netdev_priv(netdev); + + spin_lock(&enic->devcmd_lock); + enic_add_vlan(enic, vid); + spin_unlock(&enic->devcmd_lock); +} + +/* rtnl lock is held */ +static void enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct enic *enic = netdev_priv(netdev); + + spin_lock(&enic->devcmd_lock); + enic_del_vlan(enic, vid); + spin_unlock(&enic->devcmd_lock); +} + +/* netif_tx_lock held, BHs disabled */ +static void enic_tx_timeout(struct net_device *netdev) +{ + struct enic *enic = netdev_priv(netdev); + schedule_work(&enic->reset); +} + +static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) +{ + struct enic *enic = vnic_dev_priv(rq->vdev); + + if (!buf->os_buf) + return; + + pci_unmap_single(enic->pdev, buf->dma_addr, + buf->len, PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(buf->os_buf); +} + +static inline struct sk_buff *enic_rq_alloc_skb(unsigned int size) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(size + NET_IP_ALIGN); + + if (skb) + skb_reserve(skb, NET_IP_ALIGN); + + return skb; +} + +static int enic_rq_alloc_buf(struct vnic_rq *rq) +{ + struct enic *enic = vnic_dev_priv(rq->vdev); + struct sk_buff *skb; + unsigned int len = enic->netdev->mtu + ETH_HLEN; + unsigned int os_buf_index = 0; + dma_addr_t dma_addr; + + skb = enic_rq_alloc_skb(len); + if (!skb) + return -ENOMEM; + + dma_addr = pci_map_single(enic->pdev, skb->data, + len, PCI_DMA_FROMDEVICE); + + enic_queue_rq_desc(rq, skb, os_buf_index, + dma_addr, len); + + return 0; +} + +static int enic_get_skb_header(struct sk_buff *skb, void **iphdr, + void **tcph, u64 *hdr_flags, void *priv) +{ + struct cq_enet_rq_desc *cq_desc = priv; + unsigned int ip_len; + struct iphdr *iph; + + u8 type, color, eop, sop, ingress_port, vlan_stripped; + u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof; + u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok; + u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc; + u8 packet_error; + u16 q_number, completed_index, bytes_written, vlan, checksum; + u32 rss_hash; + + cq_enet_rq_desc_dec(cq_desc, + &type, &color, &q_number, &completed_index, + &ingress_port, &fcoe, &eop, &sop, &rss_type, + &csum_not_calc, &rss_hash, &bytes_written, + &packet_error, &vlan_stripped, &vlan, &checksum, + &fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error, + &fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp, + &ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment, + &fcs_ok); + + if (!(ipv4 && tcp && !ipv4_fragment)) + return -1; + + skb_reset_network_header(skb); + iph = ip_hdr(skb); + + ip_len = ip_hdrlen(skb); + skb_set_transport_header(skb, ip_len); + + /* check if ip header and tcp header are complete */ + if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb)) + return -1; + + *hdr_flags = LRO_IPV4 | LRO_TCP; + *tcph = tcp_hdr(skb); + *iphdr = iph; + + return 0; +} + +static void enic_rq_indicate_buf(struct vnic_rq *rq, + struct cq_desc *cq_desc, struct vnic_rq_buf *buf, + int skipped, void *opaque) +{ + struct enic *enic = vnic_dev_priv(rq->vdev); + struct sk_buff *skb; + + u8 type, color, eop, sop, ingress_port, vlan_stripped; + u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof; + u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok; + u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc; + u8 packet_error; + u16 q_number, completed_index, bytes_written, vlan, checksum; + u32 rss_hash; + + if (skipped) + return; + + skb = buf->os_buf; + prefetch(skb->data - NET_IP_ALIGN); + pci_unmap_single(enic->pdev, buf->dma_addr, + buf->len, PCI_DMA_FROMDEVICE); + + cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc, + &type, &color, &q_number, &completed_index, + &ingress_port, &fcoe, &eop, &sop, &rss_type, + &csum_not_calc, &rss_hash, &bytes_written, + &packet_error, &vlan_stripped, &vlan, &checksum, + &fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error, + &fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp, + &ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment, + &fcs_ok); + + if (packet_error) { + + if (bytes_written > 0 && !fcs_ok) { + if (net_ratelimit()) + printk(KERN_ERR PFX + "%s: packet error: bad FCS\n", + enic->netdev->name); + } + + dev_kfree_skb_any(skb); + + return; + } + + if (eop && bytes_written > 0) { + + /* Good receive + */ + + skb_put(skb, bytes_written); + skb->protocol = eth_type_trans(skb, enic->netdev); + + if (enic->csum_rx_enabled && !csum_not_calc) { + skb->csum = htons(checksum); + skb->ip_summed = CHECKSUM_COMPLETE; + } + + skb->dev = enic->netdev; + enic->netdev->last_rx = jiffies; + + if (enic->vlan_group && vlan_stripped) { + + if (ENIC_SETTING(enic, LRO) && ipv4) + lro_vlan_hwaccel_receive_skb(&enic->lro_mgr, + skb, enic->vlan_group, + vlan, cq_desc); + else + vlan_hwaccel_receive_skb(skb, + enic->vlan_group, vlan); + + } else { + + if (ENIC_SETTING(enic, LRO) && ipv4) + lro_receive_skb(&enic->lro_mgr, skb, cq_desc); + else + netif_receive_skb(skb); + + } + + } else { + + /* Buffer overflow + */ + + dev_kfree_skb_any(skb); + } +} + +static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, + u8 type, u16 q_number, u16 completed_index, void *opaque) +{ + struct enic *enic = vnic_dev_priv(vdev); + + vnic_rq_service(&enic->rq[q_number], cq_desc, + completed_index, VNIC_RQ_RETURN_DESC, + enic_rq_indicate_buf, opaque); + + return 0; +} + +static void enic_rq_drop_buf(struct vnic_rq *rq, + struct cq_desc *cq_desc, struct vnic_rq_buf *buf, + int skipped, void *opaque) +{ + struct enic *enic = vnic_dev_priv(rq->vdev); + struct sk_buff *skb = buf->os_buf; + + if (skipped) + return; + + pci_unmap_single(enic->pdev, buf->dma_addr, + buf->len, PCI_DMA_FROMDEVICE); + + dev_kfree_skb_any(skb); +} + +static int enic_rq_service_drop(struct vnic_dev *vdev, struct cq_desc *cq_desc, + u8 type, u16 q_number, u16 completed_index, void *opaque) +{ + struct enic *enic = vnic_dev_priv(vdev); + + vnic_rq_service(&enic->rq[q_number], cq_desc, + completed_index, VNIC_RQ_RETURN_DESC, + enic_rq_drop_buf, opaque); + + return 0; +} + +static int enic_poll(struct napi_struct *napi, int budget) +{ + struct enic *enic = container_of(napi, struct enic, napi); + struct net_device *netdev = enic->netdev; + unsigned int rq_work_to_do = budget; + unsigned int wq_work_to_do = -1; /* no limit */ + unsigned int work_done, rq_work_done, wq_work_done; + + /* Service RQ (first) and WQ + */ + + rq_work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ], + rq_work_to_do, enic_rq_service, NULL); + + wq_work_done = vnic_cq_service(&enic->cq[ENIC_CQ_WQ], + wq_work_to_do, enic_wq_service, NULL); + + /* Accumulate intr event credits for this polling + * cycle. An intr event is the completion of a + * a WQ or RQ packet. + */ + + work_done = rq_work_done + wq_work_done; + + if (work_done > 0) + vnic_intr_return_credits(&enic->intr[ENIC_INTX_WQ_RQ], + work_done, + 0 /* don't unmask intr */, + 0 /* don't reset intr timer */); + + if (rq_work_done > 0) { + + /* Replenish RQ + */ + + vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); + + } else { + + /* If no work done, flush all LROs and exit polling + */ + + if (ENIC_SETTING(enic, LRO)) + lro_flush_all(&enic->lro_mgr); + + netif_rx_complete(netdev, napi); + vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]); + } + + return rq_work_done; +} + +static int enic_poll_msix(struct napi_struct *napi, int budget) +{ + struct enic *enic = container_of(napi, struct enic, napi); + struct net_device *netdev = enic->netdev; + unsigned int work_to_do = budget; + unsigned int work_done; + + /* Service RQ + */ + + work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ], + work_to_do, enic_rq_service, NULL); + + if (work_done > 0) { + + /* Replenish RQ + */ + + vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); + + /* Accumulate intr event credits for this polling + * cycle. An intr event is the completion of a + * a WQ or RQ packet. + */ + + vnic_intr_return_credits(&enic->intr[ENIC_MSIX_RQ], + work_done, + 0 /* don't unmask intr */, + 0 /* don't reset intr timer */); + } else { + + /* If no work done, flush all LROs and exit polling + */ + + if (ENIC_SETTING(enic, LRO)) + lro_flush_all(&enic->lro_mgr); + + netif_rx_complete(netdev, napi); + vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]); + } + + return work_done; +} + +static void enic_notify_timer(unsigned long data) +{ + struct enic *enic = (struct enic *)data; + + enic_notify_check(enic); + + mod_timer(&enic->notify_timer, + round_jiffies(jiffies + ENIC_NOTIFY_TIMER_PERIOD)); +} + +static void enic_free_intr(struct enic *enic) +{ + struct net_device *netdev = enic->netdev; + unsigned int i; + + switch (vnic_dev_get_intr_mode(enic->vdev)) { + case VNIC_DEV_INTR_MODE_INTX: + free_irq(enic->pdev->irq, netdev); + break; + case VNIC_DEV_INTR_MODE_MSI: + free_irq(enic->pdev->irq, enic); + break; + case VNIC_DEV_INTR_MODE_MSIX: + for (i = 0; i < ARRAY_SIZE(enic->msix); i++) + if (enic->msix[i].requested) + free_irq(enic->msix_entry[i].vector, + enic->msix[i].devid); + break; + default: + break; + } +} + +static int enic_request_intr(struct enic *enic) +{ + struct net_device *netdev = enic->netdev; + unsigned int i; + int err = 0; + + switch (vnic_dev_get_intr_mode(enic->vdev)) { + + case VNIC_DEV_INTR_MODE_INTX: + + err = request_irq(enic->pdev->irq, enic_isr_legacy, + IRQF_SHARED, netdev->name, netdev); + break; + + case VNIC_DEV_INTR_MODE_MSI: + + err = request_irq(enic->pdev->irq, enic_isr_msi, + 0, netdev->name, enic); + break; + + case VNIC_DEV_INTR_MODE_MSIX: + + sprintf(enic->msix[ENIC_MSIX_RQ].devname, + "%.11s-rx-0", netdev->name); + enic->msix[ENIC_MSIX_RQ].isr = enic_isr_msix_rq; + enic->msix[ENIC_MSIX_RQ].devid = enic; + + sprintf(enic->msix[ENIC_MSIX_WQ].devname, + "%.11s-tx-0", netdev->name); + enic->msix[ENIC_MSIX_WQ].isr = enic_isr_msix_wq; + enic->msix[ENIC_MSIX_WQ].devid = enic; + + sprintf(enic->msix[ENIC_MSIX_ERR].devname, + "%.11s-err", netdev->name); + enic->msix[ENIC_MSIX_ERR].isr = enic_isr_msix_err; + enic->msix[ENIC_MSIX_ERR].devid = enic; + + sprintf(enic->msix[ENIC_MSIX_NOTIFY].devname, + "%.11s-notify", netdev->name); + enic->msix[ENIC_MSIX_NOTIFY].isr = enic_isr_msix_notify; + enic->msix[ENIC_MSIX_NOTIFY].devid = enic; + + for (i = 0; i < ARRAY_SIZE(enic->msix); i++) { + err = request_irq(enic->msix_entry[i].vector, + enic->msix[i].isr, 0, + enic->msix[i].devname, + enic->msix[i].devid); + if (err) { + enic_free_intr(enic); + break; + } + enic->msix[i].requested = 1; + } + + break; + + default: + break; + } + + return err; +} + +static int enic_notify_set(struct enic *enic) +{ + int err; + + switch (vnic_dev_get_intr_mode(enic->vdev)) { + case VNIC_DEV_INTR_MODE_INTX: + err = vnic_dev_notify_set(enic->vdev, ENIC_INTX_NOTIFY); + break; + case VNIC_DEV_INTR_MODE_MSIX: + err = vnic_dev_notify_set(enic->vdev, ENIC_MSIX_NOTIFY); + break; + default: + err = vnic_dev_notify_set(enic->vdev, -1 /* no intr */); + break; + } + + return err; +} + +static void enic_notify_timer_start(struct enic *enic) +{ + switch (vnic_dev_get_intr_mode(enic->vdev)) { + case VNIC_DEV_INTR_MODE_MSI: + mod_timer(&enic->notify_timer, jiffies); + break; + default: + /* Using intr for notification for INTx/MSI-X */ + break; + }; +} + +/* rtnl lock is held, process context */ +static int enic_open(struct net_device *netdev) +{ + struct enic *enic = netdev_priv(netdev); + unsigned int i; + int err; + + err = enic_request_intr(enic); + if (err) { + printk(KERN_ERR PFX "%s: Unable to request irq.\n", + netdev->name); + return err; + } + + err = enic_notify_set(enic); + if (err) { + printk(KERN_ERR PFX + "%s: Failed to alloc notify buffer, aborting.\n", + netdev->name); + goto err_out_free_intr; + } + + for (i = 0; i < enic->rq_count; i++) { + err = vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf); + if (err) { + printk(KERN_ERR PFX + "%s: Unable to alloc receive buffers.\n", + netdev->name); + goto err_out_notify_unset; + } + } + + for (i = 0; i < enic->wq_count; i++) + vnic_wq_enable(&enic->wq[i]); + for (i = 0; i < enic->rq_count; i++) + vnic_rq_enable(&enic->rq[i]); + + enic_add_station_addr(enic); + enic_set_multicast_list(netdev); + + netif_wake_queue(netdev); + napi_enable(&enic->napi); + vnic_dev_enable(enic->vdev); + + for (i = 0; i < enic->intr_count; i++) + vnic_intr_unmask(&enic->intr[i]); + + enic_notify_timer_start(enic); + + return 0; + +err_out_notify_unset: + vnic_dev_notify_unset(enic->vdev); +err_out_free_intr: + enic_free_intr(enic); + + return err; +} + +/* rtnl lock is held, process context */ +static int enic_stop(struct net_device *netdev) +{ + struct enic *enic = netdev_priv(netdev); + unsigned int i; + int err; + + del_timer_sync(&enic->notify_timer); + + vnic_dev_disable(enic->vdev); + napi_disable(&enic->napi); + netif_stop_queue(netdev); + + for (i = 0; i < enic->intr_count; i++) + vnic_intr_mask(&enic->intr[i]); + + for (i = 0; i < enic->wq_count; i++) { + err = vnic_wq_disable(&enic->wq[i]); + if (err) + return err; + } + for (i = 0; i < enic->rq_count; i++) { + err = vnic_rq_disable(&enic->rq[i]); + if (err) + return err; + } + + vnic_dev_notify_unset(enic->vdev); + enic_free_intr(enic); + + (void)vnic_cq_service(&enic->cq[ENIC_CQ_RQ], + -1, enic_rq_service_drop, NULL); + (void)vnic_cq_service(&enic->cq[ENIC_CQ_WQ], + -1, enic_wq_service, NULL); + + for (i = 0; i < enic->wq_count; i++) + vnic_wq_clean(&enic->wq[i], enic_free_wq_buf); + for (i = 0; i < enic->rq_count; i++) + vnic_rq_clean(&enic->rq[i], enic_free_rq_buf); + for (i = 0; i < enic->cq_count; i++) + vnic_cq_clean(&enic->cq[i]); + for (i = 0; i < enic->intr_count; i++) + vnic_intr_clean(&enic->intr[i]); + + return 0; +} + +static int enic_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct enic *enic = netdev_priv(netdev); + int running = netif_running(netdev); + + if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU) + return -EINVAL; + + if (running) + enic_stop(netdev); + + netdev->mtu = new_mtu; + + if (netdev->mtu > enic->port_mtu) + printk(KERN_WARNING PFX + "%s: interface MTU (%d) set higher " + "than port MTU (%d)\n", + netdev->name, netdev->mtu, enic->port_mtu); + + if (running) + enic_open(netdev); + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void enic_poll_controller(struct net_device *netdev) +{ + struct enic *enic = netdev_priv(netdev); + struct vnic_dev *vdev = enic->vdev; + + switch (vnic_dev_get_intr_mode(vdev)) { + case VNIC_DEV_INTR_MODE_MSIX: + enic_isr_msix_rq(enic->pdev->irq, enic); + enic_isr_msix_wq(enic->pdev->irq, enic); + break; + case VNIC_DEV_INTR_MODE_MSI: + enic_isr_msi(enic->pdev->irq, enic); + break; + case VNIC_DEV_INTR_MODE_INTX: + enic_isr_legacy(enic->pdev->irq, netdev); + break; + default: + break; + } +} +#endif + +static int enic_dev_wait(struct vnic_dev *vdev, + int (*start)(struct vnic_dev *, int), + int (*finished)(struct vnic_dev *, int *), + int arg) +{ + unsigned long time; + int done; + int err; + + BUG_ON(in_interrupt()); + + err = start(vdev, arg); + if (err) + return err; + + /* Wait for func to complete...2 seconds max + */ + + time = jiffies + (HZ * 2); + do { + + err = finished(vdev, &done); + if (err) + return err; + + if (done) + return 0; + + schedule_timeout_uninterruptible(HZ / 10); + + } while (time_after(time, jiffies)); + + return -ETIMEDOUT; +} + +static int enic_dev_open(struct enic *enic) +{ + int err; + + err = enic_dev_wait(enic->vdev, vnic_dev_open, + vnic_dev_open_done, 0); + if (err) + printk(KERN_ERR PFX + "vNIC device open failed, err %d.\n", err); + + return err; +} + +static int enic_dev_soft_reset(struct enic *enic) +{ + int err; + + err = enic_dev_wait(enic->vdev, vnic_dev_soft_reset, + vnic_dev_soft_reset_done, 0); + if (err) + printk(KERN_ERR PFX + "vNIC soft reset failed, err %d.\n", err); + + return err; +} + +static void enic_reset(struct work_struct *work) +{ + struct enic *enic = container_of(work, struct enic, reset); + + if (!netif_running(enic->netdev)) + return; + + rtnl_lock(); + + spin_lock(&enic->devcmd_lock); + vnic_dev_hang_notify(enic->vdev); + spin_unlock(&enic->devcmd_lock); + + enic_stop(enic->netdev); + enic_dev_soft_reset(enic); + enic_reset_mcaddrs(enic); + enic_init_vnic_resources(enic); + enic_open(enic->netdev); + + rtnl_unlock(); +} + +static int enic_set_intr_mode(struct enic *enic) +{ + unsigned int n = ARRAY_SIZE(enic->rq); + unsigned int m = ARRAY_SIZE(enic->wq); + unsigned int i; + + /* Set interrupt mode (INTx, MSI, MSI-X) depending + * system capabilities. + * + * Try MSI-X first + * + * We need n RQs, m WQs, n+m CQs, and n+m+2 INTRs + * (the second to last INTR is used for WQ/RQ errors) + * (the last INTR is used for notifications) + */ + + BUG_ON(ARRAY_SIZE(enic->msix_entry) < n + m + 2); + for (i = 0; i < n + m + 2; i++) + enic->msix_entry[i].entry = i; + + if (enic->config.intr_mode < 1 && + enic->rq_count >= n && + enic->wq_count >= m && + enic->cq_count >= n + m && + enic->intr_count >= n + m + 2 && + !pci_enable_msix(enic->pdev, enic->msix_entry, n + m + 2)) { + + enic->rq_count = n; + enic->wq_count = m; + enic->cq_count = n + m; + enic->intr_count = n + m + 2; + + vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_MSIX); + + return 0; + } + + /* Next try MSI + * + * We need 1 RQ, 1 WQ, 2 CQs, and 1 INTR + */ + + if (enic->config.intr_mode < 2 && + enic->rq_count >= 1 && + enic->wq_count >= 1 && + enic->cq_count >= 2 && + enic->intr_count >= 1 && + !pci_enable_msi(enic->pdev)) { + + enic->rq_count = 1; + enic->wq_count = 1; + enic->cq_count = 2; + enic->intr_count = 1; + + vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_MSI); + + return 0; + } + + /* Next try INTx + * + * We need 1 RQ, 1 WQ, 2 CQs, and 3 INTRs + * (the first INTR is used for WQ/RQ) + * (the second INTR is used for WQ/RQ errors) + * (the last INTR is used for notifications) + */ + + if (enic->config.intr_mode < 3 && + enic->rq_count >= 1 && + enic->wq_count >= 1 && + enic->cq_count >= 2 && + enic->intr_count >= 3) { + + enic->rq_count = 1; + enic->wq_count = 1; + enic->cq_count = 2; + enic->intr_count = 3; + + vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_INTX); + + return 0; + } + + vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); + + return -EINVAL; +} + +static void enic_clear_intr_mode(struct enic *enic) +{ + switch (vnic_dev_get_intr_mode(enic->vdev)) { + case VNIC_DEV_INTR_MODE_MSIX: + pci_disable_msix(enic->pdev); + break; + case VNIC_DEV_INTR_MODE_MSI: + pci_disable_msi(enic->pdev); + break; + default: + break; + } + + vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); +} + +static void enic_iounmap(struct enic *enic) +{ + if (enic->bar0.vaddr) + iounmap(enic->bar0.vaddr); +} + +static int __devinit enic_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct enic *enic; + int using_dac = 0; + unsigned int i; + int err; + + const u8 rss_default_cpu = 0; + const u8 rss_hash_type = 0; + const u8 rss_hash_bits = 0; + const u8 rss_base_cpu = 0; + const u8 rss_enable = 0; + const u8 tso_ipid_split_en = 0; + const u8 ig_vlan_strip_en = 1; + + /* Allocate net device structure and initialize. Private + * instance data is initialized to zero. + */ + + netdev = alloc_etherdev(sizeof(struct enic)); + if (!netdev) { + printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); + return -ENOMEM; + } + + pci_set_drvdata(pdev, netdev); + + SET_NETDEV_DEV(netdev, &pdev->dev); + + enic = netdev_priv(netdev); + enic->netdev = netdev; + enic->pdev = pdev; + + /* Setup PCI resources + */ + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR PFX + "Cannot enable PCI device, aborting.\n"); + goto err_out_free_netdev; + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + printk(KERN_ERR PFX + "Cannot request PCI regions, aborting.\n"); + goto err_out_disable_device; + } + + pci_set_master(pdev); + + /* Query PCI controller on system for DMA addressing + * limitation for the device. Try 40-bit first, and + * fail to 32-bit. + */ + + err = pci_set_dma_mask(pdev, DMA_40BIT_MASK); + if (err) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_ERR PFX + "No usable DMA configuration, aborting.\n"); + goto err_out_release_regions; + } + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_ERR PFX + "Unable to obtain 32-bit DMA " + "for consistent allocations, aborting.\n"); + goto err_out_release_regions; + } + } else { + err = pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK); + if (err) { + printk(KERN_ERR PFX + "Unable to obtain 40-bit DMA " + "for consistent allocations, aborting.\n"); + goto err_out_release_regions; + } + using_dac = 1; + } + + /* Map vNIC resources from BAR0 + */ + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + printk(KERN_ERR PFX + "BAR0 not memory-map'able, aborting.\n"); + err = -ENODEV; + goto err_out_release_regions; + } + + enic->bar0.vaddr = pci_iomap(pdev, 0, enic->bar0.len); + enic->bar0.bus_addr = pci_resource_start(pdev, 0); + enic->bar0.len = pci_resource_len(pdev, 0); + + if (!enic->bar0.vaddr) { + printk(KERN_ERR PFX + "Cannot memory-map BAR0 res hdr, aborting.\n"); + err = -ENODEV; + goto err_out_release_regions; + } + + /* Register vNIC device + */ + + enic->vdev = vnic_dev_register(NULL, enic, pdev, &enic->bar0); + if (!enic->vdev) { + printk(KERN_ERR PFX + "vNIC registration failed, aborting.\n"); + err = -ENODEV; + goto err_out_iounmap; + } + + /* Issue device open to get device in known state + */ + + err = enic_dev_open(enic); + if (err) { + printk(KERN_ERR PFX + "vNIC dev open failed, aborting.\n"); + goto err_out_vnic_unregister; + } + + /* Issue device init to initialize the vnic-to-switch link. + * We'll start with carrier off and wait for link UP + * notification later to turn on carrier. We don't need + * to wait here for the vnic-to-switch link initialization + * to complete; link UP notification is the indication that + * the process is complete. + */ + + netif_carrier_off(netdev); + + err = vnic_dev_init(enic->vdev, 0); + if (err) { + printk(KERN_ERR PFX + "vNIC dev init failed, aborting.\n"); + goto err_out_dev_close; + } + + /* Get vNIC configuration + */ + + err = enic_get_vnic_config(enic); + if (err) { + printk(KERN_ERR PFX + "Get vNIC configuration failed, aborting.\n"); + goto err_out_dev_close; + } + + /* Get available resource counts + */ + + enic_get_res_counts(enic); + + /* Set interrupt mode based on resource counts and system + * capabilities + */ + + err = enic_set_intr_mode(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to set intr mode, aborting.\n"); + goto err_out_dev_close; + } + + /* Allocate and configure vNIC resources + */ + + err = enic_alloc_vnic_resources(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to alloc vNIC resources, aborting.\n"); + goto err_out_free_vnic_resources; + } + + enic_init_vnic_resources(enic); + + /* Enable VLAN tag stripping. RSS not enabled (yet). + */ + + err = enic_set_nic_cfg(enic, + rss_default_cpu, rss_hash_type, + rss_hash_bits, rss_base_cpu, + rss_enable, tso_ipid_split_en, + ig_vlan_strip_en); + if (err) { + printk(KERN_ERR PFX + "Failed to config nic, aborting.\n"); + goto err_out_free_vnic_resources; + } + + /* Setup notification timer, HW reset task, and locks + */ + + init_timer(&enic->notify_timer); + enic->notify_timer.function = enic_notify_timer; + enic->notify_timer.data = (unsigned long)enic; + + INIT_WORK(&enic->reset, enic_reset); + + for (i = 0; i < enic->wq_count; i++) + spin_lock_init(&enic->wq_lock[i]); + + spin_lock_init(&enic->devcmd_lock); + + /* Register net device + */ + + enic->port_mtu = enic->config.mtu; + (void)enic_change_mtu(netdev, enic->port_mtu); + + err = enic_set_mac_addr(netdev, enic->mac_addr); + if (err) { + printk(KERN_ERR PFX + "Invalid MAC address, aborting.\n"); + goto err_out_free_vnic_resources; + } + + netdev->open = enic_open; + netdev->stop = enic_stop; + netdev->hard_start_xmit = enic_hard_start_xmit; + netdev->get_stats = enic_get_stats; + netdev->set_multicast_list = enic_set_multicast_list; + netdev->change_mtu = enic_change_mtu; + netdev->vlan_rx_register = enic_vlan_rx_register; + netdev->vlan_rx_add_vid = enic_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = enic_vlan_rx_kill_vid; + netdev->tx_timeout = enic_tx_timeout; + netdev->watchdog_timeo = 2 * HZ; + netdev->ethtool_ops = &enic_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = enic_poll_controller; +#endif + + switch (vnic_dev_get_intr_mode(enic->vdev)) { + default: + netif_napi_add(netdev, &enic->napi, enic_poll, 64); + break; + case VNIC_DEV_INTR_MODE_MSIX: + netif_napi_add(netdev, &enic->napi, enic_poll_msix, 64); + break; + } + + netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + if (ENIC_SETTING(enic, TXCSUM)) + netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + if (ENIC_SETTING(enic, TSO)) + netdev->features |= NETIF_F_TSO | + NETIF_F_TSO6 | NETIF_F_TSO_ECN; + if (using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + + enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM); + + if (ENIC_SETTING(enic, LRO)) { + enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR; + enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC; + enic->lro_mgr.lro_arr = enic->lro_desc; + enic->lro_mgr.get_skb_header = enic_get_skb_header; + enic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + enic->lro_mgr.dev = netdev; + enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE; + enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + } + + err = register_netdev(netdev); + if (err) { + printk(KERN_ERR PFX + "Cannot register net device, aborting.\n"); + goto err_out_free_vnic_resources; + } + + return 0; + +err_out_free_vnic_resources: + enic_free_vnic_resources(enic); +err_out_dev_close: + vnic_dev_close(enic->vdev); +err_out_vnic_unregister: + enic_clear_intr_mode(enic); + vnic_dev_unregister(enic->vdev); +err_out_iounmap: + enic_iounmap(enic); +err_out_release_regions: + pci_release_regions(pdev); +err_out_disable_device: + pci_disable_device(pdev); +err_out_free_netdev: + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); + + return err; +} + +static void __devexit enic_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + if (netdev) { + struct enic *enic = netdev_priv(netdev); + + flush_scheduled_work(); + unregister_netdev(netdev); + enic_free_vnic_resources(enic); + vnic_dev_close(enic->vdev); + enic_clear_intr_mode(enic); + vnic_dev_unregister(enic->vdev); + enic_iounmap(enic); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); + } +} + +static struct pci_driver enic_driver = { + .name = DRV_NAME, + .id_table = enic_id_table, + .probe = enic_probe, + .remove = __devexit_p(enic_remove), +}; + +static int __init enic_init_module(void) +{ + printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION); + + return pci_register_driver(&enic_driver); +} + +static void __exit enic_cleanup_module(void) +{ + pci_unregister_driver(&enic_driver); +} + +module_init(enic_init_module); +module_exit(enic_cleanup_module); diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c new file mode 100644 index 00000000000..95184b9108e --- /dev/null +++ b/drivers/net/enic/enic_res.c @@ -0,0 +1,370 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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/errno.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/netdevice.h> + +#include "wq_enet_desc.h" +#include "rq_enet_desc.h" +#include "cq_enet_desc.h" +#include "vnic_resource.h" +#include "vnic_enet.h" +#include "vnic_dev.h" +#include "vnic_wq.h" +#include "vnic_rq.h" +#include "vnic_cq.h" +#include "vnic_intr.h" +#include "vnic_stats.h" +#include "vnic_nic.h" +#include "vnic_rss.h" +#include "enic_res.h" +#include "enic.h" + +int enic_get_vnic_config(struct enic *enic) +{ + struct vnic_enet_config *c = &enic->config; + int err; + + err = vnic_dev_mac_addr(enic->vdev, enic->mac_addr); + if (err) { + printk(KERN_ERR PFX "Error getting MAC addr, %d\n", err); + return err; + } + +#define GET_CONFIG(m) \ + do { \ + err = vnic_dev_spec(enic->vdev, \ + offsetof(struct vnic_enet_config, m), \ + sizeof(c->m), &c->m); \ + if (err) { \ + printk(KERN_ERR PFX \ + "Error getting %s, %d\n", #m, err); \ + return err; \ + } \ + } while (0) + + GET_CONFIG(flags); + GET_CONFIG(wq_desc_count); + GET_CONFIG(rq_desc_count); + GET_CONFIG(mtu); + GET_CONFIG(intr_timer); + GET_CONFIG(intr_timer_type); + GET_CONFIG(intr_mode); + + c->wq_desc_count = + min_t(u32, ENIC_MAX_WQ_DESCS, + max_t(u32, ENIC_MIN_WQ_DESCS, + c->wq_desc_count)); + c->wq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */ + + c->rq_desc_count = + min_t(u32, ENIC_MAX_RQ_DESCS, + max_t(u32, ENIC_MIN_RQ_DESCS, + c->rq_desc_count)); + c->rq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */ + + if (c->mtu == 0) + c->mtu = 1500; + c->mtu = min_t(u16, ENIC_MAX_MTU, + max_t(u16, ENIC_MIN_MTU, + c->mtu)); + + c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); + + printk(KERN_INFO PFX "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x " + "wq/rq %d/%d\n", + enic->mac_addr[0], enic->mac_addr[1], enic->mac_addr[2], + enic->mac_addr[3], enic->mac_addr[4], enic->mac_addr[5], + c->wq_desc_count, c->rq_desc_count); + printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d " + "intr timer %d\n", + c->mtu, ENIC_SETTING(enic, TXCSUM), + ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO), + ENIC_SETTING(enic, LRO), c->intr_timer); + + return 0; +} + +void enic_add_station_addr(struct enic *enic) +{ + vnic_dev_add_addr(enic->vdev, enic->mac_addr); +} + +void enic_add_multicast_addr(struct enic *enic, u8 *addr) +{ + vnic_dev_add_addr(enic->vdev, addr); +} + +void enic_del_multicast_addr(struct enic *enic, u8 *addr) +{ + vnic_dev_del_addr(enic->vdev, addr); +} + +void enic_add_vlan(struct enic *enic, u16 vlanid) +{ + u64 a0 = vlanid, a1 = 0; + int wait = 1000; + int err; + + err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait); + if (err) + printk(KERN_ERR PFX "Can't add vlan id, %d\n", err); +} + +void enic_del_vlan(struct enic *enic, u16 vlanid) +{ + u64 a0 = vlanid, a1 = 0; + int wait = 1000; + int err; + + err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait); + if (err) + printk(KERN_ERR PFX "Can't delete vlan id, %d\n", err); +} + +int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type, + u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en, + u8 ig_vlan_strip_en) +{ + u64 a0, a1; + u32 nic_cfg; + int wait = 1000; + + vnic_set_nic_cfg(&nic_cfg, rss_default_cpu, + rss_hash_type, rss_hash_bits, rss_base_cpu, + rss_enable, tso_ipid_split_en, ig_vlan_strip_en); + + a0 = nic_cfg; + a1 = 0; + + return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait); +} + +void enic_free_vnic_resources(struct enic *enic) +{ + unsigned int i; + + for (i = 0; i < enic->wq_count; i++) + vnic_wq_free(&enic->wq[i]); + for (i = 0; i < enic->rq_count; i++) + vnic_rq_free(&enic->rq[i]); + for (i = 0; i < enic->cq_count; i++) + vnic_cq_free(&enic->cq[i]); + for (i = 0; i < enic->intr_count; i++) + vnic_intr_free(&enic->intr[i]); +} + +void enic_get_res_counts(struct enic *enic) +{ + enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ); + enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ); + enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ); + enic->intr_count = vnic_dev_get_res_count(enic->vdev, + RES_TYPE_INTR_CTRL); + + printk(KERN_INFO PFX "vNIC resources avail: " + "wq %d rq %d cq %d intr %d\n", + enic->wq_count, enic->rq_count, + enic->cq_count, enic->intr_count); +} + +void enic_init_vnic_resources(struct enic *enic) +{ + enum vnic_dev_intr_mode intr_mode; + unsigned int mask_on_assertion; + unsigned int interrupt_offset; + unsigned int error_interrupt_enable; + unsigned int error_interrupt_offset; + unsigned int cq_index; + unsigned int i; + + intr_mode = vnic_dev_get_intr_mode(enic->vdev); + + /* Init RQ/WQ resources. + * + * RQ[0 - n-1] point to CQ[0 - n-1] + * WQ[0 - m-1] point to CQ[n - n+m-1] + * + * Error interrupt is not enabled for MSI. + */ + + switch (intr_mode) { + case VNIC_DEV_INTR_MODE_INTX: + case VNIC_DEV_INTR_MODE_MSIX: + error_interrupt_enable = 1; + error_interrupt_offset = enic->intr_count - 2; + break; + default: + error_interrupt_enable = 0; + error_interrupt_offset = 0; + break; + } + + for (i = 0; i < enic->rq_count; i++) { + cq_index = i; + vnic_rq_init(&enic->rq[i], + cq_index, + error_interrupt_enable, + error_interrupt_offset); + } + + for (i = 0; i < enic->wq_count; i++) { + cq_index = enic->rq_count + i; + vnic_wq_init(&enic->wq[i], + cq_index, + error_interrupt_enable, + error_interrupt_offset); + } + + /* Init CQ resources + * + * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI + * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X + */ + + for (i = 0; i < enic->cq_count; i++) { + + switch (intr_mode) { + case VNIC_DEV_INTR_MODE_MSIX: + interrupt_offset = i; + break; + default: + interrupt_offset = 0; + break; + } + + vnic_cq_init(&enic->cq[i], + 0 /* flow_control_enable */, + 1 /* color_enable */, + 0 /* cq_head */, + 0 /* cq_tail */, + 1 /* cq_tail_color */, + 1 /* interrupt_enable */, + 1 /* cq_entry_enable */, + 0 /* cq_message_enable */, + interrupt_offset, + 0 /* cq_message_addr */); + } + + /* Init INTR resources + * + * mask_on_assertion is not used for INTx due to the level- + * triggered nature of INTx + */ + + switch (intr_mode) { + case VNIC_DEV_INTR_MODE_MSI: + case VNIC_DEV_INTR_MODE_MSIX: + mask_on_assertion = 1; + break; + default: + mask_on_assertion = 0; + break; + } + + for (i = 0; i < enic->intr_count; i++) { + vnic_intr_init(&enic->intr[i], + enic->config.intr_timer, + enic->config.intr_timer_type, + mask_on_assertion); + } + + /* Clear LIF stats + */ + + vnic_dev_stats_clear(enic->vdev); +} + +int enic_alloc_vnic_resources(struct enic *enic) +{ + enum vnic_dev_intr_mode intr_mode; + unsigned int i; + int err; + + intr_mode = vnic_dev_get_intr_mode(enic->vdev); + + printk(KERN_INFO PFX "vNIC resources used: " + "wq %d rq %d cq %d intr %d intr mode %s\n", + enic->wq_count, enic->rq_count, + enic->cq_count, enic->intr_count, + intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" : + intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" : + intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" : + "unknown" + ); + + /* Allocate queue resources + */ + + for (i = 0; i < enic->wq_count; i++) { + err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i, + enic->config.wq_desc_count, + sizeof(struct wq_enet_desc)); + if (err) + goto err_out_cleanup; + } + + for (i = 0; i < enic->rq_count; i++) { + err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i, + enic->config.rq_desc_count, + sizeof(struct rq_enet_desc)); + if (err) + goto err_out_cleanup; + } + + for (i = 0; i < enic->cq_count; i++) { + if (i < enic->rq_count) + err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i, + enic->config.rq_desc_count, + sizeof(struct cq_enet_rq_desc)); + else + err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i, + enic->config.wq_desc_count, + sizeof(struct cq_enet_wq_desc)); + if (err) + goto err_out_cleanup; + } + + for (i = 0; i < enic->intr_count; i++) { + err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i); + if (err) + goto err_out_cleanup; + } + + /* Hook remaining resource + */ + + enic->legacy_pba = vnic_dev_get_res(enic->vdev, + RES_TYPE_INTR_PBA_LEGACY, 0); + if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) { + printk(KERN_ERR PFX "Failed to hook legacy pba resource\n"); + err = -ENODEV; + goto err_out_cleanup; + } + + return 0; + +err_out_cleanup: + enic_free_vnic_resources(enic); + + return err; +} diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h new file mode 100644 index 00000000000..68534a29b7a --- /dev/null +++ b/drivers/net/enic/enic_res.h @@ -0,0 +1,151 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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_RES_H_ +#define _ENIC_RES_H_ + +#include "wq_enet_desc.h" +#include "rq_enet_desc.h" +#include "vnic_wq.h" +#include "vnic_rq.h" + +#define ENIC_MIN_WQ_DESCS 64 +#define ENIC_MAX_WQ_DESCS 4096 +#define ENIC_MIN_RQ_DESCS 64 +#define ENIC_MAX_RQ_DESCS 4096 + +#define ENIC_MIN_MTU 576 /* minimum for IPv4 */ +#define ENIC_MAX_MTU 9000 + +#define ENIC_MULTICAST_PERFECT_FILTERS 32 + +#define ENIC_NON_TSO_MAX_DESC 16 + +#define ENIC_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0) + +static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq, + void *os_buf, dma_addr_t dma_addr, unsigned int len, + unsigned int mss_or_csum_offset, unsigned int hdr_len, + int vlan_tag_insert, unsigned int vlan_tag, + int offload_mode, int cq_entry, int sop, int eop) +{ + struct wq_enet_desc *desc = vnic_wq_next_desc(wq); + + wq_enet_desc_enc(desc, + (u64)dma_addr | VNIC_PADDR_TARGET, + (u16)len, + (u16)mss_or_csum_offset, + (u16)hdr_len, (u8)offload_mode, + (u8)eop, (u8)cq_entry, + 0, /* fcoe_encap */ + (u8)vlan_tag_insert, + (u16)vlan_tag, + 0 /* loopback */); + + wmb(); + + vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop); +} + +static inline void enic_queue_wq_desc_cont(struct vnic_wq *wq, + void *os_buf, dma_addr_t dma_addr, unsigned int len, int eop) +{ + enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, + 0, 0, 0, 0, 0, + eop, 0 /* !SOP */, eop); +} + +static inline void enic_queue_wq_desc(struct vnic_wq *wq, void *os_buf, + dma_addr_t dma_addr, unsigned int len, int vlan_tag_insert, + unsigned int vlan_tag, int eop) +{ + enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, + 0, 0, vlan_tag_insert, vlan_tag, + WQ_ENET_OFFLOAD_MODE_CSUM, + eop, 1 /* SOP */, eop); +} + +static inline void enic_queue_wq_desc_csum(struct vnic_wq *wq, + void *os_buf, dma_addr_t dma_addr, unsigned int len, + int ip_csum, int tcpudp_csum, int vlan_tag_insert, + unsigned int vlan_tag, int eop) +{ + enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, + (ip_csum ? 1 : 0) + (tcpudp_csum ? 2 : 0), + 0, vlan_tag_insert, vlan_tag, + WQ_ENET_OFFLOAD_MODE_CSUM, + eop, 1 /* SOP */, eop); +} + +static inline void enic_queue_wq_desc_csum_l4(struct vnic_wq *wq, + void *os_buf, dma_addr_t dma_addr, unsigned int len, + unsigned int csum_offset, unsigned int hdr_len, + int vlan_tag_insert, unsigned int vlan_tag, int eop) +{ + enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, + csum_offset, hdr_len, vlan_tag_insert, vlan_tag, + WQ_ENET_OFFLOAD_MODE_CSUM_L4, + eop, 1 /* SOP */, eop); +} + +static inline void enic_queue_wq_desc_tso(struct vnic_wq *wq, + void *os_buf, dma_addr_t dma_addr, unsigned int len, + unsigned int mss, unsigned int hdr_len, int vlan_tag_insert, + unsigned int vlan_tag, int eop) +{ + enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, + mss, hdr_len, vlan_tag_insert, vlan_tag, + WQ_ENET_OFFLOAD_MODE_TSO, + eop, 1 /* SOP */, eop); +} + +static inline void enic_queue_rq_desc(struct vnic_rq *rq, + void *os_buf, unsigned int os_buf_index, + dma_addr_t dma_addr, unsigned int len) +{ + struct rq_enet_desc *desc = vnic_rq_next_desc(rq); + u8 type = os_buf_index ? + RQ_ENET_TYPE_NOT_SOP : RQ_ENET_TYPE_ONLY_SOP; + + rq_enet_desc_enc(desc, + (u64)dma_addr | VNIC_PADDR_TARGET, + type, (u16)len); + + wmb(); + + vnic_rq_post(rq, os_buf, os_buf_index, dma_addr, len); +} + +struct enic; + +int enic_get_vnic_config(struct enic *); +void enic_add_station_addr(struct enic *enic); +void enic_add_multicast_addr(struct enic *enic, u8 *addr); +void enic_del_multicast_addr(struct enic *enic, u8 *addr); +void enic_add_vlan(struct enic *enic, u16 vlanid); +void enic_del_vlan(struct enic *enic, u16 vlanid); +int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type, + u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en, + u8 ig_vlan_strip_en); +void enic_get_res_counts(struct enic *enic); +void enic_init_vnic_resources(struct enic *enic); +int enic_alloc_vnic_resources(struct enic *); +void enic_free_vnic_resources(struct enic *); + +#endif /* _ENIC_RES_H_ */ diff --git a/drivers/net/enic/rq_enet_desc.h b/drivers/net/enic/rq_enet_desc.h new file mode 100644 index 00000000000..a06e649010c --- /dev/null +++ b/drivers/net/enic/rq_enet_desc.h @@ -0,0 +1,60 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _RQ_ENET_DESC_H_ +#define _RQ_ENET_DESC_H_ + +/* Ethernet receive queue descriptor: 16B */ +struct rq_enet_desc { + __le64 address; + __le16 length_type; + u8 reserved[6]; +}; + +enum rq_enet_type_types { + RQ_ENET_TYPE_ONLY_SOP = 0, + RQ_ENET_TYPE_NOT_SOP = 1, + RQ_ENET_TYPE_RESV2 = 2, + RQ_ENET_TYPE_RESV3 = 3, +}; + +#define RQ_ENET_ADDR_BITS 64 +#define RQ_ENET_LEN_BITS 14 +#define RQ_ENET_LEN_MASK ((1 << RQ_ENET_LEN_BITS) - 1) +#define RQ_ENET_TYPE_BITS 2 +#define RQ_ENET_TYPE_MASK ((1 << RQ_ENET_TYPE_BITS) - 1) + +static inline void rq_enet_desc_enc(struct rq_enet_desc *desc, + u64 address, u8 type, u16 length) +{ + desc->address = cpu_to_le64(address); + desc->length_type = cpu_to_le16((length & RQ_ENET_LEN_MASK) | + ((type & RQ_ENET_TYPE_MASK) << RQ_ENET_LEN_BITS)); +} + +static inline void rq_enet_desc_dec(struct rq_enet_desc *desc, + u64 *address, u8 *type, u16 *length) +{ + *address = le64_to_cpu(desc->address); + *length = le16_to_cpu(desc->length_type) & RQ_ENET_LEN_MASK; + *type = (u8)((le16_to_cpu(desc->length_type) >> RQ_ENET_LEN_BITS) & + RQ_ENET_TYPE_MASK); +} + +#endif /* _RQ_ENET_DESC_H_ */ diff --git a/drivers/net/enic/vnic_cq.c b/drivers/net/enic/vnic_cq.c new file mode 100644 index 00000000000..020ae6c3f3d --- /dev/null +++ b/drivers/net/enic/vnic_cq.c @@ -0,0 +1,89 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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/errno.h> +#include <linux/types.h> +#include <linux/pci.h> + +#include "vnic_dev.h" +#include "vnic_cq.h" + +void vnic_cq_free(struct vnic_cq *cq) +{ + vnic_dev_free_desc_ring(cq->vdev, &cq->ring); + + cq->ctrl = NULL; +} + +int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index, + unsigned int desc_count, unsigned int desc_size) +{ + int err; + + cq->index = index; + cq->vdev = vdev; + + cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index); + if (!cq->ctrl) { + printk(KERN_ERR "Failed to hook CQ[%d] resource\n", index); + return -EINVAL; + } + + err = vnic_dev_alloc_desc_ring(vdev, &cq->ring, desc_count, desc_size); + if (err) + return err; + + return 0; +} + +void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable, + unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail, + unsigned int cq_tail_color, unsigned int interrupt_enable, + unsigned int cq_entry_enable, unsigned int cq_message_enable, + unsigned int interrupt_offset, u64 cq_message_addr) +{ + u64 paddr; + + paddr = (u64)cq->ring.base_addr | VNIC_PADDR_TARGET; + writeq(paddr, &cq->ctrl->ring_base); + iowrite32(cq->ring.desc_count, &cq->ctrl->ring_size); + iowrite32(flow_control_enable, &cq->ctrl->flow_control_enable); + iowrite32(color_enable, &cq->ctrl->color_enable); + iowrite32(cq_head, &cq->ctrl->cq_head); + iowrite32(cq_tail, &cq->ctrl->cq_tail); + iowrite32(cq_tail_color, &cq->ctrl->cq_tail_color); + iowrite32(interrupt_enable, &cq->ctrl->interrupt_enable); + iowrite32(cq_entry_enable, &cq->ctrl->cq_entry_enable); + iowrite32(cq_message_enable, &cq->ctrl->cq_message_enable); + iowrite32(interrupt_offset, &cq->ctrl->interrupt_offset); + writeq(cq_message_addr, &cq->ctrl->cq_message_addr); +} + +void vnic_cq_clean(struct vnic_cq *cq) +{ + cq->to_clean = 0; + cq->last_color = 0; + + iowrite32(0, &cq->ctrl->cq_head); + iowrite32(0, &cq->ctrl->cq_tail); + iowrite32(1, &cq->ctrl->cq_tail_color); + + vnic_dev_clear_desc_ring(&cq->ring); +} diff --git a/drivers/net/enic/vnic_cq.h b/drivers/net/enic/vnic_cq.h new file mode 100644 index 00000000000..114763cbc2f --- /dev/null +++ b/drivers/net/enic/vnic_cq.h @@ -0,0 +1,113 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_CQ_H_ +#define _VNIC_CQ_H_ + +#include "cq_desc.h" +#include "vnic_dev.h" + +/* Completion queue control */ +struct vnic_cq_ctrl { + u64 ring_base; /* 0x00 */ + u32 ring_size; /* 0x08 */ + u32 pad0; + u32 flow_control_enable; /* 0x10 */ + u32 pad1; + u32 color_enable; /* 0x18 */ + u32 pad2; + u32 cq_head; /* 0x20 */ + u32 pad3; + u32 cq_tail; /* 0x28 */ + u32 pad4; + u32 cq_tail_color; /* 0x30 */ + u32 pad5; + u32 interrupt_enable; /* 0x38 */ + u32 pad6; + u32 cq_entry_enable; /* 0x40 */ + u32 pad7; + u32 cq_message_enable; /* 0x48 */ + u32 pad8; + u32 interrupt_offset; /* 0x50 */ + u32 pad9; + u64 cq_message_addr; /* 0x58 */ + u32 pad10; +}; + +struct vnic_cq { + unsigned int index; + struct vnic_dev *vdev; + struct vnic_cq_ctrl __iomem *ctrl; /* memory-mapped */ + struct vnic_dev_ring ring; + unsigned int to_clean; + unsigned int last_color; +}; + +static inline unsigned int vnic_cq_service(struct vnic_cq *cq, + unsigned int work_to_do, + int (*q_service)(struct vnic_dev *vdev, struct cq_desc *cq_desc, + u8 type, u16 q_number, u16 completed_index, void *opaque), + void *opaque) +{ + struct cq_desc *cq_desc; + unsigned int work_done = 0; + u16 q_number, completed_index; + u8 type, color; + + cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + + cq->ring.desc_size * cq->to_clean); + cq_desc_dec(cq_desc, &type, &color, + &q_number, &completed_index); + + while (color != cq->last_color) { + + if ((*q_service)(cq->vdev, cq_desc, type, + q_number, completed_index, opaque)) + break; + + cq->to_clean++; + if (cq->to_clean == cq->ring.desc_count) { + cq->to_clean = 0; + cq->last_color = cq->last_color ? 0 : 1; + } + + cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + + cq->ring.desc_size * cq->to_clean); + cq_desc_dec(cq_desc, &type, &color, + &q_number, &completed_index); + + work_done++; + if (work_done >= work_to_do) + break; + } + + return work_done; +} + +void vnic_cq_free(struct vnic_cq *cq); +int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index, + unsigned int desc_count, unsigned int desc_size); +void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable, + unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail, + unsigned int cq_tail_color, unsigned int interrupt_enable, + unsigned int cq_entry_enable, unsigned int message_enable, + unsigned int interrupt_offset, u64 message_addr); +void vnic_cq_clean(struct vnic_cq *cq); + +#endif /* _VNIC_CQ_H_ */ diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c new file mode 100644 index 00000000000..4d104f5c30f --- /dev/null +++ b/drivers/net/enic/vnic_dev.c @@ -0,0 +1,674 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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/errno.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/if_ether.h> + +#include "vnic_resource.h" +#include "vnic_devcmd.h" +#include "vnic_dev.h" +#include "vnic_stats.h" + +struct vnic_res { + void __iomem *vaddr; + unsigned int count; +}; + +struct vnic_dev { + void *priv; + struct pci_dev *pdev; + struct vnic_res res[RES_TYPE_MAX]; + enum vnic_dev_intr_mode intr_mode; + struct vnic_devcmd __iomem *devcmd; + struct vnic_devcmd_notify *notify; + struct vnic_devcmd_notify notify_copy; + dma_addr_t notify_pa; + u32 *linkstatus; + dma_addr_t linkstatus_pa; + struct vnic_stats *stats; + dma_addr_t stats_pa; + struct vnic_devcmd_fw_info *fw_info; + dma_addr_t fw_info_pa; +}; + +#define VNIC_MAX_RES_HDR_SIZE \ + (sizeof(struct vnic_resource_header) + \ + sizeof(struct vnic_resource) * RES_TYPE_MAX) +#define VNIC_RES_STRIDE 128 + +void *vnic_dev_priv(struct vnic_dev *vdev) +{ + return vdev->priv; +} + +static int vnic_dev_discover_res(struct vnic_dev *vdev, + struct vnic_dev_bar *bar) +{ + struct vnic_resource_header __iomem *rh; + struct vnic_resource __iomem *r; + u8 type; + + if (bar->len < VNIC_MAX_RES_HDR_SIZE) { + printk(KERN_ERR "vNIC BAR0 res hdr length error\n"); + return -EINVAL; + } + + rh = bar->vaddr; + if (!rh) { + printk(KERN_ERR "vNIC BAR0 res hdr not mem-mapped\n"); + return -EINVAL; + } + + if (ioread32(&rh->magic) != VNIC_RES_MAGIC || + ioread32(&rh->version) != VNIC_RES_VERSION) { + printk(KERN_ERR "vNIC BAR0 res magic/version error " + "exp (%lx/%lx) curr (%x/%x)\n", + VNIC_RES_MAGIC, VNIC_RES_VERSION, + ioread32(&rh->magic), ioread32(&rh->version)); + return -EINVAL; + } + + r = (struct vnic_resource __iomem *)(rh + 1); + + while ((type = ioread8(&r->type)) != RES_TYPE_EOL) { + + u8 bar_num = ioread8(&r->bar); + u32 bar_offset = ioread32(&r->bar_offset); + u32 count = ioread32(&r->count); + u32 len; + + r++; + + if (bar_num != 0) /* only mapping in BAR0 resources */ + continue; + + switch (type) { + case RES_TYPE_WQ: + case RES_TYPE_RQ: + case RES_TYPE_CQ: + case RES_TYPE_INTR_CTRL: + /* each count is stride bytes long */ + len = count * VNIC_RES_STRIDE; + if (len + bar_offset > bar->len) { + printk(KERN_ERR "vNIC BAR0 resource %d " + "out-of-bounds, offset 0x%x + " + "size 0x%x > bar len 0x%lx\n", + type, bar_offset, + len, + bar->len); + return -EINVAL; + } + break; + case RES_TYPE_INTR_PBA_LEGACY: + case RES_TYPE_DEVCMD: + len = count; + break; + default: + continue; + } + + vdev->res[type].count = count; + vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset; + } + + return 0; +} + +unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, + enum vnic_res_type type) +{ + return vdev->res[type].count; +} + +void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, + unsigned int index) +{ + if (!vdev->res[type].vaddr) + return NULL; + + switch (type) { + case RES_TYPE_WQ: + case RES_TYPE_RQ: + case RES_TYPE_CQ: + case RES_TYPE_INTR_CTRL: + return (char __iomem *)vdev->res[type].vaddr + + index * VNIC_RES_STRIDE; + default: + return (char __iomem *)vdev->res[type].vaddr; + } +} + +unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, + unsigned int desc_count, unsigned int desc_size) +{ + /* The base address of the desc rings must be 512 byte aligned. + * Descriptor count is aligned to groups of 32 descriptors. A + * count of 0 means the maximum 4096 descriptors. Descriptor + * size is aligned to 16 bytes. + */ + + unsigned int count_align = 32; + unsigned int desc_align = 16; + + ring->base_align = 512; + + if (desc_count == 0) + desc_count = 4096; + + ring->desc_count = ALIGN(desc_count, count_align); + + ring->desc_size = ALIGN(desc_size, desc_align); + + ring->size = ring->desc_count * ring->desc_size; + ring->size_unaligned = ring->size + ring->base_align; + + return ring->size_unaligned; +} + +void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring) +{ + memset(ring->descs, 0, ring->size); +} + +int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, + unsigned int desc_count, unsigned int desc_size) +{ + vnic_dev_desc_ring_size(ring, desc_count, desc_size); + + ring->descs_unaligned = pci_alloc_consistent(vdev->pdev, + ring->size_unaligned, + &ring->base_addr_unaligned); + + if (!ring->descs_unaligned) { + printk(KERN_ERR + "Failed to allocate ring (size=%d), aborting\n", + (int)ring->size); + return -ENOMEM; + } + + ring->base_addr = ALIGN(ring->base_addr_unaligned, + ring->base_align); + ring->descs = (u8 *)ring->descs_unaligned + + (ring->base_addr - ring->base_addr_unaligned); + + vnic_dev_clear_desc_ring(ring); + + ring->desc_avail = ring->desc_count - 1; + + return 0; +} + +void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring) +{ + if (ring->descs) { + pci_free_consistent(vdev->pdev, + ring->size_unaligned, + ring->descs_unaligned, + ring->base_addr_unaligned); + ring->descs = NULL; + } +} + +int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, + u64 *a0, u64 *a1, int wait) +{ + struct vnic_devcmd __iomem *devcmd = vdev->devcmd; + int delay; + u32 status; + int dev_cmd_err[] = { + /* convert from fw's version of error.h to host's version */ + 0, /* ERR_SUCCESS */ + EINVAL, /* ERR_EINVAL */ + EFAULT, /* ERR_EFAULT */ + EPERM, /* ERR_EPERM */ + EBUSY, /* ERR_EBUSY */ + }; + int err; + + status = ioread32(&devcmd->status); + if (status & STAT_BUSY) { + printk(KERN_ERR "Busy devcmd %d\n", _CMD_N(cmd)); + return -EBUSY; + } + + if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) { + writeq(*a0, &devcmd->args[0]); + writeq(*a1, &devcmd->args[1]); + wmb(); + } + + iowrite32(cmd, &devcmd->cmd); + + if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) + return 0; + + for (delay = 0; delay < wait; delay++) { + + udelay(100); + + status = ioread32(&devcmd->status); + if (!(status & STAT_BUSY)) { + + if (status & STAT_ERROR) { + err = dev_cmd_err[(int)readq(&devcmd->args[0])]; + printk(KERN_ERR "Error %d devcmd %d\n", + err, _CMD_N(cmd)); + return -err; + } + + if (_CMD_DIR(cmd) & _CMD_DIR_READ) { + rmb(); + *a0 = readq(&devcmd->args[0]); + *a1 = readq(&devcmd->args[1]); + } + + return 0; + } + } + + printk(KERN_ERR "Timedout devcmd %d\n", _CMD_N(cmd)); + return -ETIMEDOUT; +} + +int vnic_dev_fw_info(struct vnic_dev *vdev, + struct vnic_devcmd_fw_info **fw_info) +{ + u64 a0, a1 = 0; + int wait = 1000; + int err = 0; + + if (!vdev->fw_info) { + vdev->fw_info = pci_alloc_consistent(vdev->pdev, + sizeof(struct vnic_devcmd_fw_info), + &vdev->fw_info_pa); + if (!vdev->fw_info) + return -ENOMEM; + + a0 = vdev->fw_info_pa; + + /* only get fw_info once and cache it */ + err = vnic_dev_cmd(vdev, CMD_MCPU_FW_INFO, &a0, &a1, wait); + } + + *fw_info = vdev->fw_info; + + return err; +} + +int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, + void *value) +{ + u64 a0, a1; + int wait = 1000; + int err; + + a0 = offset; + a1 = size; + + err = vnic_dev_cmd(vdev, CMD_DEV_SPEC, &a0, &a1, wait); + + switch (size) { + case 1: *(u8 *)value = (u8)a0; break; + case 2: *(u16 *)value = (u16)a0; break; + case 4: *(u32 *)value = (u32)a0; break; + case 8: *(u64 *)value = a0; break; + default: BUG(); break; + } + + return err; +} + +int vnic_dev_stats_clear(struct vnic_dev *vdev) +{ + u64 a0 = 0, a1 = 0; + int wait = 1000; + return vnic_dev_cmd(vdev, CMD_STATS_CLEAR, &a0, &a1, wait); +} + +int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats) +{ + u64 a0, a1; + int wait = 1000; + + if (!vdev->stats) { + vdev->stats = pci_alloc_consistent(vdev->pdev, + sizeof(struct vnic_stats), &vdev->stats_pa); + if (!vdev->stats) + return -ENOMEM; + } + + *stats = vdev->stats; + a0 = vdev->stats_pa; + a1 = sizeof(struct vnic_stats); + + return vnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait); +} + +int vnic_dev_close(struct vnic_dev *vdev) +{ + u64 a0 = 0, a1 = 0; + int wait = 1000; + return vnic_dev_cmd(vdev, CMD_CLOSE, &a0, &a1, wait); +} + +int vnic_dev_enable(struct vnic_dev *vdev) +{ + u64 a0 = 0, a1 = 0; + int wait = 1000; + return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait); +} + +int vnic_dev_disable(struct vnic_dev *vdev) +{ + u64 a0 = 0, a1 = 0; + int wait = 1000; + return vnic_dev_cmd(vdev, CMD_DISABLE, &a0, &a1, wait); +} + +int vnic_dev_open(struct vnic_dev *vdev, int arg) +{ + u64 a0 = (u32)arg, a1 = 0; + int wait = 1000; + return vnic_dev_cmd(vdev, CMD_OPEN, &a0, &a1, wait); +} + +int vnic_dev_open_done(struct vnic_dev *vdev, int *done) +{ + u64 a0 = 0, a1 = 0; + int wait = 1000; + int err; + + *done = 0; + + err = vnic_dev_cmd(vdev, CMD_OPEN_STATUS, &a0, &a1, wait); + if (err) + return err; + + *done = (a0 == 0); + + return 0; +} + +int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg) +{ + u64 a0 = (u32)arg, a1 = 0; + int wait = 1000; + return vnic_dev_cmd(vdev, CMD_SOFT_RESET, &a0, &a1, wait); +} + +int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done) +{ + u64 a0 = 0, a1 = 0; + int wait = 1000; + int err; + + *done = 0; + + err = vnic_dev_cmd(vdev, CMD_SOFT_RESET_STATUS, &a0, &a1, wait); + if (err) + return err; + + *done = (a0 == 0); + + return 0; +} + +int vnic_dev_hang_notify(struct vnic_dev *vdev) +{ + u64 a0, a1; + int wait = 1000; + return vnic_dev_cmd(vdev, CMD_HANG_NOTIFY, &a0, &a1, wait); +} + +int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr) +{ + u64 a0, a1; + int wait = 1000; + int err, i; + + for (i = 0; i < ETH_ALEN; i++) + mac_addr[i] = 0; + + err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); + if (err) + return err; + + for (i = 0; i < ETH_ALEN; i++) + mac_addr[i] = ((u8 *)&a0)[i]; + + return 0; +} + +void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, + int broadcast, int promisc, int allmulti) +{ + u64 a0, a1 = 0; + int wait = 1000; + int err; + + a0 = (directed ? CMD_PFILTER_DIRECTED : 0) | + (multicast ? CMD_PFILTER_MULTICAST : 0) | + (broadcast ? CMD_PFILTER_BROADCAST : 0) | + (promisc ? CMD_PFILTER_PROMISCUOUS : 0) | + (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0); + + err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait); + if (err) + printk(KERN_ERR "Can't set packet filter\n"); +} + +void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) +{ + u64 a0 = 0, a1 = 0; + int wait = 1000; + int err; + int i; + + for (i = 0; i < ETH_ALEN; i++) + ((u8 *)&a0)[i] = addr[i]; + + err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); + if (err) + printk(KERN_ERR + "Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], + err); +} + +void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) +{ + u64 a0 = 0, a1 = 0; + int wait = 1000; + int err; + int i; + + for (i = 0; i < ETH_ALEN; i++) + ((u8 *)&a0)[i] = addr[i]; + + err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); + if (err) + printk(KERN_ERR + "Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], + err); +} + +int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) +{ + u64 a0, a1; + int wait = 1000; + + if (!vdev->notify) { + vdev->notify = pci_alloc_consistent(vdev->pdev, + sizeof(struct vnic_devcmd_notify), + &vdev->notify_pa); + if (!vdev->notify) + return -ENOMEM; + } + + a0 = vdev->notify_pa; + a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL; + a1 += sizeof(struct vnic_devcmd_notify); + + return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); +} + +void vnic_dev_notify_unset(struct vnic_dev *vdev) +{ + u64 a0, a1; + int wait = 1000; + + a0 = 0; /* paddr = 0 to unset notify buffer */ + a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */ + a1 += sizeof(struct vnic_devcmd_notify); + + vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); +} + +static int vnic_dev_notify_ready(struct vnic_dev *vdev) +{ + u32 *words; + unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4; + unsigned int i; + u32 csum; + + if (!vdev->notify) + return 0; + + do { + csum = 0; + memcpy(&vdev->notify_copy, vdev->notify, + sizeof(struct vnic_devcmd_notify)); + words = (u32 *)&vdev->notify_copy; + for (i = 1; i < nwords; i++) + csum += words[i]; + } while (csum != words[0]); + + return 1; +} + +int vnic_dev_init(struct vnic_dev *vdev, int arg) +{ + u64 a0 = (u32)arg, a1 = 0; + int wait = 1000; + return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); +} + +int vnic_dev_link_status(struct vnic_dev *vdev) +{ + if (vdev->linkstatus) + return *vdev->linkstatus; + + if (!vnic_dev_notify_ready(vdev)) + return 0; + + return vdev->notify_copy.link_state; +} + +u32 vnic_dev_port_speed(struct vnic_dev *vdev) +{ + if (!vnic_dev_notify_ready(vdev)) + return 0; + + return vdev->notify_copy.port_speed; +} + +u32 vnic_dev_msg_lvl(struct vnic_dev *vdev) +{ + if (!vnic_dev_notify_ready(vdev)) + return 0; + + return vdev->notify_copy.msglvl; +} + +u32 vnic_dev_mtu(struct vnic_dev *vdev) +{ + if (!vnic_dev_notify_ready(vdev)) + return 0; + + return vdev->notify_copy.mtu; +} + +void vnic_dev_set_intr_mode(struct vnic_dev *vdev, + enum vnic_dev_intr_mode intr_mode) +{ + vdev->intr_mode = intr_mode; +} + +enum vnic_dev_intr_mode vnic_dev_get_intr_mode( + struct vnic_dev *vdev) +{ + return vdev->intr_mode; +} + +void vnic_dev_unregister(struct vnic_dev *vdev) +{ + if (vdev) { + if (vdev->notify) + pci_free_consistent(vdev->pdev, + sizeof(struct vnic_devcmd_notify), + vdev->notify, + vdev->notify_pa); + if (vdev->linkstatus) + pci_free_consistent(vdev->pdev, + sizeof(u32), + vdev->linkstatus, + vdev->linkstatus_pa); + if (vdev->stats) + pci_free_consistent(vdev->pdev, + sizeof(struct vnic_dev), + vdev->stats, vdev->stats_pa); + if (vdev->fw_info) + pci_free_consistent(vdev->pdev, + sizeof(struct vnic_devcmd_fw_info), + vdev->fw_info, vdev->fw_info_pa); + kfree(vdev); + } +} + +struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, + void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar) +{ + if (!vdev) { + vdev = kzalloc(sizeof(struct vnic_dev), GFP_ATOMIC); + if (!vdev) + return NULL; + } + + vdev->priv = priv; + vdev->pdev = pdev; + + if (vnic_dev_discover_res(vdev, bar)) + goto err_out; + + vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); + if (!vdev->devcmd) + goto err_out; + + return vdev; + +err_out: + vnic_dev_unregister(vdev); + return NULL; +} + diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h new file mode 100644 index 00000000000..b9dc1821c80 --- /dev/null +++ b/drivers/net/enic/vnic_dev.h @@ -0,0 +1,120 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_DEV_H_ +#define _VNIC_DEV_H_ + +#include "vnic_resource.h" +#include "vnic_devcmd.h" + +#ifndef VNIC_PADDR_TARGET +#define VNIC_PADDR_TARGET 0x0000000000000000ULL +#endif + +#ifndef readq +static inline u64 readq(void __iomem *reg) +{ + return (((u64)readl(reg + 0x4UL) << 32) | + (u64)readl(reg)); +} + +static inline void writeq(u64 val, void __iomem *reg) +{ + writel(val & 0xffffffff, reg); + writel(val >> 32, reg + 0x4UL); +} +#endif + +enum vnic_dev_intr_mode { + VNIC_DEV_INTR_MODE_UNKNOWN, + VNIC_DEV_INTR_MODE_INTX, + VNIC_DEV_INTR_MODE_MSI, + VNIC_DEV_INTR_MODE_MSIX, +}; + +struct vnic_dev_bar { + void __iomem *vaddr; + dma_addr_t bus_addr; + unsigned long len; +}; + +struct vnic_dev_ring { + void *descs; + size_t size; + dma_addr_t base_addr; + size_t base_align; + void *descs_unaligned; + size_t size_unaligned; + dma_addr_t base_addr_unaligned; + unsigned int desc_size; + unsigned int desc_count; + unsigned int desc_avail; +}; + +struct vnic_dev; +struct vnic_stats; + +void *vnic_dev_priv(struct vnic_dev *vdev); +unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, + enum vnic_res_type type); +void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, + unsigned int index); +unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, + unsigned int desc_count, unsigned int desc_size); +void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring); +int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, + unsigned int desc_count, unsigned int desc_size); +void vnic_dev_free_desc_ring(struct vnic_dev *vdev, + struct vnic_dev_ring *ring); +int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, + u64 *a0, u64 *a1, int wait); +int vnic_dev_fw_info(struct vnic_dev *vdev, + struct vnic_devcmd_fw_info **fw_info); +int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, + void *value); +int vnic_dev_stats_clear(struct vnic_dev *vdev); +int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats); +int vnic_dev_hang_notify(struct vnic_dev *vdev); +void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, + int broadcast, int promisc, int allmulti); +void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr); +void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr); +int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr); +int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr); +void vnic_dev_notify_unset(struct vnic_dev *vdev); +int vnic_dev_link_status(struct vnic_dev *vdev); +u32 vnic_dev_port_speed(struct vnic_dev *vdev); +u32 vnic_dev_msg_lvl(struct vnic_dev *vdev); +u32 vnic_dev_mtu(struct vnic_dev *vdev); +int vnic_dev_close(struct vnic_dev *vdev); +int vnic_dev_enable(struct vnic_dev *vdev); +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_soft_reset(struct vnic_dev *vdev, int arg); +int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done); +void vnic_dev_set_intr_mode(struct vnic_dev *vdev, + enum vnic_dev_intr_mode intr_mode); +enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); +void vnic_dev_unregister(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); + +#endif /* _VNIC_DEV_H_ */ diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h new file mode 100644 index 00000000000..d8617a3373b --- /dev/null +++ b/drivers/net/enic/vnic_devcmd.h @@ -0,0 +1,282 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_DEVCMD_H_ +#define _VNIC_DEVCMD_H_ + +#define _CMD_NBITS 14 +#define _CMD_VTYPEBITS 10 +#define _CMD_FLAGSBITS 6 +#define _CMD_DIRBITS 2 + +#define _CMD_NMASK ((1 << _CMD_NBITS)-1) +#define _CMD_VTYPEMASK ((1 << _CMD_VTYPEBITS)-1) +#define _CMD_FLAGSMASK ((1 << _CMD_FLAGSBITS)-1) +#define _CMD_DIRMASK ((1 << _CMD_DIRBITS)-1) + +#define _CMD_NSHIFT 0 +#define _CMD_VTYPESHIFT (_CMD_NSHIFT+_CMD_NBITS) +#define _CMD_FLAGSSHIFT (_CMD_VTYPESHIFT+_CMD_VTYPEBITS) +#define _CMD_DIRSHIFT (_CMD_FLAGSSHIFT+_CMD_FLAGSBITS) + +/* + * Direction bits (from host perspective). + */ +#define _CMD_DIR_NONE 0U +#define _CMD_DIR_WRITE 1U +#define _CMD_DIR_READ 2U +#define _CMD_DIR_RW (_CMD_DIR_WRITE | _CMD_DIR_READ) + +/* + * Flag bits. + */ +#define _CMD_FLAGS_NONE 0U +#define _CMD_FLAGS_NOWAIT 1U + +/* + * vNIC type bits. + */ +#define _CMD_VTYPE_NONE 0U +#define _CMD_VTYPE_ENET 1U +#define _CMD_VTYPE_FC 2U +#define _CMD_VTYPE_SCSI 4U +#define _CMD_VTYPE_ALL (_CMD_VTYPE_ENET | _CMD_VTYPE_FC | _CMD_VTYPE_SCSI) + +/* + * Used to create cmds.. +*/ +#define _CMDCF(dir, flags, vtype, nr) \ + (((dir) << _CMD_DIRSHIFT) | \ + ((flags) << _CMD_FLAGSSHIFT) | \ + ((vtype) << _CMD_VTYPESHIFT) | \ + ((nr) << _CMD_NSHIFT)) +#define _CMDC(dir, vtype, nr) _CMDCF(dir, 0, vtype, nr) +#define _CMDCNW(dir, vtype, nr) _CMDCF(dir, _CMD_FLAGS_NOWAIT, vtype, nr) + +/* + * Used to decode cmds.. +*/ +#define _CMD_DIR(cmd) (((cmd) >> _CMD_DIRSHIFT) & _CMD_DIRMASK) +#define _CMD_FLAGS(cmd) (((cmd) >> _CMD_FLAGSSHIFT) & _CMD_FLAGSMASK) +#define _CMD_VTYPE(cmd) (((cmd) >> _CMD_VTYPESHIFT) & _CMD_VTYPEMASK) +#define _CMD_N(cmd) (((cmd) >> _CMD_NSHIFT) & _CMD_NMASK) + +enum vnic_devcmd_cmd { + CMD_NONE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_NONE, 0), + + /* mcpu fw info in mem: (u64)a0=paddr to struct vnic_devcmd_fw_info */ + CMD_MCPU_FW_INFO = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 1), + + /* dev-specific block member: + * in: (u16)a0=offset,(u8)a1=size + * out: a0=value */ + CMD_DEV_SPEC = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 2), + + /* stats clear */ + CMD_STATS_CLEAR = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 3), + + /* stats dump in mem: (u64)a0=paddr to stats area, + * (u16)a1=sizeof stats area */ + CMD_STATS_DUMP = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 4), + + /* set Rx packet filter: (u32)a0=filters (see CMD_PFILTER_*) */ + CMD_PACKET_FILTER = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 7), + + /* hang detection notification */ + CMD_HANG_NOTIFY = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8), + + /* MAC address in (u48)a0 */ + CMD_MAC_ADDR = _CMDC(_CMD_DIR_READ, + _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 9), + + /* disable/enable promisc mode: (u8)a0=0/1 */ +/***** XXX DEPRECATED *****/ + CMD_PROMISC_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 10), + + /* disable/enable all-multi mode: (u8)a0=0/1 */ +/***** XXX DEPRECATED *****/ + CMD_ALLMULTI_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 11), + + /* add addr from (u48)a0 */ + CMD_ADDR_ADD = _CMDCNW(_CMD_DIR_WRITE, + _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 12), + + /* del addr from (u48)a0 */ + CMD_ADDR_DEL = _CMDCNW(_CMD_DIR_WRITE, + _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 13), + + /* add VLAN id in (u16)a0 */ + CMD_VLAN_ADD = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 14), + + /* del VLAN id in (u16)a0 */ + CMD_VLAN_DEL = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 15), + + /* nic_cfg in (u32)a0 */ + CMD_NIC_CFG = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 16), + + /* union vnic_rss_key in mem: (u64)a0=paddr, (u16)a1=len */ + CMD_RSS_KEY = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 17), + + /* union vnic_rss_cpu in mem: (u64)a0=paddr, (u16)a1=len */ + CMD_RSS_CPU = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 18), + + /* initiate softreset */ + CMD_SOFT_RESET = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 19), + + /* softreset status: + * out: a0=0 reset complete, a0=1 reset in progress */ + CMD_SOFT_RESET_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 20), + + /* set struct vnic_devcmd_notify buffer in mem: + * in: + * (u64)a0=paddr to notify (set paddr=0 to unset) + * (u32)a1 & 0x00000000ffffffff=sizeof(struct vnic_devcmd_notify) + * (u16)a1 & 0x0000ffff00000000=intr num (-1 for no intr) + * out: + * (u32)a1 = effective size + */ + CMD_NOTIFY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 21), + + /* UNDI API: (u64)a0=paddr to s_PXENV_UNDI_ struct, + * (u8)a1=PXENV_UNDI_xxx */ + CMD_UNDI = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 22), + + /* initiate open sequence (u32)a0=flags (see CMD_OPENF_*) */ + CMD_OPEN = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 23), + + /* open status: + * out: a0=0 open complete, a0=1 open in progress */ + CMD_OPEN_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 24), + + /* close vnic */ + CMD_CLOSE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25), + + /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ + CMD_INIT = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), + + /* variant of CMD_INIT, with provisioning info + * (u64)a0=paddr of vnic_devcmd_provinfo + * (u32)a1=sizeof provision info */ + CMD_INIT_PROV_INFO = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 27), + + /* enable virtual link */ + CMD_ENABLE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28), + + /* disable virtual link */ + CMD_DISABLE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29), + + /* stats dump all vnics on uplink in mem: (u64)a0=paddr (u32)a1=uif */ + CMD_STATS_DUMP_ALL = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 30), + + /* init status: + * out: a0=0 init complete, a0=1 init in progress + * if a0=0, a1=errno */ + CMD_INIT_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 31), + + /* INT13 API: (u64)a0=paddr to vnic_int13_params struct + * (u8)a1=INT13_CMD_xxx */ + CMD_INT13 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_FC, 32), + + /* logical uplink enable/disable: (u64)a0: 0/1=disable/enable */ + CMD_LOGICAL_UPLINK = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 33), + + /* undo initialize of virtual link */ + CMD_DEINIT = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34), +}; + +/* flags for CMD_OPEN */ +#define CMD_OPENF_OPROM 0x1 /* open coming from option rom */ + +/* flags for CMD_INIT */ +#define CMD_INITF_DEFAULT_MAC 0x1 /* init with default mac addr */ + +/* flags for CMD_PACKET_FILTER */ +#define CMD_PFILTER_DIRECTED 0x01 +#define CMD_PFILTER_MULTICAST 0x02 +#define CMD_PFILTER_BROADCAST 0x04 +#define CMD_PFILTER_PROMISCUOUS 0x08 +#define CMD_PFILTER_ALL_MULTICAST 0x10 + +enum vnic_devcmd_status { + STAT_NONE = 0, + STAT_BUSY = 1 << 0, /* cmd in progress */ + STAT_ERROR = 1 << 1, /* last cmd caused error (code in a0) */ +}; + +enum vnic_devcmd_error { + ERR_SUCCESS = 0, + ERR_EINVAL = 1, + ERR_EFAULT = 2, + ERR_EPERM = 3, + ERR_EBUSY = 4, + ERR_ECMDUNKNOWN = 5, + ERR_EBADSTATE = 6, + ERR_ENOMEM = 7, + ERR_ETIMEDOUT = 8, + ERR_ELINKDOWN = 9, +}; + +struct vnic_devcmd_fw_info { + char fw_version[32]; + char fw_build[32]; + char hw_version[32]; + char hw_serial_number[32]; +}; + +struct vnic_devcmd_notify { + u32 csum; /* checksum over following words */ + + u32 link_state; /* link up == 1 */ + u32 port_speed; /* effective port speed (rate limit) */ + u32 mtu; /* MTU */ + u32 msglvl; /* requested driver msg lvl */ + u32 uif; /* uplink interface */ + u32 status; /* status bits (see VNIC_STF_*) */ + u32 error; /* error code (see ERR_*) for first ERR */ +}; +#define VNIC_STF_FATAL_ERR 0x0001 /* fatal fw error */ + +struct vnic_devcmd_provinfo { + u8 oui[3]; + u8 type; + u8 data[0]; +}; + +/* + * Writing cmd register causes STAT_BUSY to get set in status register. + * When cmd completes, STAT_BUSY will be cleared. + * + * If cmd completed successfully STAT_ERROR will be clear + * and args registers contain cmd-specific results. + * + * If cmd error, STAT_ERROR will be set and args[0] contains error code. + * + * status register is read-only. While STAT_BUSY is set, + * all other register contents are read-only. + */ + +/* Make sizeof(vnic_devcmd) a power-of-2 for I/O BAR. */ +#define VNIC_DEVCMD_NARGS 15 +struct vnic_devcmd { + u32 status; /* RO */ + u32 cmd; /* RW */ + u64 args[VNIC_DEVCMD_NARGS]; /* RW cmd args (little-endian) */ +}; + +#endif /* _VNIC_DEVCMD_H_ */ diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h new file mode 100644 index 00000000000..6332ac9391b --- /dev/null +++ b/drivers/net/enic/vnic_enet.h @@ -0,0 +1,47 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_ENIC_H_ +#define _VNIC_ENIC_H_ + +/* Device-specific region: enet configuration */ +struct vnic_enet_config { + u32 flags; + u32 wq_desc_count; + u32 rq_desc_count; + u16 mtu; + u16 intr_timer; + u8 intr_timer_type; + u8 intr_mode; + char devname[16]; +}; + +#define VENETF_TSO 0x1 /* TSO enabled */ +#define VENETF_LRO 0x2 /* LRO enabled */ +#define VENETF_RXCSUM 0x4 /* RX csum enabled */ +#define VENETF_TXCSUM 0x8 /* TX csum enabled */ +#define VENETF_RSS 0x10 /* RSS enabled */ +#define VENETF_RSSHASH_IPV4 0x20 /* Hash on IPv4 fields */ +#define VENETF_RSSHASH_TCPIPV4 0x40 /* Hash on TCP + IPv4 fields */ +#define VENETF_RSSHASH_IPV6 0x80 /* Hash on IPv6 fields */ +#define VENETF_RSSHASH_TCPIPV6 0x100 /* Hash on TCP + IPv6 fields */ +#define VENETF_RSSHASH_IPV6_EX 0x200 /* Hash on IPv6 extended fields */ +#define VENETF_RSSHASH_TCPIPV6_EX 0x400 /* Hash on TCP + IPv6 ext. fields */ + +#endif /* _VNIC_ENIC_H_ */ diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c new file mode 100644 index 00000000000..ddc38f8f465 --- /dev/null +++ b/drivers/net/enic/vnic_intr.c @@ -0,0 +1,62 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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/errno.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/delay.h> + +#include "vnic_dev.h" +#include "vnic_intr.h" + +void vnic_intr_free(struct vnic_intr *intr) +{ + intr->ctrl = NULL; +} + +int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, + unsigned int index) +{ + intr->index = index; + intr->vdev = vdev; + + intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index); + if (!intr->ctrl) { + printk(KERN_ERR "Failed to hook INTR[%d].ctrl resource\n", + index); + return -EINVAL; + } + + return 0; +} + +void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, + unsigned int coalescing_type, unsigned int mask_on_assertion) +{ + iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer); + iowrite32(coalescing_type, &intr->ctrl->coalescing_type); + iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion); + iowrite32(0, &intr->ctrl->int_credits); +} + +void vnic_intr_clean(struct vnic_intr *intr) +{ + iowrite32(0, &intr->ctrl->int_credits); +} diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h new file mode 100644 index 00000000000..ccc408116af --- /dev/null +++ b/drivers/net/enic/vnic_intr.h @@ -0,0 +1,92 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_INTR_H_ +#define _VNIC_INTR_H_ + +#include <linux/pci.h> + +#include "vnic_dev.h" + +#define VNIC_INTR_TIMER_MAX 0xffff + +#define VNIC_INTR_TIMER_TYPE_ABS 0 +#define VNIC_INTR_TIMER_TYPE_QUIET 1 + +/* Interrupt control */ +struct vnic_intr_ctrl { + u32 coalescing_timer; /* 0x00 */ + u32 pad0; + u32 coalescing_value; /* 0x08 */ + u32 pad1; + u32 coalescing_type; /* 0x10 */ + u32 pad2; + u32 mask_on_assertion; /* 0x18 */ + u32 pad3; + u32 mask; /* 0x20 */ + u32 pad4; + u32 int_credits; /* 0x28 */ + u32 pad5; + u32 int_credit_return; /* 0x30 */ + u32 pad6; +}; + +struct vnic_intr { + unsigned int index; + struct vnic_dev *vdev; + struct vnic_intr_ctrl __iomem *ctrl; /* memory-mapped */ +}; + +static inline void vnic_intr_unmask(struct vnic_intr *intr) +{ + iowrite32(0, &intr->ctrl->mask); +} + +static inline void vnic_intr_mask(struct vnic_intr *intr) +{ + iowrite32(1, &intr->ctrl->mask); +} + +static inline void vnic_intr_return_credits(struct vnic_intr *intr, + unsigned int credits, int unmask, int reset_timer) +{ +#define VNIC_INTR_UNMASK_SHIFT 16 +#define VNIC_INTR_RESET_TIMER_SHIFT 17 + + u32 int_credit_return = (credits & 0xffff) | + (unmask ? (1 << VNIC_INTR_UNMASK_SHIFT) : 0) | + (reset_timer ? (1 << VNIC_INTR_RESET_TIMER_SHIFT) : 0); + + iowrite32(int_credit_return, &intr->ctrl->int_credit_return); +} + +static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba) +{ + /* get and ack interrupt in one read (clear-and-ack-on-read) */ + return ioread32(legacy_pba); +} + +void vnic_intr_free(struct vnic_intr *intr); +int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, + unsigned int index); +void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, + unsigned int coalescing_type, unsigned int mask_on_assertion); +void vnic_intr_clean(struct vnic_intr *intr); + +#endif /* _VNIC_INTR_H_ */ diff --git a/drivers/net/enic/vnic_nic.h b/drivers/net/enic/vnic_nic.h new file mode 100644 index 00000000000..dadf26fae69 --- /dev/null +++ b/drivers/net/enic/vnic_nic.h @@ -0,0 +1,65 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_NIC_H_ +#define _VNIC_NIC_H_ + +#define NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD 0xffUL +#define NIC_CFG_RSS_DEFAULT_CPU_SHIFT 0 +#define NIC_CFG_RSS_HASH_TYPE (0xffUL << 8) +#define NIC_CFG_RSS_HASH_TYPE_MASK_FIELD 0xffUL +#define NIC_CFG_RSS_HASH_TYPE_SHIFT 8 +#define NIC_CFG_RSS_HASH_BITS (7UL << 16) +#define NIC_CFG_RSS_HASH_BITS_MASK_FIELD 7UL +#define NIC_CFG_RSS_HASH_BITS_SHIFT 16 +#define NIC_CFG_RSS_BASE_CPU (7UL << 19) +#define NIC_CFG_RSS_BASE_CPU_MASK_FIELD 7UL +#define NIC_CFG_RSS_BASE_CPU_SHIFT 19 +#define NIC_CFG_RSS_ENABLE (1UL << 22) +#define NIC_CFG_RSS_ENABLE_MASK_FIELD 1UL +#define NIC_CFG_RSS_ENABLE_SHIFT 22 +#define NIC_CFG_TSO_IPID_SPLIT_EN (1UL << 23) +#define NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD 1UL +#define NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT 23 +#define NIC_CFG_IG_VLAN_STRIP_EN (1UL << 24) +#define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD 1UL +#define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT 24 + +static inline void vnic_set_nic_cfg(u32 *nic_cfg, + u8 rss_default_cpu, u8 rss_hash_type, + u8 rss_hash_bits, u8 rss_base_cpu, + u8 rss_enable, u8 tso_ipid_split_en, + u8 ig_vlan_strip_en) +{ + *nic_cfg = (rss_default_cpu & NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD) | + ((rss_hash_type & NIC_CFG_RSS_HASH_TYPE_MASK_FIELD) + << NIC_CFG_RSS_HASH_TYPE_SHIFT) | + ((rss_hash_bits & NIC_CFG_RSS_HASH_BITS_MASK_FIELD) + << NIC_CFG_RSS_HASH_BITS_SHIFT) | + ((rss_base_cpu & NIC_CFG_RSS_BASE_CPU_MASK_FIELD) + << NIC_CFG_RSS_BASE_CPU_SHIFT) | + ((rss_enable & NIC_CFG_RSS_ENABLE_MASK_FIELD) + << NIC_CFG_RSS_ENABLE_SHIFT) | + ((tso_ipid_split_en & NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD) + << NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT) | + ((ig_vlan_strip_en & NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD) + << NIC_CFG_IG_VLAN_STRIP_EN_SHIFT); +} + +#endif /* _VNIC_NIC_H_ */ diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/enic/vnic_resource.h new file mode 100644 index 00000000000..144d2812f08 --- /dev/null +++ b/drivers/net/enic/vnic_resource.h @@ -0,0 +1,63 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_RESOURCE_H_ +#define _VNIC_RESOURCE_H_ + +#define VNIC_RES_MAGIC 0x766E6963L /* 'vnic' */ +#define VNIC_RES_VERSION 0x00000000L + +/* vNIC resource types */ +enum vnic_res_type { + RES_TYPE_EOL, /* End-of-list */ + RES_TYPE_WQ, /* Work queues */ + RES_TYPE_RQ, /* Receive queues */ + RES_TYPE_CQ, /* Completion queues */ + RES_TYPE_RSVD1, + RES_TYPE_NIC_CFG, /* Enet NIC config registers */ + RES_TYPE_RSVD2, + RES_TYPE_RSVD3, + RES_TYPE_RSVD4, + RES_TYPE_RSVD5, + RES_TYPE_INTR_CTRL, /* Interrupt ctrl table */ + RES_TYPE_INTR_TABLE, /* MSI/MSI-X Interrupt table */ + RES_TYPE_INTR_PBA, /* MSI/MSI-X PBA table */ + RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status, r2c */ + RES_TYPE_RSVD6, + RES_TYPE_RSVD7, + RES_TYPE_DEVCMD, /* Device command region */ + RES_TYPE_PASS_THRU_PAGE, /* Pass-thru page */ + + RES_TYPE_MAX, /* Count of resource types */ +}; + +struct vnic_resource_header { + u32 magic; + u32 version; +}; + +struct vnic_resource { + u8 type; + u8 bar; + u8 pad[2]; + u32 bar_offset; + u32 count; +}; + +#endif /* _VNIC_RESOURCE_H_ */ diff --git a/drivers/net/enic/vnic_rq.c b/drivers/net/enic/vnic_rq.c new file mode 100644 index 00000000000..9365e63e821 --- /dev/null +++ b/drivers/net/enic/vnic_rq.c @@ -0,0 +1,199 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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/errno.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/delay.h> + +#include "vnic_dev.h" +#include "vnic_rq.h" + +static int vnic_rq_alloc_bufs(struct vnic_rq *rq) +{ + struct vnic_rq_buf *buf; + struct vnic_dev *vdev; + unsigned int i, j, count = rq->ring.desc_count; + unsigned int blks = VNIC_RQ_BUF_BLKS_NEEDED(count); + + vdev = rq->vdev; + + for (i = 0; i < blks; i++) { + rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ, GFP_ATOMIC); + if (!rq->bufs[i]) { + printk(KERN_ERR "Failed to alloc rq_bufs\n"); + return -ENOMEM; + } + } + + for (i = 0; i < blks; i++) { + buf = rq->bufs[i]; + for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES; j++) { + buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES + j; + buf->desc = (u8 *)rq->ring.descs + + rq->ring.desc_size * buf->index; + if (buf->index + 1 == count) { + buf->next = rq->bufs[0]; + break; + } else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES) { + buf->next = rq->bufs[i + 1]; + } else { + buf->next = buf + 1; + buf++; + } + } + } + + rq->to_use = rq->to_clean = rq->bufs[0]; + rq->buf_index = 0; + + return 0; +} + +void vnic_rq_free(struct vnic_rq *rq) +{ + struct vnic_dev *vdev; + unsigned int i; + + vdev = rq->vdev; + + vnic_dev_free_desc_ring(vdev, &rq->ring); + + for (i = 0; i < VNIC_RQ_BUF_BLKS_MAX; i++) { + kfree(rq->bufs[i]); + rq->bufs[i] = NULL; + } + + rq->ctrl = NULL; +} + +int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, + unsigned int desc_count, unsigned int desc_size) +{ + int err; + + rq->index = index; + rq->vdev = vdev; + + rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index); + if (!rq->ctrl) { + printk(KERN_ERR "Failed to hook RQ[%d] resource\n", index); + return -EINVAL; + } + + vnic_rq_disable(rq); + + err = vnic_dev_alloc_desc_ring(vdev, &rq->ring, desc_count, desc_size); + if (err) + return err; + + err = vnic_rq_alloc_bufs(rq); + if (err) { + vnic_rq_free(rq); + return err; + } + + return 0; +} + +void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset) +{ + u64 paddr; + u32 fetch_index; + + paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET; + writeq(paddr, &rq->ctrl->ring_base); + iowrite32(rq->ring.desc_count, &rq->ctrl->ring_size); + iowrite32(cq_index, &rq->ctrl->cq_index); + iowrite32(error_interrupt_enable, &rq->ctrl->error_interrupt_enable); + iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset); + iowrite32(0, &rq->ctrl->dropped_packet_count); + iowrite32(0, &rq->ctrl->error_status); + + /* Use current fetch_index as the ring starting point */ + fetch_index = ioread32(&rq->ctrl->fetch_index); + rq->to_use = rq->to_clean = + &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES] + [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; + iowrite32(fetch_index, &rq->ctrl->posted_index); + + rq->buf_index = 0; +} + +unsigned int vnic_rq_error_status(struct vnic_rq *rq) +{ + return ioread32(&rq->ctrl->error_status); +} + +void vnic_rq_enable(struct vnic_rq *rq) +{ + iowrite32(1, &rq->ctrl->enable); +} + +int vnic_rq_disable(struct vnic_rq *rq) +{ + unsigned int wait; + + iowrite32(0, &rq->ctrl->enable); + + /* Wait for HW to ACK disable request */ + for (wait = 0; wait < 100; wait++) { + if (!(ioread32(&rq->ctrl->running))) + return 0; + udelay(1); + } + + printk(KERN_ERR "Failed to disable RQ[%d]\n", rq->index); + + return -ETIMEDOUT; +} + +void vnic_rq_clean(struct vnic_rq *rq, + void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf)) +{ + struct vnic_rq_buf *buf; + u32 fetch_index; + + BUG_ON(ioread32(&rq->ctrl->enable)); + + buf = rq->to_clean; + + while (vnic_rq_desc_used(rq) > 0) { + + (*buf_clean)(rq, buf); + + buf = rq->to_clean = buf->next; + rq->ring.desc_avail++; + } + + /* Use current fetch_index as the ring starting point */ + fetch_index = ioread32(&rq->ctrl->fetch_index); + rq->to_use = rq->to_clean = + &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES] + [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; + iowrite32(fetch_index, &rq->ctrl->posted_index); + + rq->buf_index = 0; + + vnic_dev_clear_desc_ring(&rq->ring); +} + diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h new file mode 100644 index 00000000000..82bfca67cc4 --- /dev/null +++ b/drivers/net/enic/vnic_rq.h @@ -0,0 +1,204 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_RQ_H_ +#define _VNIC_RQ_H_ + +#include <linux/pci.h> + +#include "vnic_dev.h" +#include "vnic_cq.h" + +/* Receive queue control */ +struct vnic_rq_ctrl { + u64 ring_base; /* 0x00 */ + u32 ring_size; /* 0x08 */ + u32 pad0; + u32 posted_index; /* 0x10 */ + u32 pad1; + u32 cq_index; /* 0x18 */ + u32 pad2; + u32 enable; /* 0x20 */ + u32 pad3; + u32 running; /* 0x28 */ + u32 pad4; + u32 fetch_index; /* 0x30 */ + u32 pad5; + u32 error_interrupt_enable; /* 0x38 */ + u32 pad6; + u32 error_interrupt_offset; /* 0x40 */ + u32 pad7; + u32 error_status; /* 0x48 */ + u32 pad8; + u32 dropped_packet_count; /* 0x50 */ + u32 pad9; + u32 dropped_packet_count_rc; /* 0x58 */ + u32 pad10; +}; + +/* Break the vnic_rq_buf allocations into blocks of 64 entries */ +#define VNIC_RQ_BUF_BLK_ENTRIES 64 +#define VNIC_RQ_BUF_BLK_SZ \ + (VNIC_RQ_BUF_BLK_ENTRIES * sizeof(struct vnic_rq_buf)) +#define VNIC_RQ_BUF_BLKS_NEEDED(entries) \ + DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES) +#define VNIC_RQ_BUF_BLKS_MAX VNIC_RQ_BUF_BLKS_NEEDED(4096) + +struct vnic_rq_buf { + struct vnic_rq_buf *next; + dma_addr_t dma_addr; + void *os_buf; + unsigned int os_buf_index; + unsigned int len; + unsigned int index; + void *desc; +}; + +struct vnic_rq { + unsigned int index; + struct vnic_dev *vdev; + struct vnic_rq_ctrl __iomem *ctrl; /* memory-mapped */ + struct vnic_dev_ring ring; + struct vnic_rq_buf *bufs[VNIC_RQ_BUF_BLKS_MAX]; + struct vnic_rq_buf *to_use; + struct vnic_rq_buf *to_clean; + void *os_buf_head; + unsigned int buf_index; + unsigned int pkts_outstanding; +}; + +static inline unsigned int vnic_rq_desc_avail(struct vnic_rq *rq) +{ + /* how many does SW own? */ + return rq->ring.desc_avail; +} + +static inline unsigned int vnic_rq_desc_used(struct vnic_rq *rq) +{ + /* how many does HW own? */ + return rq->ring.desc_count - rq->ring.desc_avail - 1; +} + +static inline void *vnic_rq_next_desc(struct vnic_rq *rq) +{ + return rq->to_use->desc; +} + +static inline unsigned int vnic_rq_next_index(struct vnic_rq *rq) +{ + return rq->to_use->index; +} + +static inline unsigned int vnic_rq_next_buf_index(struct vnic_rq *rq) +{ + return rq->buf_index++; +} + +static inline void vnic_rq_post(struct vnic_rq *rq, + void *os_buf, unsigned int os_buf_index, + dma_addr_t dma_addr, unsigned int len) +{ + struct vnic_rq_buf *buf = rq->to_use; + + buf->os_buf = os_buf; + buf->os_buf_index = os_buf_index; + buf->dma_addr = dma_addr; + buf->len = len; + + buf = buf->next; + rq->to_use = buf; + rq->ring.desc_avail--; + + /* Move the posted_index every nth descriptor + */ + +#ifndef VNIC_RQ_RETURN_RATE +#define VNIC_RQ_RETURN_RATE 0xf /* keep 2^n - 1 */ +#endif + + if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) + iowrite32(buf->index, &rq->ctrl->posted_index); +} + +static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) +{ + rq->ring.desc_avail += count; +} + +enum desc_return_options { + VNIC_RQ_RETURN_DESC, + VNIC_RQ_DEFER_RETURN_DESC, +}; + +static inline void vnic_rq_service(struct vnic_rq *rq, + struct cq_desc *cq_desc, u16 completed_index, + int desc_return, void (*buf_service)(struct vnic_rq *rq, + struct cq_desc *cq_desc, struct vnic_rq_buf *buf, + int skipped, void *opaque), void *opaque) +{ + struct vnic_rq_buf *buf; + int skipped; + + buf = rq->to_clean; + while (1) { + + skipped = (buf->index != completed_index); + + (*buf_service)(rq, cq_desc, buf, skipped, opaque); + + if (desc_return == VNIC_RQ_RETURN_DESC) + rq->ring.desc_avail++; + + rq->to_clean = buf->next; + + if (!skipped) + break; + + buf = rq->to_clean; + } +} + +static inline int vnic_rq_fill(struct vnic_rq *rq, + int (*buf_fill)(struct vnic_rq *rq)) +{ + int err; + + while (vnic_rq_desc_avail(rq) > 1) { + + err = (*buf_fill)(rq); + if (err) + return err; + } + + return 0; +} + +void vnic_rq_free(struct vnic_rq *rq); +int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, + unsigned int desc_count, unsigned int desc_size); +void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset); +unsigned int vnic_rq_error_status(struct vnic_rq *rq); +void vnic_rq_enable(struct vnic_rq *rq); +int vnic_rq_disable(struct vnic_rq *rq); +void vnic_rq_clean(struct vnic_rq *rq, + void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf)); + +#endif /* _VNIC_RQ_H_ */ diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/enic/vnic_rss.h new file mode 100644 index 00000000000..e325d65d7c3 --- /dev/null +++ b/drivers/net/enic/vnic_rss.h @@ -0,0 +1,32 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova Systems, Inc. All rights reserved. + */ + +#ifndef _VNIC_RSS_H_ +#define _VNIC_RSS_H_ + +/* RSS key array */ +union vnic_rss_key { + struct { + u8 b[10]; + u8 b_pad[6]; + } key[4]; + u64 raw[8]; +}; + +/* RSS cpu array */ +union vnic_rss_cpu { + struct { + u8 b[4] ; + u8 b_pad[4]; + } cpu[32]; + u64 raw[32]; +}; + +void vnic_set_rss_key(union vnic_rss_key *rss_key, u8 *key); +void vnic_set_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu); +void vnic_get_rss_key(union vnic_rss_key *rss_key, u8 *key); +void vnic_get_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu); + +#endif /* _VNIC_RSS_H_ */ diff --git a/drivers/net/enic/vnic_stats.h b/drivers/net/enic/vnic_stats.h new file mode 100644 index 00000000000..9ff9614d89b --- /dev/null +++ b/drivers/net/enic/vnic_stats.h @@ -0,0 +1,70 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_STATS_H_ +#define _VNIC_STATS_H_ + +/* Tx statistics */ +struct vnic_tx_stats { + u64 tx_frames_ok; + u64 tx_unicast_frames_ok; + u64 tx_multicast_frames_ok; + u64 tx_broadcast_frames_ok; + u64 tx_bytes_ok; + u64 tx_unicast_bytes_ok; + u64 tx_multicast_bytes_ok; + u64 tx_broadcast_bytes_ok; + u64 tx_drops; + u64 tx_errors; + u64 tx_tso; + u64 rsvd[16]; +}; + +/* Rx statistics */ +struct vnic_rx_stats { + u64 rx_frames_ok; + u64 rx_frames_total; + u64 rx_unicast_frames_ok; + u64 rx_multicast_frames_ok; + u64 rx_broadcast_frames_ok; + u64 rx_bytes_ok; + u64 rx_unicast_bytes_ok; + u64 rx_multicast_bytes_ok; + u64 rx_broadcast_bytes_ok; + u64 rx_drop; + u64 rx_no_bufs; + u64 rx_errors; + u64 rx_rss; + u64 rx_crc_errors; + u64 rx_frames_64; + u64 rx_frames_127; + u64 rx_frames_255; + u64 rx_frames_511; + u64 rx_frames_1023; + u64 rx_frames_1518; + u64 rx_frames_to_max; + u64 rsvd[16]; +}; + +struct vnic_stats { + struct vnic_tx_stats tx; + struct vnic_rx_stats rx; +}; + +#endif /* _VNIC_STATS_H_ */ diff --git a/drivers/net/enic/vnic_wq.c b/drivers/net/enic/vnic_wq.c new file mode 100644 index 00000000000..a576d04708e --- /dev/null +++ b/drivers/net/enic/vnic_wq.c @@ -0,0 +1,184 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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/errno.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/delay.h> + +#include "vnic_dev.h" +#include "vnic_wq.h" + +static int vnic_wq_alloc_bufs(struct vnic_wq *wq) +{ + struct vnic_wq_buf *buf; + struct vnic_dev *vdev; + unsigned int i, j, count = wq->ring.desc_count; + unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count); + + vdev = wq->vdev; + + for (i = 0; i < blks; i++) { + wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC); + if (!wq->bufs[i]) { + printk(KERN_ERR "Failed to alloc wq_bufs\n"); + return -ENOMEM; + } + } + + for (i = 0; i < blks; i++) { + buf = wq->bufs[i]; + for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES; j++) { + buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES + j; + buf->desc = (u8 *)wq->ring.descs + + wq->ring.desc_size * buf->index; + if (buf->index + 1 == count) { + buf->next = wq->bufs[0]; + break; + } else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES) { + buf->next = wq->bufs[i + 1]; + } else { + buf->next = buf + 1; + buf++; + } + } + } + + wq->to_use = wq->to_clean = wq->bufs[0]; + + return 0; +} + +void vnic_wq_free(struct vnic_wq *wq) +{ + struct vnic_dev *vdev; + unsigned int i; + + vdev = wq->vdev; + + vnic_dev_free_desc_ring(vdev, &wq->ring); + + for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) { + kfree(wq->bufs[i]); + wq->bufs[i] = NULL; + } + + wq->ctrl = NULL; +} + +int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, + unsigned int desc_count, unsigned int desc_size) +{ + int err; + + wq->index = index; + wq->vdev = vdev; + + wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index); + if (!wq->ctrl) { + printk(KERN_ERR "Failed to hook WQ[%d] resource\n", index); + return -EINVAL; + } + + vnic_wq_disable(wq); + + err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size); + if (err) + return err; + + err = vnic_wq_alloc_bufs(wq); + if (err) { + vnic_wq_free(wq); + return err; + } + + return 0; +} + +void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset) +{ + u64 paddr; + + paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET; + writeq(paddr, &wq->ctrl->ring_base); + iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size); + iowrite32(0, &wq->ctrl->fetch_index); + iowrite32(0, &wq->ctrl->posted_index); + iowrite32(cq_index, &wq->ctrl->cq_index); + iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); + iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); + iowrite32(0, &wq->ctrl->error_status); +} + +unsigned int vnic_wq_error_status(struct vnic_wq *wq) +{ + return ioread32(&wq->ctrl->error_status); +} + +void vnic_wq_enable(struct vnic_wq *wq) +{ + iowrite32(1, &wq->ctrl->enable); +} + +int vnic_wq_disable(struct vnic_wq *wq) +{ + unsigned int wait; + + iowrite32(0, &wq->ctrl->enable); + + /* Wait for HW to ACK disable request */ + for (wait = 0; wait < 100; wait++) { + if (!(ioread32(&wq->ctrl->running))) + return 0; + udelay(1); + } + + printk(KERN_ERR "Failed to disable WQ[%d]\n", wq->index); + + return -ETIMEDOUT; +} + +void vnic_wq_clean(struct vnic_wq *wq, + void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)) +{ + struct vnic_wq_buf *buf; + + BUG_ON(ioread32(&wq->ctrl->enable)); + + buf = wq->to_clean; + + while (vnic_wq_desc_used(wq) > 0) { + + (*buf_clean)(wq, buf); + + buf = wq->to_clean = buf->next; + wq->ring.desc_avail++; + } + + wq->to_use = wq->to_clean = wq->bufs[0]; + + iowrite32(0, &wq->ctrl->fetch_index); + iowrite32(0, &wq->ctrl->posted_index); + iowrite32(0, &wq->ctrl->error_status); + + vnic_dev_clear_desc_ring(&wq->ring); +} diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h new file mode 100644 index 00000000000..7081828d8a4 --- /dev/null +++ b/drivers/net/enic/vnic_wq.h @@ -0,0 +1,154 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _VNIC_WQ_H_ +#define _VNIC_WQ_H_ + +#include <linux/pci.h> + +#include "vnic_dev.h" +#include "vnic_cq.h" + +/* Work queue control */ +struct vnic_wq_ctrl { + u64 ring_base; /* 0x00 */ + u32 ring_size; /* 0x08 */ + u32 pad0; + u32 posted_index; /* 0x10 */ + u32 pad1; + u32 cq_index; /* 0x18 */ + u32 pad2; + u32 enable; /* 0x20 */ + u32 pad3; + u32 running; /* 0x28 */ + u32 pad4; + u32 fetch_index; /* 0x30 */ + u32 pad5; + u32 dca_value; /* 0x38 */ + u32 pad6; + u32 error_interrupt_enable; /* 0x40 */ + u32 pad7; + u32 error_interrupt_offset; /* 0x48 */ + u32 pad8; + u32 error_status; /* 0x50 */ + u32 pad9; +}; + +struct vnic_wq_buf { + struct vnic_wq_buf *next; + dma_addr_t dma_addr; + void *os_buf; + unsigned int len; + unsigned int index; + int sop; + void *desc; +}; + +/* Break the vnic_wq_buf allocations into blocks of 64 entries */ +#define VNIC_WQ_BUF_BLK_ENTRIES 64 +#define VNIC_WQ_BUF_BLK_SZ \ + (VNIC_WQ_BUF_BLK_ENTRIES * sizeof(struct vnic_wq_buf)) +#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \ + DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES) +#define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096) + +struct vnic_wq { + unsigned int index; + struct vnic_dev *vdev; + struct vnic_wq_ctrl __iomem *ctrl; /* memory-mapped */ + struct vnic_dev_ring ring; + struct vnic_wq_buf *bufs[VNIC_WQ_BUF_BLKS_MAX]; + struct vnic_wq_buf *to_use; + struct vnic_wq_buf *to_clean; + unsigned int pkts_outstanding; +}; + +static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq) +{ + /* how many does SW own? */ + return wq->ring.desc_avail; +} + +static inline unsigned int vnic_wq_desc_used(struct vnic_wq *wq) +{ + /* how many does HW own? */ + return wq->ring.desc_count - wq->ring.desc_avail - 1; +} + +static inline void *vnic_wq_next_desc(struct vnic_wq *wq) +{ + return wq->to_use->desc; +} + +static inline void vnic_wq_post(struct vnic_wq *wq, + void *os_buf, dma_addr_t dma_addr, + unsigned int len, int sop, int eop) +{ + struct vnic_wq_buf *buf = wq->to_use; + + buf->sop = sop; + buf->os_buf = eop ? os_buf : NULL; + buf->dma_addr = dma_addr; + buf->len = len; + + buf = buf->next; + if (eop) + iowrite32(buf->index, &wq->ctrl->posted_index); + wq->to_use = buf; + + wq->ring.desc_avail--; +} + +static inline void vnic_wq_service(struct vnic_wq *wq, + struct cq_desc *cq_desc, u16 completed_index, + void (*buf_service)(struct vnic_wq *wq, + struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque), + void *opaque) +{ + struct vnic_wq_buf *buf; + + buf = wq->to_clean; + while (1) { + + (*buf_service)(wq, cq_desc, buf, opaque); + + wq->ring.desc_avail++; + + wq->to_clean = buf->next; + + if (buf->index == completed_index) + break; + + buf = wq->to_clean; + } +} + +void vnic_wq_free(struct vnic_wq *wq); +int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, + unsigned int desc_count, unsigned int desc_size); +void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset); +unsigned int vnic_wq_error_status(struct vnic_wq *wq); +void vnic_wq_enable(struct vnic_wq *wq); +int vnic_wq_disable(struct vnic_wq *wq); +void vnic_wq_clean(struct vnic_wq *wq, + void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)); + +#endif /* _VNIC_WQ_H_ */ diff --git a/drivers/net/enic/wq_enet_desc.h b/drivers/net/enic/wq_enet_desc.h new file mode 100644 index 00000000000..483596c2d8b --- /dev/null +++ b/drivers/net/enic/wq_enet_desc.h @@ -0,0 +1,98 @@ +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova 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 _WQ_ENET_DESC_H_ +#define _WQ_ENET_DESC_H_ + +/* Ethernet work queue descriptor: 16B */ +struct wq_enet_desc { + __le64 address; + __le16 length; + __le16 mss_loopback; + __le16 header_length_flags; + __le16 vlan_tag; +}; + +#define WQ_ENET_ADDR_BITS 64 +#define WQ_ENET_LEN_BITS 14 +#define WQ_ENET_LEN_MASK ((1 << WQ_ENET_LEN_BITS) - 1) +#define WQ_ENET_MSS_BITS 14 +#define WQ_ENET_MSS_MASK ((1 << WQ_ENET_MSS_BITS) - 1) +#define WQ_ENET_MSS_SHIFT 2 +#define WQ_ENET_LOOPBACK_SHIFT 1 +#define WQ_ENET_HDRLEN_BITS 10 +#define WQ_ENET_HDRLEN_MASK ((1 << WQ_ENET_HDRLEN_BITS) - 1) +#define WQ_ENET_FLAGS_OM_BITS 2 +#define WQ_ENET_FLAGS_OM_MASK ((1 << WQ_ENET_FLAGS_OM_BITS) - 1) +#define WQ_ENET_FLAGS_EOP_SHIFT 12 +#define WQ_ENET_FLAGS_CQ_ENTRY_SHIFT 13 +#define WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT 14 +#define WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT 15 + +#define WQ_ENET_OFFLOAD_MODE_CSUM 0 +#define WQ_ENET_OFFLOAD_MODE_RESERVED 1 +#define WQ_ENET_OFFLOAD_MODE_CSUM_L4 2 +#define WQ_ENET_OFFLOAD_MODE_TSO 3 + +static inline void wq_enet_desc_enc(struct wq_enet_desc *desc, + u64 address, u16 length, u16 mss, u16 header_length, + u8 offload_mode, u8 eop, u8 cq_entry, u8 fcoe_encap, + u8 vlan_tag_insert, u16 vlan_tag, u8 loopback) +{ + desc->address = cpu_to_le64(address); + desc->length = cpu_to_le16(length & WQ_ENET_LEN_MASK); + desc->mss_loopback = cpu_to_le16((mss & WQ_ENET_MSS_MASK) << + WQ_ENET_MSS_SHIFT | (loopback & 1) << WQ_ENET_LOOPBACK_SHIFT); + desc->header_length_flags = cpu_to_le16( + (header_length & WQ_ENET_HDRLEN_MASK) | + (offload_mode & WQ_ENET_FLAGS_OM_MASK) << WQ_ENET_HDRLEN_BITS | + (eop & 1) << WQ_ENET_FLAGS_EOP_SHIFT | + (cq_entry & 1) << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT | + (fcoe_encap & 1) << WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT | + (vlan_tag_insert & 1) << WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT); + desc->vlan_tag = cpu_to_le16(vlan_tag); +} + +static inline void wq_enet_desc_dec(struct wq_enet_desc *desc, + u64 *address, u16 *length, u16 *mss, u16 *header_length, + u8 *offload_mode, u8 *eop, u8 *cq_entry, u8 *fcoe_encap, + u8 *vlan_tag_insert, u16 *vlan_tag, u8 *loopback) +{ + *address = le64_to_cpu(desc->address); + *length = le16_to_cpu(desc->length) & WQ_ENET_LEN_MASK; + *mss = (le16_to_cpu(desc->mss_loopback) >> WQ_ENET_MSS_SHIFT) & + WQ_ENET_MSS_MASK; + *loopback = (u8)((le16_to_cpu(desc->mss_loopback) >> + WQ_ENET_LOOPBACK_SHIFT) & 1); + *header_length = le16_to_cpu(desc->header_length_flags) & + WQ_ENET_HDRLEN_MASK; + *offload_mode = (u8)((le16_to_cpu(desc->header_length_flags) >> + WQ_ENET_HDRLEN_BITS) & WQ_ENET_FLAGS_OM_MASK); + *eop = (u8)((le16_to_cpu(desc->header_length_flags) >> + WQ_ENET_FLAGS_EOP_SHIFT) & 1); + *cq_entry = (u8)((le16_to_cpu(desc->header_length_flags) >> + WQ_ENET_FLAGS_CQ_ENTRY_SHIFT) & 1); + *fcoe_encap = (u8)((le16_to_cpu(desc->header_length_flags) >> + WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT) & 1); + *vlan_tag_insert = (u8)((le16_to_cpu(desc->header_length_flags) >> + WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT) & 1); + *vlan_tag = le16_to_cpu(desc->vlan_tag); +} + +#endif /* _WQ_ENET_DESC_H_ */ diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 3c1364de2b6..b455ae931f7 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -431,7 +431,7 @@ static void getlinktype(struct net_device *dev); static void getlinkstatus(struct net_device *dev); static void netdev_timer(unsigned long data); static void reset_timer(unsigned long data); -static void tx_timeout(struct net_device *dev); +static void fealnx_tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); @@ -658,7 +658,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = &tx_timeout; + dev->tx_timeout = &fealnx_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; err = register_netdev(dev); @@ -1198,7 +1198,7 @@ static void reset_timer(unsigned long data) } -static void tx_timeout(struct net_device *dev) +static void fealnx_tx_timeout(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->mem; diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index f5634447276..08e18bcb970 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -83,7 +83,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i int err; int i; - bus = kzalloc(sizeof(*bus), GFP_KERNEL); + bus = mdiobus_alloc(); if (bus == NULL) return -ENOMEM; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -127,7 +127,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); bus->priv = priv; - bus->dev = dev; + bus->parent = dev; dev_set_drvdata(dev, bus); /* set MII speed */ @@ -150,7 +150,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i irq_dispose_mapping(bus->irq[i]); kfree(bus->irq); kfree(priv); - kfree(bus); + mdiobus_free(bus); return err; } @@ -171,7 +171,7 @@ static int mpc52xx_fec_mdio_remove(struct of_device *of) irq_dispose_mapping(bus->irq[i]); kfree(priv); kfree(bus->irq); - kfree(bus); + mdiobus_free(bus); return 0; } diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 0b6ecef9a84..cc7328b1552 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -337,7 +337,7 @@ enum { NvRegMSIXIrqStatus = 0x3f0, NvRegPowerState2 = 0x600, -#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11 +#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F15 #define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 #define NVREG_POWERSTATE2_PHY_RESET 0x0004 }; @@ -5643,6 +5643,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll); + printk(KERN_DEBUG "nv_probe: set workaround bit for reversed mac addr\n"); } memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); @@ -5890,14 +5891,12 @@ static void nv_restore_phy(struct net_device *dev) } } -static void __devexit nv_remove(struct pci_dev *pci_dev) +static void nv_restore_mac_addr(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - unregister_netdev(dev); - /* special op: write back the misordered MAC address - otherwise * the next nv_probe would see a wrong address. */ @@ -5905,6 +5904,15 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) writel(np->orig_mac[1], base + NvRegMacAddrB); writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll); +} + +static void __devexit nv_remove(struct pci_dev *pci_dev) +{ + struct net_device *dev = pci_get_drvdata(pci_dev); + + unregister_netdev(dev); + + nv_restore_mac_addr(pci_dev); /* restore any phy related changes */ nv_restore_phy(dev); @@ -5975,6 +5983,8 @@ static void nv_shutdown(struct pci_dev *pdev) if (netif_running(dev)) nv_close(dev); + nv_restore_mac_addr(pdev); + pci_disable_device(pdev); if (system_state == SYSTEM_POWER_OFF) { if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled)) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 9d461825bf4..cb51c1fb033 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -664,23 +664,6 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static int fs_request_irq(struct net_device *dev, int irq, const char *name, - irq_handler_t irqf) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - (*fep->ops->pre_request_irq)(dev, irq); - return request_irq(irq, irqf, IRQF_SHARED, name, dev); -} - -static void fs_free_irq(struct net_device *dev, int irq) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - free_irq(irq, dev); - (*fep->ops->post_free_irq)(dev, irq); -} - static void fs_timeout(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); @@ -800,7 +783,8 @@ static int fs_enet_open(struct net_device *dev) napi_enable(&fep->napi); /* Install our interrupt handler. */ - r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); + r = request_irq(fep->interrupt, fs_enet_interrupt, IRQF_SHARED, + "fs_enet-mac", dev); if (r != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s Could not allocate FS_ENET IRQ!", dev->name); @@ -842,7 +826,7 @@ static int fs_enet_close(struct net_device *dev) /* release any irqs */ phy_disconnect(fep->phydev); fep->phydev = NULL; - fs_free_irq(dev, fep->interrupt); + free_irq(fep->interrupt, dev); return 0; } diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index db46d2e7232..85a4bab7f63 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -34,8 +34,6 @@ struct fs_ops { void (*adjust_link)(struct net_device *dev); void (*restart)(struct net_device *dev); void (*stop)(struct net_device *dev); - void (*pre_request_irq)(struct net_device *dev, int irq); - void (*post_free_irq)(struct net_device *dev, int irq); void (*napi_clear_rx_event)(struct net_device *dev); void (*napi_enable_rx)(struct net_device *dev); void (*napi_disable_rx)(struct net_device *dev); diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 1c7ef812a8e..22e5a847a58 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -421,16 +421,6 @@ static void stop(struct net_device *dev) fs_cleanup_bds(dev); } -static void pre_request_irq(struct net_device *dev, int irq) -{ - /* nothing */ -} - -static void post_free_irq(struct net_device *dev, int irq) -{ - /* nothing */ -} - static void napi_clear_rx_event(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); @@ -540,8 +530,6 @@ const struct fs_ops fs_fcc_ops = { .set_multicast_list = set_multicast_list, .restart = restart, .stop = stop, - .pre_request_irq = pre_request_irq, - .post_free_irq = post_free_irq, .napi_clear_rx_event = napi_clear_rx_event, .napi_enable_rx = napi_enable_rx, .napi_disable_rx = napi_disable_rx, diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 0a7d1c5c652..14e575313c8 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -313,11 +313,7 @@ static void restart(struct net_device *dev) * Clear any outstanding interrupt. */ FW(fecp, ievent, 0xffc0); -#ifndef CONFIG_PPC_MERGE - FW(fecp, ivec, (fep->interrupt / 2) << 29); -#else FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29); -#endif /* * adjust to speed (only for DUET & RMII) @@ -413,30 +409,6 @@ static void stop(struct net_device *dev) } } -static void pre_request_irq(struct net_device *dev, int irq) -{ -#ifndef CONFIG_PPC_MERGE - immap_t *immap = fs_enet_immap; - u32 siel; - - /* SIU interrupt */ - if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { - - siel = in_be32(&immap->im_siu_conf.sc_siel); - if ((irq & 1) == 0) - siel |= (0x80000000 >> irq); - else - siel &= ~(0x80000000 >> (irq & ~1)); - out_be32(&immap->im_siu_conf.sc_siel, siel); - } -#endif -} - -static void post_free_irq(struct net_device *dev, int irq) -{ - /* nothing */ -} - static void napi_clear_rx_event(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); @@ -529,8 +501,6 @@ const struct fs_ops fs_fec_ops = { .set_multicast_list = set_multicast_list, .restart = restart, .stop = stop, - .pre_request_irq = pre_request_irq, - .post_free_irq = post_free_irq, .napi_clear_rx_event = napi_clear_rx_event, .napi_enable_rx = napi_enable_rx, .napi_disable_rx = napi_disable_rx, diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index 22f50dd8b27..008cdd9cc53 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -377,30 +377,6 @@ static void stop(struct net_device *dev) fs_cleanup_bds(dev); } -static void pre_request_irq(struct net_device *dev, int irq) -{ -#ifndef CONFIG_PPC_MERGE - immap_t *immap = fs_enet_immap; - u32 siel; - - /* SIU interrupt */ - if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { - - siel = in_be32(&immap->im_siu_conf.sc_siel); - if ((irq & 1) == 0) - siel |= (0x80000000 >> irq); - else - siel &= ~(0x80000000 >> (irq & ~1)); - out_be32(&immap->im_siu_conf.sc_siel, siel); - } -#endif -} - -static void post_free_irq(struct net_device *dev, int irq) -{ - /* nothing */ -} - static void napi_clear_rx_event(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); @@ -494,8 +470,6 @@ const struct fs_ops fs_scc_ops = { .set_multicast_list = set_multicast_list, .restart = restart, .stop = stop, - .pre_request_irq = pre_request_irq, - .post_free_irq = post_free_irq, .napi_clear_rx_event = napi_clear_rx_event, .napi_enable_rx = napi_enable_rx, .napi_disable_rx = napi_disable_rx, diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index be4b72f4f49..49b6645d7e0 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -203,7 +203,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!strcmp(np->type, "ethernet-phy")) add_phy(new_bus, np); - new_bus->dev = &ofdev->dev; + new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); ret = mdiobus_register(new_bus); @@ -218,9 +218,9 @@ out_free_irqs: out_unmap_regs: iounmap(bitbang->dir); out_free_bus: - kfree(new_bus); -out_free_priv: free_mdio_bitbang(new_bus); +out_free_priv: + kfree(bitbang); out: return ret; } @@ -231,12 +231,11 @@ static int fs_enet_mdio_remove(struct of_device *ofdev) struct bb_info *bitbang = bus->priv; mdiobus_unregister(bus); - free_mdio_bitbang(bus); dev_set_drvdata(&ofdev->dev, NULL); kfree(bus->irq); + free_mdio_bitbang(bus); iounmap(bitbang->dir); kfree(bitbang); - kfree(bus); return 0; } diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 695f74cc439..28077cc1b94 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -128,7 +128,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, struct fec_info *fec; int ret = -ENOMEM, i; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + new_bus = mdiobus_alloc(); if (!new_bus) goto out; @@ -172,7 +172,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!strcmp(np->type, "ethernet-phy")) add_phy(new_bus, np); - new_bus->dev = &ofdev->dev; + new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); ret = mdiobus_register(new_bus); @@ -190,7 +190,7 @@ out_res: out_fec: kfree(fec); out_mii: - kfree(new_bus); + mdiobus_free(new_bus); out: return ret; } @@ -205,7 +205,7 @@ static int fs_enet_mdio_remove(struct of_device *ofdev) kfree(bus->irq); iounmap(fec->fecp); kfree(fec); - kfree(bus); + mdiobus_free(bus); return 0; } diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 4320a983a58..b5bb7ae2817 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -339,6 +339,9 @@ static int gfar_probe(struct platform_device *pdev) /* Enable most messages by default */ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; + /* Carrier starts down, phylib will bring it up */ + netif_carrier_off(dev); + err = register_netdev(dev); if (err) { diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index ebcfb27a904..bf73eea9801 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -136,12 +136,12 @@ static int gfar_mdio_reset(struct mii_bus *bus) /* Wait until the bus is free */ while ((gfar_read(®s->miimind) & MIIMIND_BUSY) && - timeout--) + --timeout) cpu_relax(); mutex_unlock(&bus->mdio_lock); - if(timeout <= 0) { + if(timeout == 0) { printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name); return -EBUSY; @@ -164,8 +164,7 @@ static int gfar_mdio_probe(struct device *dev) if (NULL == dev) return -EINVAL; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - + new_bus = mdiobus_alloc(); if (NULL == new_bus) return -ENOMEM; @@ -196,7 +195,7 @@ static int gfar_mdio_probe(struct device *dev) new_bus->irq = pdata->irq; - new_bus->dev = dev; + new_bus->parent = dev; dev_set_drvdata(dev, new_bus); /* @@ -211,19 +210,21 @@ static int gfar_mdio_probe(struct device *dev) gfar_write(&enet_regs->tbipa, 0); for (i = PHY_MAX_ADDR; i > 0; i--) { u32 phy_id; - int r; - r = get_phy_id(new_bus, i, &phy_id); - if (r) - return r; + err = get_phy_id(new_bus, i, &phy_id); + if (err) + goto bus_register_fail; if (phy_id == 0xffffffff) break; } /* The bus is full. We don't support using 31 PHYs, sorry */ - if (i == 0) - return -EBUSY; + if (i == 0) { + err = -EBUSY; + + goto bus_register_fail; + } gfar_write(&enet_regs->tbipa, i); @@ -240,7 +241,7 @@ static int gfar_mdio_probe(struct device *dev) bus_register_fail: iounmap(regs); reg_map_fail: - kfree(new_bus); + mdiobus_free(new_bus); return err; } @@ -256,7 +257,7 @@ static int gfar_mdio_remove(struct device *dev) iounmap((void __iomem *)bus->priv); bus->priv = NULL; - kfree(bus); + mdiobus_free(bus); return 0; } diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 8239939554b..fbbd3e660c2 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -139,7 +139,7 @@ static int __init do_hpp_probe(struct net_device *dev) #ifndef MODULE struct net_device * __init hp_plus_probe(int unit) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = alloc_eip_netdev(); int err; if (!dev) @@ -284,7 +284,7 @@ hpp_open(struct net_device *dev) int option_reg; int retval; - if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) { + if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) { return retval; } @@ -302,7 +302,7 @@ hpp_open(struct net_device *dev) /* Select the operational page. */ outw(Perf_Page, ioaddr + HP_PAGING); - ei_open(dev); + eip_open(dev); return 0; } @@ -313,7 +313,7 @@ hpp_close(struct net_device *dev) int option_reg = inw(ioaddr + HPP_OPTION); free_irq(dev->irq, dev); - ei_close(dev); + eip_close(dev); outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset, ioaddr + HPP_OPTION); diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig index 70a3272ee99..78a1628c989 100644 --- a/drivers/net/ibm_newemac/Kconfig +++ b/drivers/net/ibm_newemac/Kconfig @@ -1,6 +1,6 @@ config IBM_NEW_EMAC tristate "IBM EMAC Ethernet support" - depends on PPC_DCR && PPC_MERGE + depends on PPC_DCR select CRC32 help This driver supports the IBM EMAC family of Ethernet controllers @@ -62,3 +62,15 @@ config IBM_NEW_EMAC_TAH config IBM_NEW_EMAC_EMAC4 bool default n + +config IBM_NEW_EMAC_NO_FLOW_CTRL + bool + default n + +config IBM_NEW_EMAC_MAL_CLR_ICINTSTAT + bool + default n + +config IBM_NEW_EMAC_MAL_COMMON_ERR + bool + default n diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index ccd9d9058f6..efcf21c9f5c 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -130,6 +130,7 @@ static inline void emac_report_timeout_error(struct emac_instance *dev, const char *error) { if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX | + EMAC_FTR_460EX_PHY_CLK_FIX | EMAC_FTR_440EP_PHY_CLK_FIX)) DBG(dev, "%s" NL, error); else if (net_ratelimit()) @@ -201,13 +202,15 @@ static inline int emac_phy_supports_gige(int phy_mode) { return phy_mode == PHY_MODE_GMII || phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_SGMII || phy_mode == PHY_MODE_TBI || phy_mode == PHY_MODE_RTBI; } static inline int emac_phy_gpcs(int phy_mode) { - return phy_mode == PHY_MODE_TBI || + return phy_mode == PHY_MODE_SGMII || + phy_mode == PHY_MODE_TBI || phy_mode == PHY_MODE_RTBI; } @@ -351,10 +354,24 @@ static int emac_reset(struct emac_instance *dev) emac_tx_disable(dev); } +#ifdef CONFIG_PPC_DCR_NATIVE + /* Enable internal clock source */ + if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) + dcri_clrset(SDR0, SDR0_ETH_CFG, + 0, SDR0_ETH_CFG_ECS << dev->cell_index); +#endif + out_be32(&p->mr0, EMAC_MR0_SRST); while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) --n; +#ifdef CONFIG_PPC_DCR_NATIVE + /* Enable external clock source */ + if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) + dcri_clrset(SDR0, SDR0_ETH_CFG, + SDR0_ETH_CFG_ECS << dev->cell_index, 0); +#endif + if (n) { dev->reset_failed = 0; return 0; @@ -547,8 +564,9 @@ static int emac_configure(struct emac_instance *dev) switch (dev->phy.speed) { case SPEED_1000: if (emac_phy_gpcs(dev->phy.mode)) { - mr1 |= EMAC_MR1_MF_1000GPCS | - EMAC_MR1_MF_IPPA(dev->phy.address); + mr1 |= EMAC_MR1_MF_1000GPCS | EMAC_MR1_MF_IPPA( + (dev->phy.gpcs_address != 0xffffffff) ? + dev->phy.gpcs_address : dev->phy.address); /* Put some arbitrary OUI, Manuf & Rev IDs so we can * identify this GPCS PHY later. @@ -660,8 +678,12 @@ static int emac_configure(struct emac_instance *dev) out_be32(&p->iser, r); /* We need to take GPCS PHY out of isolate mode after EMAC reset */ - if (emac_phy_gpcs(dev->phy.mode)) - emac_mii_reset_phy(&dev->phy); + if (emac_phy_gpcs(dev->phy.mode)) { + if (dev->phy.gpcs_address != 0xffffffff) + emac_mii_reset_gpcs(&dev->phy); + else + emac_mii_reset_phy(&dev->phy); + } return 0; } @@ -866,7 +888,9 @@ static int emac_mdio_read(struct net_device *ndev, int id, int reg) struct emac_instance *dev = netdev_priv(ndev); int res; - res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev, + res = __emac_mdio_read((dev->mdio_instance && + dev->phy.gpcs_address != id) ? + dev->mdio_instance : dev, (u8) id, (u8) reg); return res; } @@ -875,7 +899,9 @@ static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) { struct emac_instance *dev = netdev_priv(ndev); - __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev, + __emac_mdio_write((dev->mdio_instance && + dev->phy.gpcs_address != id) ? + dev->mdio_instance : dev, (u8) id, (u8) reg, (u16) val); } @@ -2367,7 +2393,11 @@ static int __devinit emac_init_phy(struct emac_instance *dev) * XXX I probably should move these settings to the dev tree */ dev->phy.address = -1; - dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; + dev->phy.features = SUPPORTED_MII; + if (emac_phy_supports_gige(dev->phy_mode)) + dev->phy.features |= SUPPORTED_1000baseT_Full; + else + dev->phy.features |= SUPPORTED_100baseT_Full; dev->phy.pause = 1; return 0; @@ -2406,7 +2436,9 @@ static int __devinit emac_init_phy(struct emac_instance *dev) * Note that the busy_phy_map is currently global * while it should probably be per-ASIC... */ - dev->phy.address = dev->cell_index; + dev->phy.gpcs_address = dev->gpcs_address; + if (dev->phy.gpcs_address == 0xffffffff) + dev->phy.address = dev->cell_index; } emac_configure(dev); @@ -2516,6 +2548,8 @@ static int __devinit emac_init_config(struct emac_instance *dev) dev->phy_address = 0xffffffff; if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0)) dev->phy_map = 0xffffffff; + if (emac_read_uint_prop(np, "gpcs-address", &dev->gpcs_address, 0)) + dev->gpcs_address = 0xffffffff; if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1)) return -ENXIO; if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0)) @@ -2559,6 +2593,9 @@ static int __devinit emac_init_config(struct emac_instance *dev) /* Check EMAC version */ if (of_device_is_compatible(np, "ibm,emac4sync")) { dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC); + if (of_device_is_compatible(np, "ibm,emac-460ex") || + of_device_is_compatible(np, "ibm,emac-460gt")) + dev->features |= EMAC_FTR_460EX_PHY_CLK_FIX; } else if (of_device_is_compatible(np, "ibm,emac4")) { dev->features |= EMAC_FTR_EMAC4; if (of_device_is_compatible(np, "ibm,emac-440gx")) @@ -2567,6 +2604,8 @@ static int __devinit emac_init_config(struct emac_instance *dev) if (of_device_is_compatible(np, "ibm,emac-440ep") || of_device_is_compatible(np, "ibm,emac-440gr")) dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX; + if (of_device_is_compatible(np, "ibm,emac-405ez")) + dev->features |= EMAC_FTR_NO_FLOW_CONTROL_40x; } /* Fixup some feature bits based on the device tree */ @@ -2824,6 +2863,9 @@ static int __devinit emac_probe(struct of_device *ofdev, ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + if (dev->phy_mode == PHY_MODE_SGMII) + printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name); + if (dev->phy.address >= 0) printk("%s: found %s PHY (0x%02x)\n", ndev->name, dev->phy.def->name, dev->phy.address); diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h index 6545e69d12c..18d56c6c423 100644 --- a/drivers/net/ibm_newemac/core.h +++ b/drivers/net/ibm_newemac/core.h @@ -190,6 +190,9 @@ struct emac_instance { struct delayed_work link_work; int link_polling; + /* GPCS PHY infos */ + u32 gpcs_address; + /* Shared MDIO if any */ u32 mdio_ph; struct of_device *mdio_dev; @@ -317,6 +320,10 @@ struct emac_instance { * The 405EX and 460EX contain the EMAC4SYNC core */ #define EMAC_FTR_EMAC4SYNC 0x00000200 +/* + * Set if we need phy clock workaround for 460ex or 460gt + */ +#define EMAC_FTR_460EX_PHY_CLK_FIX 0x00000400 /* Right now, we don't quite handle the always/possible masks on the @@ -341,6 +348,10 @@ enum { #ifdef CONFIG_IBM_NEW_EMAC_RGMII EMAC_FTR_HAS_RGMII | #endif +#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL + EMAC_FTR_NO_FLOW_CONTROL_40x | +#endif + EMAC_FTR_460EX_PHY_CLK_FIX | EMAC_FTR_440EP_PHY_CLK_FIX, }; diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index 10c267b2b96..1839d3f154a 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c @@ -28,6 +28,7 @@ #include <linux/delay.h> #include "core.h" +#include <asm/dcr-regs.h> static int mal_count; @@ -279,6 +280,10 @@ static irqreturn_t mal_txeob(int irq, void *dev_instance) mal_schedule_poll(mal); set_mal_dcrn(mal, MAL_TXEOBISR, r); + if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT)) + mtdcri(SDR0, DCRN_SDR_ICINTSTAT, + (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICTX)); + return IRQ_HANDLED; } @@ -293,6 +298,10 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance) mal_schedule_poll(mal); set_mal_dcrn(mal, MAL_RXEOBISR, r); + if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT)) + mtdcri(SDR0, DCRN_SDR_ICINTSTAT, + (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICRX)); + return IRQ_HANDLED; } @@ -336,6 +345,25 @@ static irqreturn_t mal_rxde(int irq, void *dev_instance) return IRQ_HANDLED; } +static irqreturn_t mal_int(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + u32 esr = get_mal_dcrn(mal, MAL_ESR); + + if (esr & MAL_ESR_EVB) { + /* descriptor error */ + if (esr & MAL_ESR_DE) { + if (esr & MAL_ESR_CIDT) + return mal_rxde(irq, dev_instance); + else + return mal_txde(irq, dev_instance); + } else { /* SERR */ + return mal_serr(irq, dev_instance); + } + } + return IRQ_HANDLED; +} + void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac) { /* Spinlock-type semantics: only one caller disable poll at a time */ @@ -493,6 +521,8 @@ static int __devinit mal_probe(struct of_device *ofdev, unsigned int dcr_base; const u32 *prop; u32 cfg; + unsigned long irqflags; + irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde; mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL); if (!mal) { @@ -542,11 +572,21 @@ static int __devinit mal_probe(struct of_device *ofdev, goto fail; } + if (of_device_is_compatible(ofdev->node, "ibm,mcmal-405ez")) + mal->features |= (MAL_FTR_CLEAR_ICINTSTAT | + MAL_FTR_COMMON_ERR_INT); + mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0); mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1); mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2); - mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3); - mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4); + + if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) { + mal->txde_irq = mal->rxde_irq = mal->serr_irq; + } else { + mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3); + mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4); + } + if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ || mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ || mal->rxde_irq == NO_IRQ) { @@ -608,16 +648,26 @@ static int __devinit mal_probe(struct of_device *ofdev, sizeof(struct mal_descriptor) * mal_rx_bd_offset(mal, i)); - err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal); + if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) { + irqflags = IRQF_SHARED; + hdlr_serr = hdlr_txde = hdlr_rxde = mal_int; + } else { + irqflags = 0; + hdlr_serr = mal_serr; + hdlr_txde = mal_txde; + hdlr_rxde = mal_rxde; + } + + err = request_irq(mal->serr_irq, hdlr_serr, irqflags, "MAL SERR", mal); if (err) goto fail2; - err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal); + err = request_irq(mal->txde_irq, hdlr_txde, irqflags, "MAL TX DE", mal); if (err) goto fail3; err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); if (err) goto fail4; - err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); + err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags, "MAL RX DE", mal); if (err) goto fail5; err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h index eaa7262dc07..2f0a8736084 100644 --- a/drivers/net/ibm_newemac/mal.h +++ b/drivers/net/ibm_newemac/mal.h @@ -102,7 +102,7 @@ /* MAL V1 IER bits */ #define MAL1_IER_NWE 0x00000008 #define MAL1_IER_SOC_EVENTS MAL1_IER_NWE -#define MAL1_IER_EVENTS (MAL1_IER_SOC_EVENTS | MAL_IER_OTE | \ +#define MAL1_IER_EVENTS (MAL1_IER_SOC_EVENTS | MAL_IER_DE | \ MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) /* MAL V2 IER bits */ @@ -110,7 +110,7 @@ #define MAL2_IER_PRE 0x00000040 #define MAL2_IER_PWE 0x00000020 #define MAL2_IER_SOC_EVENTS (MAL2_IER_PT | MAL2_IER_PRE | MAL2_IER_PWE) -#define MAL2_IER_EVENTS (MAL2_IER_SOC_EVENTS | MAL_IER_OTE | \ +#define MAL2_IER_EVENTS (MAL2_IER_SOC_EVENTS | MAL_IER_DE | \ MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) @@ -213,6 +213,8 @@ struct mal_instance { struct of_device *ofdev; int index; spinlock_t lock; + + unsigned int features; }; static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg) @@ -225,6 +227,38 @@ static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val) dcr_write(mal->dcr_host, reg, val); } +/* Features of various MAL implementations */ + +/* Set if you have interrupt coalescing and you have to clear the SDR + * register for TXEOB and RXEOB interrupts to work + */ +#define MAL_FTR_CLEAR_ICINTSTAT 0x00000001 + +/* Set if your MAL has SERR, TXDE, and RXDE OR'd into a single UIC + * interrupt + */ +#define MAL_FTR_COMMON_ERR_INT 0x00000002 + +enum { + MAL_FTRS_ALWAYS = 0, + + MAL_FTRS_POSSIBLE = +#ifdef CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT + MAL_FTR_CLEAR_ICINTSTAT | +#endif +#ifdef CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR + MAL_FTR_COMMON_ERR_INT | +#endif + 0, +}; + +static inline int mal_has_feature(struct mal_instance *dev, + unsigned long feature) +{ + return (MAL_FTRS_ALWAYS & feature) || + (MAL_FTRS_POSSIBLE & dev->features & feature); +} + /* Register MAL devices */ int mal_init(void); void mal_exit(void); diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c index 37bfeea8788..c40cd8df221 100644 --- a/drivers/net/ibm_newemac/phy.c +++ b/drivers/net/ibm_newemac/phy.c @@ -38,6 +38,16 @@ static inline void phy_write(struct mii_phy *phy, int reg, int val) phy->mdio_write(phy->dev, phy->address, reg, val); } +static inline int gpcs_phy_read(struct mii_phy *phy, int reg) +{ + return phy->mdio_read(phy->dev, phy->gpcs_address, reg); +} + +static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val) +{ + phy->mdio_write(phy->dev, phy->gpcs_address, reg, val); +} + int emac_mii_reset_phy(struct mii_phy *phy) { int val; @@ -62,6 +72,37 @@ int emac_mii_reset_phy(struct mii_phy *phy) return limit <= 0; } +int emac_mii_reset_gpcs(struct mii_phy *phy) +{ + int val; + int limit = 10000; + + val = gpcs_phy_read(phy, MII_BMCR); + val &= ~(BMCR_ISOLATE | BMCR_ANENABLE); + val |= BMCR_RESET; + gpcs_phy_write(phy, MII_BMCR, val); + + udelay(300); + + while (limit--) { + val = gpcs_phy_read(phy, MII_BMCR); + if (val >= 0 && (val & BMCR_RESET) == 0) + break; + udelay(10); + } + if ((val & BMCR_ISOLATE) && limit > 0) + gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); + + if (limit > 0 && phy->mode == PHY_MODE_SGMII) { + /* Configure GPCS interface to recommended setting for SGMII */ + gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */ + gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */ + gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX */ + } + + return limit <= 0; +} + static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) { int ctl, adv; @@ -321,7 +362,7 @@ static struct mii_phy_def bcm5248_phy_def = { static int m88e1111_init(struct mii_phy *phy) { - pr_debug("%s: Marvell 88E1111 Ethernet\n", __FUNCTION__); + pr_debug("%s: Marvell 88E1111 Ethernet\n", __func__); phy_write(phy, 0x14, 0x0ce3); phy_write(phy, 0x18, 0x4101); phy_write(phy, 0x09, 0x0e00); @@ -332,6 +373,33 @@ static int m88e1111_init(struct mii_phy *phy) return 0; } +static int m88e1112_init(struct mii_phy *phy) +{ + /* + * Marvell 88E1112 PHY needs to have the SGMII MAC + * interace (page 2) properly configured to + * communicate with the 460EX/GT GPCS interface. + */ + + u16 reg_short; + + pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__); + + /* Set access to Page 2 */ + phy_write(phy, 0x16, 0x0002); + + phy_write(phy, 0x00, 0x0040); /* 1Gbps */ + reg_short = (u16)(phy_read(phy, 0x1a)); + reg_short |= 0x8000; /* bypass Auto-Negotiation */ + phy_write(phy, 0x1a, reg_short); + emac_mii_reset_phy(phy); /* reset MAC interface */ + + /* Reset access to Page 0 */ + phy_write(phy, 0x16, 0x0000); + + return 0; +} + static int et1011c_init(struct mii_phy *phy) { u16 reg_short; @@ -384,11 +452,27 @@ static struct mii_phy_def m88e1111_phy_def = { .ops = &m88e1111_phy_ops, }; +static struct mii_phy_ops m88e1112_phy_ops = { + .init = m88e1112_init, + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link +}; + +static struct mii_phy_def m88e1112_phy_def = { + .phy_id = 0x01410C90, + .phy_id_mask = 0x0ffffff0, + .name = "Marvell 88E1112 Ethernet", + .ops = &m88e1112_phy_ops, +}; + static struct mii_phy_def *mii_phy_table[] = { &et1011c_phy_def, &cis8201_phy_def, &bcm5248_phy_def, &m88e1111_phy_def, + &m88e1112_phy_def, &genmii_phy_def, NULL }; diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h index 1b65c81f655..5d2bf4cbe50 100644 --- a/drivers/net/ibm_newemac/phy.h +++ b/drivers/net/ibm_newemac/phy.h @@ -57,6 +57,7 @@ struct mii_phy { or determined automaticaly */ int address; /* PHY address */ int mode; /* PHY mode */ + int gpcs_address; /* GPCS PHY address */ /* 1: autoneg enabled, 0: disabled */ int autoneg; @@ -81,5 +82,6 @@ struct mii_phy { */ int emac_mii_phy_probe(struct mii_phy *phy, int address); int emac_mii_reset_phy(struct mii_phy *phy); +int emac_mii_reset_gpcs(struct mii_phy *phy); #endif /* __IBM_NEWEMAC_PHY_H */ diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 95e3464068d..f02764725a2 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -71,7 +71,7 @@ History: June 1st, 2000 corrected version codes, added support for the latest 2.3 changes Oct 28th, 2002 - cleaned up for the 2.5 tree <alan@redhat.com> + cleaned up for the 2.5 tree <alan@lxorguk.ukuu.org.uk> *************************************************************************/ diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 634c4c9d87b..93d02efa9a0 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3563,10 +3563,6 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) struct net_device *netdev = adapter->netdev; int work_done = 0; - /* Keep link state information with original netdev */ - if (!netif_carrier_ok(netdev)) - goto quit_polling; - #ifdef CONFIG_DCA if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_rx_dca(rx_ring); @@ -3576,7 +3572,6 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) /* If not enough Rx work done, exit the polling mode */ if ((work_done == 0) || !netif_running(netdev)) { -quit_polling: netif_rx_complete(netdev, napi); if (adapter->itr_setting & 3) { @@ -3617,16 +3612,14 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring) unsigned int i; u32 head, oldhead; unsigned int count = 0; - bool cleaned = false; - bool retval = true; unsigned int total_bytes = 0, total_packets = 0; + bool retval = true; rmb(); head = get_head(tx_ring); i = tx_ring->next_to_clean; while (1) { while (i != head) { - cleaned = true; tx_desc = E1000_TX_DESC(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; skb = buffer_info->skb; @@ -3643,7 +3636,6 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring) } igb_unmap_and_free_tx_resource(adapter, buffer_info); - tx_desc->upper.data = 0; i++; if (i == tx_ring->count) @@ -3665,7 +3657,7 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring) done_cleaning: tx_ring->next_to_clean = i; - if (unlikely(cleaned && + if (unlikely(count && netif_carrier_ok(netdev) && IGB_DESC_UNUSED(tx_ring) >= IGB_TX_QUEUE_WAKE)) { /* Make sure that anybody stopping the queue after this diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index 73fe83be34f..e1429fc6d05 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -540,7 +540,8 @@ static int kingsun_probe(struct usb_interface *intf, if (ret != 0) goto free_mem; - info("IrDA: Registered KingSun/DonShine device %s", net->name); + dev_info(&net->dev, "IrDA: Registered KingSun/DonShine device %s\n", + net->name); usb_set_intfdata(intf, kingsun); diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index 8c257a51341..2482d61662a 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -801,7 +801,8 @@ static int ks959_probe(struct usb_interface *intf, if (ret != 0) goto free_mem; - info("IrDA: Registered KingSun KS-959 device %s", net->name); + dev_info(&net->dev, "IrDA: Registered KingSun KS-959 device %s\n", + net->name); usb_set_intfdata(intf, kingsun); diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index d01a28593ce..1e0de93fd61 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -705,7 +705,8 @@ static int ksdazzle_probe(struct usb_interface *intf, if (ret != 0) goto free_mem; - info("IrDA: Registered KingSun/Dazzle device %s", net->name); + dev_info(&net->dev, "IrDA: Registered KingSun/Dazzle device %s\n", + net->name); usb_set_intfdata(intf, kingsun); diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 4aa61a1a3d5..c5b02b66f75 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -572,8 +572,8 @@ static void pxa_irda_startup(struct pxa_irda *si) ICCR2 = ICCR2_TXP | ICCR2_TRIG_32; /* configure DMAC */ - DRCMR17 = si->rxdma | DRCMR_MAPVLD; - DRCMR18 = si->txdma | DRCMR_MAPVLD; + DRCMR(17) = si->rxdma | DRCMR_MAPVLD; + DRCMR(18) = si->txdma | DRCMR_MAPVLD; /* force SIR reinitialization */ si->speed = 4000000; @@ -602,8 +602,8 @@ static void pxa_irda_shutdown(struct pxa_irda *si) /* disable the STUART or FICP clocks */ pxa_irda_disable_clk(si); - DRCMR17 = 0; - DRCMR18 = 0; + DRCMR(17) = 0; + DRCMR(18) = 0; local_irq_restore(flags); diff --git a/drivers/net/irda/sir_dongle.c b/drivers/net/irda/sir_dongle.c index 36030241f7a..2a9930e6e2a 100644 --- a/drivers/net/irda/sir_dongle.c +++ b/drivers/net/irda/sir_dongle.c @@ -67,9 +67,7 @@ int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type) const struct dongle_driver *drv = NULL; int err = -EINVAL; -#ifdef CONFIG_KMOD request_module("irda-dongle-%d", type); -#endif if (dev->dongle_drv != NULL) return -EBUSY; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 05196378274..3575804fd7c 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -506,7 +506,7 @@ static int change_speed(struct stir_cb *stir, unsigned speed) goto found; } - warn("%s: invalid speed %d", stir->netdev->name, speed); + dev_warn(&stir->netdev->dev, "invalid speed %d\n", speed); return -EINVAL; found: @@ -598,8 +598,8 @@ static int fifo_txwait(struct stir_cb *stir, int space) err = read_reg(stir, REG_FIFOCTL, stir->fifo_status, FIFO_REGS_SIZE); if (unlikely(err != FIFO_REGS_SIZE)) { - warn("%s: FIFO register read error: %d", - stir->netdev->name, err); + dev_warn(&stir->netdev->dev, + "FIFO register read error: %d\n", err); return err; } @@ -783,8 +783,9 @@ static int stir_transmit_thread(void *arg) if (unlikely(receive_start(stir))) { if (net_ratelimit()) - info("%s: receive usb submit failed", - stir->netdev->name); + dev_info(&dev->dev, + "%s: receive usb submit failed\n", + stir->netdev->name); stir->receiving = 0; msleep(10); continue; @@ -836,8 +837,8 @@ static void stir_rcv_irq(struct urb *urb) /* in case of error, the kernel thread will restart us */ if (err) { - warn("%s: usb receive submit error: %d", - stir->netdev->name, err); + dev_warn(&stir->netdev->dev, "usb receive submit error: %d\n", + err); stir->receiving = 0; wake_up_process(stir->thread); } @@ -1073,7 +1074,8 @@ static int stir_probe(struct usb_interface *intf, if (ret != 0) goto err_out2; - info("IrDA: Registered SigmaTel device %s", net->name); + dev_info(&intf->dev, "IrDA: Registered SigmaTel device %s\n", + net->name); usb_set_intfdata(intf, stir); diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 18f4b3a96ae..9c926d205de 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -165,7 +165,7 @@ static void vlsi_proc_pdev(struct seq_file *seq, struct pci_dev *pdev) unsigned iobase = pci_resource_start(pdev, 0); unsigned i; - seq_printf(seq, "\n%s (vid/did: %04x/%04x)\n", + seq_printf(seq, "\n%s (vid/did: [%04x:%04x])\n", pci_name(pdev), (int)pdev->vendor, (int)pdev->device); seq_printf(seq, "pci-power-state: %u\n", (unsigned) pdev->current_state); seq_printf(seq, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n", diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index 804698fc6a8..d85717e3022 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -85,7 +85,7 @@ struct ixgb_adapter; #define DPRINTK(nlevel, klevel, fmt, args...) \ (void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \ printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \ - __FUNCTION__ , ## args)) + __func__ , ## args)) /* TX/RX descriptor defines */ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index aa75385cd6c..be3c7dc96f6 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -977,15 +977,17 @@ ixgb_clean_rx_ring(struct ixgb_adapter *adapter) for (i = 0; i < rx_ring->count; i++) { buffer_info = &rx_ring->buffer_info[i]; - if (buffer_info->skb) { - + if (buffer_info->dma) { pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + buffer_info->length = 0; + } + if (buffer_info->skb) { dev_kfree_skb(buffer_info->skb); - buffer_info->skb = NULL; } } diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 956914a5028..e116d340dcc 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2007 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -20,7 +20,6 @@ the file called "COPYING". Contact Information: - Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -37,17 +36,15 @@ #include "ixgbe_type.h" #include "ixgbe_common.h" -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA #include <linux/dca.h> #endif -#define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args) - #define PFX "ixgbe: " #define DPRINTK(nlevel, klevel, fmt, args...) \ ((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \ printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \ - __FUNCTION__ , ## args))) + __func__ , ## args))) /* TX/RX descriptor defines */ #define IXGBE_DEFAULT_TXD 1024 @@ -58,23 +55,14 @@ #define IXGBE_MAX_RXD 4096 #define IXGBE_MIN_RXD 64 -#define IXGBE_DEFAULT_RXQ 1 -#define IXGBE_MAX_RXQ 1 -#define IXGBE_MIN_RXQ 1 - -#define IXGBE_DEFAULT_ITR_RX_USECS 125 /* 8k irqs/sec */ -#define IXGBE_DEFAULT_ITR_TX_USECS 250 /* 4k irqs/sec */ -#define IXGBE_MIN_ITR_USECS 100 /* 500k irqs/sec */ -#define IXGBE_MAX_ITR_USECS 10000 /* 100 irqs/sec */ - /* flow control */ #define IXGBE_DEFAULT_FCRTL 0x10000 -#define IXGBE_MIN_FCRTL 0 +#define IXGBE_MIN_FCRTL 0x40 #define IXGBE_MAX_FCRTL 0x7FF80 #define IXGBE_DEFAULT_FCRTH 0x20000 -#define IXGBE_MIN_FCRTH 0 +#define IXGBE_MIN_FCRTH 0x600 #define IXGBE_MAX_FCRTH 0x7FFF0 -#define IXGBE_DEFAULT_FCPAUSE 0x6800 /* may be too long */ +#define IXGBE_DEFAULT_FCPAUSE 0xFFFF #define IXGBE_MIN_FCPAUSE 0 #define IXGBE_MAX_FCPAUSE 0xFFFF @@ -88,9 +76,6 @@ #define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) -/* How many Tx Descriptors do we need to call netif_wake_queue? */ -#define IXGBE_TX_QUEUE_WAKE 16 - /* How many Rx Buffers do we bundle into one write to the hardware ? */ #define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */ @@ -119,6 +104,7 @@ struct ixgbe_rx_buffer { dma_addr_t dma; struct page *page; dma_addr_t page_dma; + unsigned int page_offset; }; struct ixgbe_queue_stats { @@ -150,22 +136,20 @@ struct ixgbe_ring { * offset associated with this ring, which is different * for DCE and RSS modes */ -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA /* cpu for tx queue */ int cpu; #endif struct net_lro_mgr lro_mgr; bool lro_used; struct ixgbe_queue_stats stats; - u8 v_idx; /* maps directly to the index for this ring in the hardware - * vector array, can also be used for finding the bit in EICR - * and friends that represents the vector for this ring */ + u16 v_idx; /* maps directly to the index for this ring in the hardware + * vector array, can also be used for finding the bit in EICR + * and friends that represents the vector for this ring */ - u32 eims_value; - u16 itr_register; - char name[IFNAMSIZ + 5]; u16 work_limit; /* max work per interrupt */ + u16 rx_buf_len; }; #define RING_F_VMDQ 1 @@ -190,8 +174,8 @@ struct ixgbe_q_vector { DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */ u8 rxr_count; /* Rx ring count assigned to this vector */ u8 txr_count; /* Tx ring count assigned to this vector */ - u8 tx_eitr; - u8 rx_eitr; + u8 tx_itr; + u8 rx_itr; u32 eitr; }; @@ -228,7 +212,6 @@ struct ixgbe_adapter { struct timer_list watchdog_timer; struct vlan_group *vlgrp; u16 bd_number; - u16 rx_buf_len; struct work_struct reset_task; struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS]; char name[MAX_MSIX_COUNT][IFNAMSIZ + 5]; @@ -240,7 +223,9 @@ struct ixgbe_adapter { /* TX */ struct ixgbe_ring *tx_ring; /* One per active queue */ + int num_tx_queues; u64 restart_queue; + u64 hw_csum_tx_good; u64 lsc_int; u64 hw_tso_ctxt; u64 hw_tso6_ctxt; @@ -249,12 +234,10 @@ struct ixgbe_adapter { /* RX */ struct ixgbe_ring *rx_ring; /* One per active queue */ - u64 hw_csum_tx_good; + int num_rx_queues; u64 hw_csum_rx_error; u64 hw_csum_rx_good; u64 non_eop_descs; - int num_tx_queues; - int num_rx_queues; int num_msix_vectors; struct ixgbe_ring_feature ring_feature[3]; struct msix_entry *msix_entries; @@ -267,15 +250,28 @@ struct ixgbe_adapter { * thus the additional *_CAPABLE flags. */ u32 flags; -#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1 << 0) -#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 1) -#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 2) -#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 3) -#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 4) -#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 5) -#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 6) -#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 7) -#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 8) +#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1) +#define IXGBE_FLAG_MSI_CAPABLE (u32)(1 << 1) +#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 2) +#define IXGBE_FLAG_MSIX_CAPABLE (u32)(1 << 3) +#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 4) +#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 6) +#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 7) +#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 8) +#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 9) +#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 10) +#define IXGBE_FLAG_DCA_CAPABLE (u32)(1 << 11) +#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 12) +#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 13) +#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 16) +#define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17) +#define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18) +#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) +#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) +#define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) + +/* default to trying for four seconds */ +#define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) /* OS defined structs */ struct net_device *netdev; @@ -288,14 +284,21 @@ struct ixgbe_adapter { struct ixgbe_hw_stats stats; /* Interrupt Throttle Rate */ - u32 rx_eitr; - u32 tx_eitr; + u32 eitr_param; unsigned long state; u64 tx_busy; u64 lro_aggregated; u64 lro_flushed; u64 lro_no_desc; + unsigned int tx_ring_count; + unsigned int rx_ring_count; + + u32 link_speed; + bool link_up; + unsigned long link_check_timeout; + + struct work_struct watchdog_task; }; enum ixbge_state_t { @@ -317,11 +320,11 @@ extern int ixgbe_up(struct ixgbe_adapter *adapter); extern void ixgbe_down(struct ixgbe_adapter *adapter); extern void ixgbe_reinit_locked(struct ixgbe_adapter *adapter); extern void ixgbe_reset(struct ixgbe_adapter *adapter); -extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); extern void ixgbe_set_ethtool_ops(struct net_device *netdev); -extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, - struct ixgbe_ring *rxdr); -extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, - struct ixgbe_ring *txdr); +extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); +extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); +extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); +extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); +extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index f96358b641a..7cddcfba809 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2007 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -20,7 +20,6 @@ the file called "COPYING". Contact Information: - Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -36,67 +35,62 @@ #define IXGBE_82598_MAX_TX_QUEUES 32 #define IXGBE_82598_MAX_RX_QUEUES 64 #define IXGBE_82598_RAR_ENTRIES 16 +#define IXGBE_82598_MC_TBL_SIZE 128 +#define IXGBE_82598_VFT_TBL_SIZE 128 -static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw); -static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed, - bool *autoneg); -static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw, - u32 *speed, bool *autoneg); -static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw); -static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw); -static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, - bool *link_up); -static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed, - bool autoneg, - bool autoneg_wait_to_complete); +static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg); static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw); -static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, - bool autoneg, - bool autoneg_wait_to_complete); -static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw); - +static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); +/** + */ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) { - hw->mac.num_rx_queues = IXGBE_82598_MAX_RX_QUEUES; - hw->mac.num_tx_queues = IXGBE_82598_MAX_TX_QUEUES; - hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES; - - /* PHY ops are filled in by default properly for Fiber only */ - if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper) { - hw->mac.ops.setup_link = &ixgbe_setup_copper_link_82598; - hw->mac.ops.setup_link_speed = &ixgbe_setup_copper_link_speed_82598; - hw->mac.ops.get_link_settings = - &ixgbe_get_copper_link_settings_82598; - - /* Call PHY identify routine to get the phy type */ - ixgbe_identify_phy(hw); - - switch (hw->phy.type) { - case ixgbe_phy_tn: - hw->phy.ops.setup_link = &ixgbe_setup_tnx_phy_link; - hw->phy.ops.check_link = &ixgbe_check_tnx_phy_link; - hw->phy.ops.setup_link_speed = - &ixgbe_setup_tnx_phy_link_speed; - break; - default: - break; - } + struct ixgbe_mac_info *mac = &hw->mac; + struct ixgbe_phy_info *phy = &hw->phy; + + /* Call PHY identify routine to get the phy type */ + ixgbe_identify_phy_generic(hw); + + /* PHY Init */ + switch (phy->type) { + default: + break; } + if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { + mac->ops.setup_link = &ixgbe_setup_copper_link_82598; + mac->ops.setup_link_speed = + &ixgbe_setup_copper_link_speed_82598; + mac->ops.get_link_capabilities = + &ixgbe_get_copper_link_capabilities_82598; + } + + mac->mcft_size = IXGBE_82598_MC_TBL_SIZE; + mac->vft_size = IXGBE_82598_VFT_TBL_SIZE; + mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES; + mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; + mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; + return 0; } /** - * ixgbe_get_link_settings_82598 - Determines default link settings + * ixgbe_get_link_capabilities_82598 - Determines link capabilities * @hw: pointer to hardware structure * @speed: pointer to link speed * @autoneg: boolean auto-negotiation value * - * Determines the default link settings by reading the AUTOC register. + * Determines the link capabilities by reading the AUTOC register. **/ -static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed, - bool *autoneg) +static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg) { s32 status = 0; s32 autoc_reg; @@ -145,15 +139,16 @@ static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed, } /** - * ixgbe_get_copper_link_settings_82598 - Determines default link settings + * ixgbe_get_copper_link_capabilities_82598 - Determines link capabilities * @hw: pointer to hardware structure * @speed: pointer to link speed * @autoneg: boolean auto-negotiation value * - * Determines the default link settings by reading the AUTOC register. + * Determines the link capabilities by reading the AUTOC register. **/ -static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw, - u32 *speed, bool *autoneg) +s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg) { s32 status = IXGBE_ERR_LINK_SETUP; u16 speed_ability; @@ -161,9 +156,9 @@ static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw, *speed = 0; *autoneg = true; - status = ixgbe_read_phy_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, - &speed_ability); + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &speed_ability); if (status == 0) { if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) @@ -191,11 +186,9 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82598AF_SINGLE_PORT: case IXGBE_DEV_ID_82598EB_CX4: case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: + case IXGBE_DEV_ID_82598EB_XF_LR: media_type = ixgbe_media_type_fiber; break; - case IXGBE_DEV_ID_82598AT_DUAL_PORT: - media_type = ixgbe_media_type_copper; - break; default: media_type = ixgbe_media_type_unknown; break; @@ -205,6 +198,122 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) } /** + * ixgbe_setup_fc_82598 - Configure flow control settings + * @hw: pointer to hardware structure + * @packetbuf_num: packet buffer number (0-7) + * + * Configures the flow control settings based on SW configuration. This + * function is used for 802.3x flow control configuration only. + **/ +s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) +{ + u32 frctl_reg; + u32 rmcs_reg; + + if (packetbuf_num < 0 || packetbuf_num > 7) { + hw_dbg(hw, "Invalid packet buffer number [%d], expected range is" + " 0-7\n", packetbuf_num); + } + + frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); + frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); + + rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X); + + /* + * 10 gig parts do not have a word in the EEPROM to determine the + * default flow control setting, so we explicitly set it to full. + */ + if (hw->fc.type == ixgbe_fc_default) + hw->fc.type = ixgbe_fc_full; + + /* + * We want to save off the original Flow Control configuration just in + * case we get disconnected and then reconnected into a different hub + * or switch with different Flow Control capabilities. + */ + hw->fc.original_type = hw->fc.type; + + /* + * The possible values of the "flow_control" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames but not + * send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but we do not + * support receiving pause frames) + * 3: Both Rx and Tx flow control (symmetric) are enabled. + * other: Invalid. + */ + switch (hw->fc.type) { + case ixgbe_fc_none: + break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled, + * and Tx Flow control is disabled. + */ + frctl_reg |= IXGBE_FCTRL_RFCE; + break; + case ixgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is disabled, + * by a software over-ride. + */ + rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; + break; + case ixgbe_fc_full: + /* + * Flow control (both Rx and Tx) is enabled by a software + * over-ride. + */ + frctl_reg |= IXGBE_FCTRL_RFCE; + rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; + break; + default: + /* We should never get here. The value should be 0-3. */ + hw_dbg(hw, "Flow control param set incorrectly\n"); + break; + } + + /* Enable 802.3x based flow control settings. */ + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg); + IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); + + /* + * Check for invalid software configuration, zeros are completely + * invalid for all parameters used past this point, and if we enable + * flow control with zero water marks, we blast flow control packets. + */ + if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { + hw_dbg(hw, "Flow control structure initialized incorrectly\n"); + return IXGBE_ERR_INVALID_LINK_SETTINGS; + } + + /* + * We need to set up the Receive Threshold high and low water + * marks as well as (optionally) enabling the transmission of + * XON frames. + */ + if (hw->fc.type & ixgbe_fc_tx_pause) { + if (hw->fc.send_xon) { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), + (hw->fc.low_water | IXGBE_FCRTL_XONE)); + } else { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), + hw->fc.low_water); + } + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), + (hw->fc.high_water)|IXGBE_FCRTH_FCEN); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time); + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); + + return 0; +} + +/** * ixgbe_setup_mac_link_82598 - Configures MAC link settings * @hw: pointer to hardware structure * @@ -248,8 +357,7 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) } if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) { status = IXGBE_ERR_AUTONEG_NOT_COMPLETE; - hw_dbg(hw, - "Autonegotiation did not complete.\n"); + hw_dbg(hw, "Autonegotiation did not complete.\n"); } } } @@ -259,8 +367,8 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) * case we get disconnected and then reconnected into a different hub * or switch with different Flow Control capabilities. */ - hw->fc.type = hw->fc.original_type; - ixgbe_setup_fc(hw, 0); + hw->fc.original_type = hw->fc.type; + ixgbe_setup_fc_82598(hw, 0); /* Add delay to filter out noises during initial link setup */ msleep(50); @@ -273,20 +381,35 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) * @hw: pointer to hardware structure * @speed: pointer to link speed * @link_up: true is link is up, false otherwise + * @link_up_wait_to_complete: bool used to wait for link up or not * * Reads the links register to determine if link is up and the current speed **/ -static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, - bool *link_up) +static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, bool *link_up, + bool link_up_wait_to_complete) { u32 links_reg; + u32 i; links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); - - if (links_reg & IXGBE_LINKS_UP) - *link_up = true; - else - *link_up = false; + if (link_up_wait_to_complete) { + for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { + if (links_reg & IXGBE_LINKS_UP) { + *link_up = true; + break; + } else { + *link_up = false; + } + msleep(100); + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + } + } else { + if (links_reg & IXGBE_LINKS_UP) + *link_up = true; + else + *link_up = false; + } if (links_reg & IXGBE_LINKS_SPEED) *speed = IXGBE_LINK_SPEED_10GB_FULL; @@ -296,6 +419,7 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, return 0; } + /** * ixgbe_setup_mac_link_speed_82598 - Set MAC link speed * @hw: pointer to hardware structure @@ -306,18 +430,18 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, * Set the link speed in the AUTOC register and restarts link. **/ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, - u32 speed, bool autoneg, - bool autoneg_wait_to_complete) + ixgbe_link_speed speed, bool autoneg, + bool autoneg_wait_to_complete) { s32 status = 0; /* If speed is 10G, then check for CX4 or XAUI. */ if ((speed == IXGBE_LINK_SPEED_10GB_FULL) && - (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4))) + (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4))) { hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN; - else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg)) + } else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg)) { hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN; - else if (autoneg) { + } else if (autoneg) { /* BX mode - Autonegotiate 1G */ if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD)) hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN; @@ -336,7 +460,7 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, * ixgbe_hw This will write the AUTOC register based on the new * stored values */ - hw->mac.ops.setup_link(hw); + ixgbe_setup_mac_link_82598(hw); } return status; @@ -354,18 +478,17 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, **/ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) { - s32 status = 0; + s32 status; /* Restart autonegotiation on PHY */ - if (hw->phy.ops.setup_link) - status = hw->phy.ops.setup_link(hw); + status = hw->phy.ops.setup_link(hw); - /* Set MAC to KX/KX4 autoneg, which defaultis to Parallel detection */ + /* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */ hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX); hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN; /* Set up MAC */ - hw->mac.ops.setup_link(hw); + ixgbe_setup_mac_link_82598(hw); return status; } @@ -379,23 +502,23 @@ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) * * Sets the link speed in the AUTOC register in the MAC and restarts link. **/ -static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, - bool autoneg, - bool autoneg_wait_to_complete) +static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) { - s32 status = 0; + s32 status; /* Setup the PHY according to input speed */ - if (hw->phy.ops.setup_link_speed) - status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, - autoneg_wait_to_complete); + status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, + autoneg_wait_to_complete); /* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */ hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX); hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN; /* Set up MAC */ - hw->mac.ops.setup_link(hw); + ixgbe_setup_mac_link_82598(hw); return status; } @@ -404,7 +527,7 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, * ixgbe_reset_hw_82598 - Performs hardware reset * @hw: pointer to hardware structure * - * Resets the hardware by reseting the transmit and receive units, masks and + * Resets the hardware by resetting the transmit and receive units, masks and * clears all interrupts, performing a PHY reset, and performing a link (MAC) * reset. **/ @@ -418,35 +541,44 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) u8 analog_val; /* Call adapter stop to disable tx/rx and clear interrupts */ - ixgbe_stop_adapter(hw); + hw->mac.ops.stop_adapter(hw); /* - * Power up the Atlas TX lanes if they are currently powered down. - * Atlas TX lanes are powered down for MAC loopback tests, but + * Power up the Atlas Tx lanes if they are currently powered down. + * Atlas Tx lanes are powered down for MAC loopback tests, but * they are not automatically restored on reset. */ - ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) { - /* Enable TX Atlas so packets can be transmitted again */ - ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); + /* Enable Tx Atlas so packets can be transmitted again */ + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, + &analog_val); analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN; - ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, analog_val); + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, + analog_val); - ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &analog_val); + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, + &analog_val); analog_val &= ~IXGBE_ATLAS_PDN_TX_10G_QL_ALL; - ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, analog_val); + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, + analog_val); - ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &analog_val); + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, + &analog_val); analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL; - ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, analog_val); + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, + analog_val); - ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &analog_val); + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, + &analog_val); analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL; - ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, analog_val); + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, + analog_val); } /* Reset PHY */ - ixgbe_reset_phy(hw); + if (hw->phy.reset_disable == false) + hw->phy.ops.reset(hw); /* * Prevent the PCI-E bus from from hanging by disabling PCI-E master @@ -499,29 +631,311 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); } else { hw->mac.link_attach_type = - (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE); + (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE); hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK); hw->mac.link_settings_loaded = true; } /* Store the permanent mac address */ - ixgbe_get_mac_addr(hw, hw->mac.perm_addr); + hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); return status; } +/** + * ixgbe_set_vmdq_82598 - Associate a VMDq set index with a rx address + * @hw: pointer to hardware struct + * @rar: receive address register index to associate with a VMDq index + * @vmdq: VMDq set index + **/ +s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +{ + u32 rar_high; + + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar)); + rar_high &= ~IXGBE_RAH_VIND_MASK; + rar_high |= ((vmdq << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK); + IXGBE_WRITE_REG(hw, IXGBE_RAH(rar), rar_high); + return 0; +} + +/** + * ixgbe_clear_vmdq_82598 - Disassociate a VMDq set index from an rx address + * @hw: pointer to hardware struct + * @rar: receive address register index to associate with a VMDq index + * @vmdq: VMDq clear index (not used in 82598, but elsewhere) + **/ +static s32 ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +{ + u32 rar_high; + u32 rar_entries = hw->mac.num_rar_entries; + + if (rar < rar_entries) { + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar)); + if (rar_high & IXGBE_RAH_VIND_MASK) { + rar_high &= ~IXGBE_RAH_VIND_MASK; + IXGBE_WRITE_REG(hw, IXGBE_RAH(rar), rar_high); + } + } else { + hw_dbg(hw, "RAR index %d is out of range.\n", rar); + } + + return 0; +} + +/** + * ixgbe_set_vfta_82598 - Set VLAN filter table + * @hw: pointer to hardware structure + * @vlan: VLAN id to write to VLAN filter + * @vind: VMDq output index that maps queue to VLAN id in VFTA + * @vlan_on: boolean flag to turn on/off VLAN in VFTA + * + * Turn on/off specified VLAN in the VLAN filter table. + **/ +s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on) +{ + u32 regindex; + u32 bitindex; + u32 bits; + u32 vftabyte; + + if (vlan > 4095) + return IXGBE_ERR_PARAM; + + /* Determine 32-bit word position in array */ + regindex = (vlan >> 5) & 0x7F; /* upper seven bits */ + + /* Determine the location of the (VMD) queue index */ + vftabyte = ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */ + bitindex = (vlan & 0x7) << 2; /* lower 3 bits indicate nibble */ + + /* Set the nibble for VMD queue index */ + bits = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(vftabyte, regindex)); + bits &= (~(0x0F << bitindex)); + bits |= (vind << bitindex); + IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vftabyte, regindex), bits); + + /* Determine the location of the bit for this VLAN id */ + bitindex = vlan & 0x1F; /* lower five bits */ + + bits = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex)); + if (vlan_on) + /* Turn on this VLAN id */ + bits |= (1 << bitindex); + else + /* Turn off this VLAN id */ + bits &= ~(1 << bitindex); + IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), bits); + + return 0; +} + +/** + * ixgbe_clear_vfta_82598 - Clear VLAN filter table + * @hw: pointer to hardware structure + * + * Clears the VLAN filer table, and the VMDq index associated with the filter + **/ +static s32 ixgbe_clear_vfta_82598(struct ixgbe_hw *hw) +{ + u32 offset; + u32 vlanbyte; + + for (offset = 0; offset < hw->mac.vft_size; offset++) + IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0); + + for (vlanbyte = 0; vlanbyte < 4; vlanbyte++) + for (offset = 0; offset < hw->mac.vft_size; offset++) + IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset), + 0); + + return 0; +} + +/** + * ixgbe_blink_led_start_82598 - Blink LED based on index. + * @hw: pointer to hardware structure + * @index: led number to blink + **/ +static s32 ixgbe_blink_led_start_82598(struct ixgbe_hw *hw, u32 index) +{ + ixgbe_link_speed speed = 0; + bool link_up = 0; + u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* + * Link must be up to auto-blink the LEDs on the 82598EB MAC; + * force it if link is down. + */ + hw->mac.ops.check_link(hw, &speed, &link_up, false); + + if (!link_up) { + autoc_reg |= IXGBE_AUTOC_FLU; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + msleep(10); + } + + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg |= IXGBE_LED_BLINK(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); + + return 0; +} + +/** + * ixgbe_blink_led_stop_82598 - Stop blinking LED based on index. + * @hw: pointer to hardware structure + * @index: led number to stop blinking + **/ +static s32 ixgbe_blink_led_stop_82598(struct ixgbe_hw *hw, u32 index) +{ + u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + autoc_reg &= ~IXGBE_AUTOC_FLU; + autoc_reg |= IXGBE_AUTOC_AN_RESTART; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg &= ~IXGBE_LED_BLINK(index); + led_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); + + return 0; +} + +/** + * ixgbe_read_analog_reg8_82598 - Reads 8 bit Atlas analog register + * @hw: pointer to hardware structure + * @reg: analog register to read + * @val: read value + * + * Performs read operation to Atlas analog register specified. + **/ +s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) +{ + u32 atlas_ctl; + + IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, + IXGBE_ATLASCTL_WRITE_CMD | (reg << 8)); + IXGBE_WRITE_FLUSH(hw); + udelay(10); + atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); + *val = (u8)atlas_ctl; + + return 0; +} + +/** + * ixgbe_write_analog_reg8_82598 - Writes 8 bit Atlas analog register + * @hw: pointer to hardware structure + * @reg: atlas register to write + * @val: value to write + * + * Performs write operation to Atlas analog register specified. + **/ +s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) +{ + u32 atlas_ctl; + + atlas_ctl = (reg << 8) | val; + IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl); + IXGBE_WRITE_FLUSH(hw); + udelay(10); + + return 0; +} + +/** + * ixgbe_get_supported_physical_layer_82598 - Returns physical layer type + * @hw: pointer to hardware structure + * + * Determines physical layer capabilities of the current configuration. + **/ +s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) +{ + s32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + + switch (hw->device_id) { + case IXGBE_DEV_ID_82598EB_CX4: + case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; + break; + case IXGBE_DEV_ID_82598AF_DUAL_PORT: + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; + break; + case IXGBE_DEV_ID_82598EB_XF_LR: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; + break; + + default: + physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + break; + } + + return physical_layer; +} + static struct ixgbe_mac_operations mac_ops_82598 = { - .reset = &ixgbe_reset_hw_82598, + .init_hw = &ixgbe_init_hw_generic, + .reset_hw = &ixgbe_reset_hw_82598, + .start_hw = &ixgbe_start_hw_generic, + .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic, .get_media_type = &ixgbe_get_media_type_82598, + .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82598, + .get_mac_addr = &ixgbe_get_mac_addr_generic, + .stop_adapter = &ixgbe_stop_adapter_generic, + .read_analog_reg8 = &ixgbe_read_analog_reg8_82598, + .write_analog_reg8 = &ixgbe_write_analog_reg8_82598, .setup_link = &ixgbe_setup_mac_link_82598, - .check_link = &ixgbe_check_mac_link_82598, .setup_link_speed = &ixgbe_setup_mac_link_speed_82598, - .get_link_settings = &ixgbe_get_link_settings_82598, + .check_link = &ixgbe_check_mac_link_82598, + .get_link_capabilities = &ixgbe_get_link_capabilities_82598, + .led_on = &ixgbe_led_on_generic, + .led_off = &ixgbe_led_off_generic, + .blink_led_start = &ixgbe_blink_led_start_82598, + .blink_led_stop = &ixgbe_blink_led_stop_82598, + .set_rar = &ixgbe_set_rar_generic, + .clear_rar = &ixgbe_clear_rar_generic, + .set_vmdq = &ixgbe_set_vmdq_82598, + .clear_vmdq = &ixgbe_clear_vmdq_82598, + .init_rx_addrs = &ixgbe_init_rx_addrs_generic, + .update_uc_addr_list = &ixgbe_update_uc_addr_list_generic, + .update_mc_addr_list = &ixgbe_update_mc_addr_list_generic, + .enable_mc = &ixgbe_enable_mc_generic, + .disable_mc = &ixgbe_disable_mc_generic, + .clear_vfta = &ixgbe_clear_vfta_82598, + .set_vfta = &ixgbe_set_vfta_82598, + .setup_fc = &ixgbe_setup_fc_82598, +}; + +static struct ixgbe_eeprom_operations eeprom_ops_82598 = { + .init_params = &ixgbe_init_eeprom_params_generic, + .read = &ixgbe_read_eeprom_generic, + .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, + .update_checksum = &ixgbe_update_eeprom_checksum_generic, +}; + +static struct ixgbe_phy_operations phy_ops_82598 = { + .identify = &ixgbe_identify_phy_generic, + /* .identify_sfp = &ixgbe_identify_sfp_module_generic, */ + .reset = &ixgbe_reset_phy_generic, + .read_reg = &ixgbe_read_phy_reg_generic, + .write_reg = &ixgbe_write_phy_reg_generic, + .setup_link = &ixgbe_setup_phy_link_generic, + .setup_link_speed = &ixgbe_setup_phy_link_speed_generic, }; struct ixgbe_info ixgbe_82598_info = { .mac = ixgbe_mac_82598EB, .get_invariants = &ixgbe_get_invariants_82598, .mac_ops = &mac_ops_82598, + .eeprom_ops = &eeprom_ops_82598, + .phy_ops = &phy_ops_82598, }; diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 7fd6aeb1b02..f67c68404bb 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2007 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -20,7 +20,6 @@ the file called "COPYING". Contact Information: - Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -33,20 +32,28 @@ #include "ixgbe_common.h" #include "ixgbe_phy.h" -static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw); - static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw); +static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw); static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw); static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw); +static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw); +static void ixgbe_standby_eeprom(struct ixgbe_hw *hw); +static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, + u16 count); +static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count); +static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); +static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); +static void ixgbe_release_eeprom(struct ixgbe_hw *hw); static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw); -static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw); -static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw); +static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index); +static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index); static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr); +static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq); /** - * ixgbe_start_hw - Prepare hardware for TX/RX + * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx * @hw: pointer to hardware structure * * Starts the hardware by filling the bus info structure and media type, clears @@ -54,7 +61,7 @@ static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr); * table, VLAN filter table, calls routine to set up link and flow control * settings, and leaves transmit and receive units disabled and uninitialized **/ -s32 ixgbe_start_hw(struct ixgbe_hw *hw) +s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) { u32 ctrl_ext; @@ -62,22 +69,22 @@ s32 ixgbe_start_hw(struct ixgbe_hw *hw) hw->phy.media_type = hw->mac.ops.get_media_type(hw); /* Identify the PHY */ - ixgbe_identify_phy(hw); + hw->phy.ops.identify(hw); /* * Store MAC address from RAR0, clear receive address registers, and * clear the multicast table */ - ixgbe_init_rx_addrs(hw); + hw->mac.ops.init_rx_addrs(hw); /* Clear the VLAN filter table */ - ixgbe_clear_vfta(hw); + hw->mac.ops.clear_vfta(hw); /* Set up link */ hw->mac.ops.setup_link(hw); /* Clear statistics registers */ - ixgbe_clear_hw_cntrs(hw); + hw->mac.ops.clear_hw_cntrs(hw); /* Set No Snoop Disable */ ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); @@ -92,34 +99,34 @@ s32 ixgbe_start_hw(struct ixgbe_hw *hw) } /** - * ixgbe_init_hw - Generic hardware initialization + * ixgbe_init_hw_generic - Generic hardware initialization * @hw: pointer to hardware structure * - * Initialize the hardware by reseting the hardware, filling the bus info + * Initialize the hardware by resetting the hardware, filling the bus info * structure and media type, clears all on chip counters, initializes receive * address registers, multicast table, VLAN filter table, calls routine to set * up link and flow control settings, and leaves transmit and receive units * disabled and uninitialized **/ -s32 ixgbe_init_hw(struct ixgbe_hw *hw) +s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) { /* Reset the hardware */ - hw->mac.ops.reset(hw); + hw->mac.ops.reset_hw(hw); /* Start the HW */ - ixgbe_start_hw(hw); + hw->mac.ops.start_hw(hw); return 0; } /** - * ixgbe_clear_hw_cntrs - Generic clear hardware counters + * ixgbe_clear_hw_cntrs_generic - Generic clear hardware counters * @hw: pointer to hardware structure * * Clears all hardware statistics counters by reading them from the hardware * Statistics counters are clear on read. **/ -static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw) +s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw) { u16 i = 0; @@ -191,7 +198,36 @@ static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw) } /** - * ixgbe_get_mac_addr - Generic get MAC address + * ixgbe_read_pba_num_generic - Reads part number from EEPROM + * @hw: pointer to hardware structure + * @pba_num: stores the part number from the EEPROM + * + * Reads the part number from the EEPROM. + **/ +s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num) +{ + s32 ret_val; + u16 data; + + ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM0_PTR, &data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *pba_num = (u32)(data << 16); + + ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM1_PTR, &data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *pba_num |= data; + + return 0; +} + +/** + * ixgbe_get_mac_addr_generic - Generic get MAC address * @hw: pointer to hardware structure * @mac_addr: Adapter MAC address * @@ -199,7 +235,7 @@ static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw) * A reset of the adapter must be performed prior to calling this function * in order for the MAC address to have been loaded from the EEPROM into RAR0 **/ -s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr) +s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr) { u32 rar_high; u32 rar_low; @@ -217,30 +253,8 @@ s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr) return 0; } -s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num) -{ - s32 ret_val; - u16 data; - - ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM0_PTR, &data); - if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); - return ret_val; - } - *part_num = (u32)(data << 16); - - ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM1_PTR, &data); - if (ret_val) { - hw_dbg(hw, "NVM Read Error\n"); - return ret_val; - } - *part_num |= data; - - return 0; -} - /** - * ixgbe_stop_adapter - Generic stop TX/RX units + * ixgbe_stop_adapter_generic - Generic stop Tx/Rx units * @hw: pointer to hardware structure * * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts, @@ -248,7 +262,7 @@ s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num) * the shared code and drivers to determine if the adapter is in a stopped * state and should not touch the hardware. **/ -s32 ixgbe_stop_adapter(struct ixgbe_hw *hw) +s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) { u32 number_of_queues; u32 reg_val; @@ -264,6 +278,7 @@ s32 ixgbe_stop_adapter(struct ixgbe_hw *hw) reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL); reg_val &= ~(IXGBE_RXCTRL_RXEN); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); + IXGBE_WRITE_FLUSH(hw); msleep(2); /* Clear interrupt mask to stop from interrupts being generated */ @@ -273,7 +288,7 @@ s32 ixgbe_stop_adapter(struct ixgbe_hw *hw) IXGBE_READ_REG(hw, IXGBE_EICR); /* Disable the transmit unit. Each queue must be disabled. */ - number_of_queues = hw->mac.num_tx_queues; + number_of_queues = hw->mac.max_tx_queues; for (i = 0; i < number_of_queues; i++) { reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); if (reg_val & IXGBE_TXDCTL_ENABLE) { @@ -282,15 +297,22 @@ s32 ixgbe_stop_adapter(struct ixgbe_hw *hw) } } + /* + * Prevent the PCI-E bus from from hanging by disabling PCI-E master + * access and verify no pending requests + */ + if (ixgbe_disable_pcie_master(hw) != 0) + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + return 0; } /** - * ixgbe_led_on - Turns on the software controllable LEDs. + * ixgbe_led_on_generic - Turns on the software controllable LEDs. * @hw: pointer to hardware structure * @index: led number to turn on **/ -s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index) +s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index) { u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); @@ -304,11 +326,11 @@ s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index) } /** - * ixgbe_led_off - Turns off the software controllable LEDs. + * ixgbe_led_off_generic - Turns off the software controllable LEDs. * @hw: pointer to hardware structure * @index: led number to turn off **/ -s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index) +s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index) { u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); @@ -321,15 +343,14 @@ s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index) return 0; } - /** - * ixgbe_init_eeprom - Initialize EEPROM params + * ixgbe_init_eeprom_params_generic - Initialize EEPROM params * @hw: pointer to hardware structure * * Initializes the EEPROM parameters ixgbe_eeprom_info within the * ixgbe_hw struct in order to set up EEPROM access. **/ -s32 ixgbe_init_eeprom(struct ixgbe_hw *hw) +s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; u32 eec; @@ -337,6 +358,9 @@ s32 ixgbe_init_eeprom(struct ixgbe_hw *hw) if (eeprom->type == ixgbe_eeprom_uninitialized) { eeprom->type = ixgbe_eeprom_none; + /* Set default semaphore delay to 10ms which is a well + * tested value */ + eeprom->semaphore_delay = 10; /* * Check for EEPROM present first. @@ -369,18 +393,85 @@ s32 ixgbe_init_eeprom(struct ixgbe_hw *hw) } /** - * ixgbe_read_eeprom - Read EEPROM word using EERD + * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be read + * @data: read 16 bit value from EEPROM + * + * Reads 16 bit value from EEPROM through bit-bang method + **/ +s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 *data) +{ + s32 status; + u16 word_in; + u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; + + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + /* Prepare the EEPROM for reading */ + status = ixgbe_acquire_eeprom(hw); + + if (status == 0) { + if (ixgbe_ready_eeprom(hw) != 0) { + ixgbe_release_eeprom(hw); + status = IXGBE_ERR_EEPROM; + } + } + + if (status == 0) { + ixgbe_standby_eeprom(hw); + + /* + * Some SPI eeproms use the 8th address bit embedded in the + * opcode + */ + if ((hw->eeprom.address_bits == 8) && (offset >= 128)) + read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; + + /* Send the READ command (opcode + addr) */ + ixgbe_shift_out_eeprom_bits(hw, read_opcode, + IXGBE_EEPROM_OPCODE_BITS); + ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2), + hw->eeprom.address_bits); + + /* Read the data. */ + word_in = ixgbe_shift_in_eeprom_bits(hw, 16); + *data = (word_in >> 8) | (word_in << 8); + + /* End this read operation */ + ixgbe_release_eeprom(hw); + } + +out: + return status; +} + +/** + * ixgbe_read_eeprom_generic - Read EEPROM word using EERD * @hw: pointer to hardware structure * @offset: offset of word in the EEPROM to read * @data: word read from the EEPROM * * Reads a 16 bit word from the EEPROM using the EERD register. **/ -s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data) +s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) { u32 eerd; s32 status; + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) + IXGBE_EEPROM_READ_REG_START; @@ -389,10 +480,11 @@ s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data) if (status == 0) *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >> - IXGBE_EEPROM_READ_REG_DATA); + IXGBE_EEPROM_READ_REG_DATA); else hw_dbg(hw, "Eeprom read timed out\n"); +out: return status; } @@ -420,6 +512,58 @@ static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw) } /** + * ixgbe_acquire_eeprom - Acquire EEPROM using bit-bang + * @hw: pointer to hardware structure + * + * Prepares EEPROM for access using bit-bang method. This function should + * be called before issuing a command to the EEPROM. + **/ +static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw) +{ + s32 status = 0; + u32 eec; + u32 i; + + if (ixgbe_acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != 0) + status = IXGBE_ERR_SWFW_SYNC; + + if (status == 0) { + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + /* Request EEPROM Access */ + eec |= IXGBE_EEC_REQ; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + + for (i = 0; i < IXGBE_EEPROM_GRANT_ATTEMPTS; i++) { + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + if (eec & IXGBE_EEC_GNT) + break; + udelay(5); + } + + /* Release if grant not acquired */ + if (!(eec & IXGBE_EEC_GNT)) { + eec &= ~IXGBE_EEC_REQ; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + hw_dbg(hw, "Could not acquire EEPROM grant\n"); + + ixgbe_release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + status = IXGBE_ERR_EEPROM; + } + } + + /* Setup EEPROM for Read/Write */ + if (status == 0) { + /* Clear CS and SK */ + eec &= ~(IXGBE_EEC_CS | IXGBE_EEC_SK); + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + udelay(1); + } + return status; +} + +/** * ixgbe_get_eeprom_semaphore - Get hardware semaphore * @hw: pointer to hardware structure * @@ -475,7 +619,7 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) */ if (i >= timeout) { hw_dbg(hw, "Driver can't access the Eeprom - Semaphore " - "not granted.\n"); + "not granted.\n"); ixgbe_release_eeprom_semaphore(hw); status = IXGBE_ERR_EEPROM; } @@ -503,6 +647,217 @@ static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw) } /** + * ixgbe_ready_eeprom - Polls for EEPROM ready + * @hw: pointer to hardware structure + **/ +static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw) +{ + s32 status = 0; + u16 i; + u8 spi_stat_reg; + + /* + * Read "Status Register" repeatedly until the LSB is cleared. The + * EEPROM will signal that the command has been completed by clearing + * bit 0 of the internal status register. If it's not cleared within + * 5 milliseconds, then error out. + */ + for (i = 0; i < IXGBE_EEPROM_MAX_RETRY_SPI; i += 5) { + ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_RDSR_OPCODE_SPI, + IXGBE_EEPROM_OPCODE_BITS); + spi_stat_reg = (u8)ixgbe_shift_in_eeprom_bits(hw, 8); + if (!(spi_stat_reg & IXGBE_EEPROM_STATUS_RDY_SPI)) + break; + + udelay(5); + ixgbe_standby_eeprom(hw); + }; + + /* + * On some parts, SPI write time could vary from 0-20mSec on 3.3V + * devices (and only 0-5mSec on 5V devices) + */ + if (i >= IXGBE_EEPROM_MAX_RETRY_SPI) { + hw_dbg(hw, "SPI EEPROM Status error\n"); + status = IXGBE_ERR_EEPROM; + } + + return status; +} + +/** + * ixgbe_standby_eeprom - Returns EEPROM to a "standby" state + * @hw: pointer to hardware structure + **/ +static void ixgbe_standby_eeprom(struct ixgbe_hw *hw) +{ + u32 eec; + + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + /* Toggle CS to flush commands */ + eec |= IXGBE_EEC_CS; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + udelay(1); + eec &= ~IXGBE_EEC_CS; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + udelay(1); +} + +/** + * ixgbe_shift_out_eeprom_bits - Shift data bits out to the EEPROM. + * @hw: pointer to hardware structure + * @data: data to send to the EEPROM + * @count: number of bits to shift out + **/ +static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, + u16 count) +{ + u32 eec; + u32 mask; + u32 i; + + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + /* + * Mask is used to shift "count" bits of "data" out to the EEPROM + * one bit at a time. Determine the starting bit based on count + */ + mask = 0x01 << (count - 1); + + for (i = 0; i < count; i++) { + /* + * A "1" is shifted out to the EEPROM by setting bit "DI" to a + * "1", and then raising and then lowering the clock (the SK + * bit controls the clock input to the EEPROM). A "0" is + * shifted out to the EEPROM by setting "DI" to "0" and then + * raising and then lowering the clock. + */ + if (data & mask) + eec |= IXGBE_EEC_DI; + else + eec &= ~IXGBE_EEC_DI; + + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + + udelay(1); + + ixgbe_raise_eeprom_clk(hw, &eec); + ixgbe_lower_eeprom_clk(hw, &eec); + + /* + * Shift mask to signify next bit of data to shift in to the + * EEPROM + */ + mask = mask >> 1; + }; + + /* We leave the "DI" bit set to "0" when we leave this routine. */ + eec &= ~IXGBE_EEC_DI; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); +} + +/** + * ixgbe_shift_in_eeprom_bits - Shift data bits in from the EEPROM + * @hw: pointer to hardware structure + **/ +static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count) +{ + u32 eec; + u32 i; + u16 data = 0; + + /* + * In order to read a register from the EEPROM, we need to shift + * 'count' bits in from the EEPROM. Bits are "shifted in" by raising + * the clock input to the EEPROM (setting the SK bit), and then reading + * the value of the "DO" bit. During this "shifting in" process the + * "DI" bit should always be clear. + */ + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + eec &= ~(IXGBE_EEC_DO | IXGBE_EEC_DI); + + for (i = 0; i < count; i++) { + data = data << 1; + ixgbe_raise_eeprom_clk(hw, &eec); + + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + eec &= ~(IXGBE_EEC_DI); + if (eec & IXGBE_EEC_DO) + data |= 1; + + ixgbe_lower_eeprom_clk(hw, &eec); + } + + return data; +} + +/** + * ixgbe_raise_eeprom_clk - Raises the EEPROM's clock input. + * @hw: pointer to hardware structure + * @eec: EEC register's current value + **/ +static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec) +{ + /* + * Raise the clock input to the EEPROM + * (setting the SK bit), then delay + */ + *eec = *eec | IXGBE_EEC_SK; + IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec); + IXGBE_WRITE_FLUSH(hw); + udelay(1); +} + +/** + * ixgbe_lower_eeprom_clk - Lowers the EEPROM's clock input. + * @hw: pointer to hardware structure + * @eecd: EECD's current value + **/ +static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec) +{ + /* + * Lower the clock input to the EEPROM (clearing the SK bit), then + * delay + */ + *eec = *eec & ~IXGBE_EEC_SK; + IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec); + IXGBE_WRITE_FLUSH(hw); + udelay(1); +} + +/** + * ixgbe_release_eeprom - Release EEPROM, release semaphores + * @hw: pointer to hardware structure + **/ +static void ixgbe_release_eeprom(struct ixgbe_hw *hw) +{ + u32 eec; + + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + eec |= IXGBE_EEC_CS; /* Pull CS high */ + eec &= ~IXGBE_EEC_SK; /* Lower SCK */ + + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + + udelay(1); + + /* Stop requesting EEPROM access */ + eec &= ~IXGBE_EEC_REQ; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + + ixgbe_release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); +} + +/** * ixgbe_calc_eeprom_checksum - Calculates and returns the checksum * @hw: pointer to hardware structure **/ @@ -517,7 +872,7 @@ static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw) /* Include 0x0-0x3F in the checksum */ for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { - if (ixgbe_read_eeprom(hw, i, &word) != 0) { + if (hw->eeprom.ops.read(hw, i, &word) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -526,15 +881,15 @@ static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw) /* Include all data from pointers except for the fw pointer */ for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) { - ixgbe_read_eeprom(hw, i, &pointer); + hw->eeprom.ops.read(hw, i, &pointer); /* Make sure the pointer seems valid */ if (pointer != 0xFFFF && pointer != 0) { - ixgbe_read_eeprom(hw, pointer, &length); + hw->eeprom.ops.read(hw, pointer, &length); if (length != 0xFFFF && length != 0) { for (j = pointer+1; j <= pointer+length; j++) { - ixgbe_read_eeprom(hw, j, &word); + hw->eeprom.ops.read(hw, j, &word); checksum += word; } } @@ -547,14 +902,15 @@ static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw) } /** - * ixgbe_validate_eeprom_checksum - Validate EEPROM checksum + * ixgbe_validate_eeprom_checksum_generic - 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. **/ -s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val) +s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, + u16 *checksum_val) { s32 status; u16 checksum; @@ -565,12 +921,12 @@ s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val) * not continue or we could be in for a very long wait while every * EEPROM read fails */ - status = ixgbe_read_eeprom(hw, 0, &checksum); + status = hw->eeprom.ops.read(hw, 0, &checksum); if (status == 0) { checksum = ixgbe_calc_eeprom_checksum(hw); - ixgbe_read_eeprom(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); + hw->eeprom.ops.read(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); /* * Verify read checksum from EEPROM is the same as @@ -590,6 +946,33 @@ s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val) } /** + * ixgbe_update_eeprom_checksum_generic - Updates the EEPROM checksum + * @hw: pointer to hardware structure + **/ +s32 ixgbe_update_eeprom_checksum_generic(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); + + if (status == 0) { + checksum = ixgbe_calc_eeprom_checksum(hw); + status = hw->eeprom.ops.write(hw, IXGBE_EEPROM_CHECKSUM, + checksum); + } else { + hw_dbg(hw, "EEPROM read failed\n"); + } + + return status; +} + +/** * ixgbe_validate_mac_addr - Validate MAC address * @mac_addr: pointer to MAC address. * @@ -607,61 +990,140 @@ s32 ixgbe_validate_mac_addr(u8 *mac_addr) status = IXGBE_ERR_INVALID_MAC_ADDR; /* Reject the zero address */ else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 && - mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) + mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) status = IXGBE_ERR_INVALID_MAC_ADDR; return status; } /** - * ixgbe_set_rar - Set RX address register + * ixgbe_set_rar_generic - Set Rx address register * @hw: pointer to hardware structure - * @addr: Address to put into receive address register * @index: Receive address register to write - * @vind: Vind to set RAR to + * @addr: Address to put into receive address register + * @vmdq: VMDq "set" or "pool" index * @enable_addr: set flag that address is active * * Puts an ethernet address into a receive address register. **/ -s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind, - u32 enable_addr) +s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, + u32 enable_addr) { u32 rar_low, rar_high; + u32 rar_entries = hw->mac.num_rar_entries; - /* - * HW expects these in little endian so we reverse the byte order from - * network order (big endian) to little endian - */ - rar_low = ((u32)addr[0] | - ((u32)addr[1] << 8) | - ((u32)addr[2] << 16) | - ((u32)addr[3] << 24)); + /* setup VMDq pool selection before this RAR gets enabled */ + hw->mac.ops.set_vmdq(hw, index, vmdq); - rar_high = ((u32)addr[4] | - ((u32)addr[5] << 8) | - ((vind << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK)); + /* Make sure we are using a valid rar index range */ + if (index < rar_entries) { + /* + * HW expects these in little endian so we reverse the byte + * order from network order (big endian) to little endian + */ + rar_low = ((u32)addr[0] | + ((u32)addr[1] << 8) | + ((u32)addr[2] << 16) | + ((u32)addr[3] << 24)); + /* + * Some parts put the VMDq setting in the extra RAH bits, + * so save everything except the lower 16 bits that hold part + * of the address and the address valid bit. + */ + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); + rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); + rar_high |= ((u32)addr[4] | ((u32)addr[5] << 8)); - if (enable_addr != 0) - rar_high |= IXGBE_RAH_AV; + if (enable_addr != 0) + rar_high |= IXGBE_RAH_AV; - IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); - IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); + IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); + IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); + } else { + hw_dbg(hw, "RAR index %d is out of range.\n", index); + } return 0; } /** - * ixgbe_init_rx_addrs - Initializes receive address filters. + * ixgbe_clear_rar_generic - Remove Rx address register + * @hw: pointer to hardware structure + * @index: Receive address register to write + * + * Clears an ethernet address from a receive address register. + **/ +s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) +{ + u32 rar_high; + u32 rar_entries = hw->mac.num_rar_entries; + + /* Make sure we are using a valid rar index range */ + if (index < rar_entries) { + /* + * Some parts put the VMDq setting in the extra RAH bits, + * so save everything except the lower 16 bits that hold part + * of the address and the address valid bit. + */ + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); + rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); + + IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); + } else { + hw_dbg(hw, "RAR index %d is out of range.\n", index); + } + + /* clear VMDq pool/queue selection for this RAR */ + hw->mac.ops.clear_vmdq(hw, index, IXGBE_CLEAR_VMDQ_ALL); + + return 0; +} + +/** + * ixgbe_enable_rar - Enable Rx address register + * @hw: pointer to hardware structure + * @index: index into the RAR table + * + * Enables the select receive address register. + **/ +static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index) +{ + u32 rar_high; + + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); + rar_high |= IXGBE_RAH_AV; + IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); +} + +/** + * ixgbe_disable_rar - Disable Rx address register + * @hw: pointer to hardware structure + * @index: index into the RAR table + * + * Disables the select receive address register. + **/ +static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index) +{ + u32 rar_high; + + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); + rar_high &= (~IXGBE_RAH_AV); + IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); +} + +/** + * ixgbe_init_rx_addrs_generic - Initializes receive address filters. * @hw: pointer to hardware structure * * Places the MAC address in receive address register 0 and clears the rest - * of the receive addresss registers. Clears the multicast table. Assumes + * of the receive address registers. Clears the multicast table. Assumes * the receiver is in reset when the routine is called. **/ -static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw) +s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw) { u32 i; - u32 rar_entries = hw->mac.num_rx_addrs; + u32 rar_entries = hw->mac.num_rar_entries; /* * If the current mac address is valid, assume it is a software override @@ -671,29 +1133,30 @@ static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw) if (ixgbe_validate_mac_addr(hw->mac.addr) == IXGBE_ERR_INVALID_MAC_ADDR) { /* Get the MAC address from the RAR0 for later reference */ - ixgbe_get_mac_addr(hw, hw->mac.addr); + hw->mac.ops.get_mac_addr(hw, hw->mac.addr); hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ", - hw->mac.addr[0], hw->mac.addr[1], - hw->mac.addr[2]); + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], - hw->mac.addr[4], hw->mac.addr[5]); + hw->mac.addr[4], hw->mac.addr[5]); } else { /* Setup the receive address. */ hw_dbg(hw, "Overriding MAC Address in RAR[0]\n"); hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ", - hw->mac.addr[0], hw->mac.addr[1], - hw->mac.addr[2]); + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], - hw->mac.addr[4], hw->mac.addr[5]); + hw->mac.addr[4], hw->mac.addr[5]); - ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); } + hw->addr_ctrl.overflow_promisc = 0; hw->addr_ctrl.rar_used_count = 1; /* Zero out the other receive addresses. */ - hw_dbg(hw, "Clearing RAR[1-15]\n"); + hw_dbg(hw, "Clearing RAR[1-%d]\n", rar_entries - 1); for (i = 1; i < rar_entries; i++) { IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); @@ -705,9 +1168,113 @@ static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); hw_dbg(hw, " Clearing MTA\n"); - for (i = 0; i < IXGBE_MC_TBL_SIZE; i++) + for (i = 0; i < hw->mac.mcft_size; i++) IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); + if (hw->mac.ops.init_uta_tables) + hw->mac.ops.init_uta_tables(hw); + + return 0; +} + +/** + * ixgbe_add_uc_addr - Adds a secondary unicast address. + * @hw: pointer to hardware structure + * @addr: new address + * + * Adds it to unused receive address register or goes into promiscuous mode. + **/ +static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) +{ + u32 rar_entries = hw->mac.num_rar_entries; + u32 rar; + + hw_dbg(hw, " UC Addr = %.2X %.2X %.2X %.2X %.2X %.2X\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + + /* + * Place this address in the RAR if there is room, + * else put the controller into promiscuous mode + */ + if (hw->addr_ctrl.rar_used_count < rar_entries) { + rar = hw->addr_ctrl.rar_used_count - + hw->addr_ctrl.mc_addr_in_rar_count; + hw->mac.ops.set_rar(hw, rar, addr, vmdq, IXGBE_RAH_AV); + hw_dbg(hw, "Added a secondary address to RAR[%d]\n", rar); + hw->addr_ctrl.rar_used_count++; + } else { + hw->addr_ctrl.overflow_promisc++; + } + + hw_dbg(hw, "ixgbe_add_uc_addr Complete\n"); +} + +/** + * ixgbe_update_uc_addr_list_generic - Updates MAC list of secondary addresses + * @hw: pointer to hardware structure + * @addr_list: the list of new addresses + * @addr_count: number of addresses + * @next: iterator function to walk the address list + * + * The given list replaces any existing list. Clears the secondary addrs from + * receive address registers. Uses unused receive address registers for the + * first secondary addresses, and falls back to promiscuous mode as needed. + * + * Drivers using secondary unicast addresses must set user_set_promisc when + * manually putting the device into promiscuous mode. + **/ +s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, + u32 addr_count, ixgbe_mc_addr_itr next) +{ + u8 *addr; + u32 i; + u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc; + u32 uc_addr_in_use; + u32 fctrl; + u32 vmdq; + + /* + * Clear accounting of old secondary address list, + * don't count RAR[0] + */ + uc_addr_in_use = hw->addr_ctrl.rar_used_count - + hw->addr_ctrl.mc_addr_in_rar_count - 1; + hw->addr_ctrl.rar_used_count -= uc_addr_in_use; + hw->addr_ctrl.overflow_promisc = 0; + + /* Zero out the other receive addresses */ + hw_dbg(hw, "Clearing RAR[1-%d]\n", uc_addr_in_use); + for (i = 1; i <= uc_addr_in_use; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); + } + + /* Add the new addresses */ + for (i = 0; i < addr_count; i++) { + hw_dbg(hw, " Adding the secondary addresses:\n"); + addr = next(hw, &addr_list, &vmdq); + ixgbe_add_uc_addr(hw, addr, vmdq); + } + + if (hw->addr_ctrl.overflow_promisc) { + /* enable promisc if not already in overflow or set by user */ + if (!old_promisc_setting && !hw->addr_ctrl.user_set_promisc) { + hw_dbg(hw, " Entering address overflow promisc mode\n"); + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + fctrl |= IXGBE_FCTRL_UPE; + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); + } + } else { + /* only disable if set by overflow, not by user */ + if (old_promisc_setting && !hw->addr_ctrl.user_set_promisc) { + hw_dbg(hw, " Leaving address overflow promisc mode\n"); + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + fctrl &= ~IXGBE_FCTRL_UPE; + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); + } + } + + hw_dbg(hw, "ixgbe_update_uc_addr_list_generic Complete\n"); return 0; } @@ -720,7 +1287,7 @@ static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw) * bit-vector to set in the multicast table. The hardware uses 12 bits, from * incoming rx multicast addresses, to determine the bit-vector to check in * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set - * by the MO field of the MCSTCTRL. The MO field is set during initalization + * by the MO field of the MCSTCTRL. The MO field is set during initialization * to mc_filter_type. **/ static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) @@ -728,19 +1295,19 @@ static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) u32 vector = 0; switch (hw->mac.mc_filter_type) { - case 0: /* use bits [47:36] of the address */ + case 0: /* use bits [47:36] of the address */ vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4)); break; - case 1: /* use bits [46:35] of the address */ + case 1: /* use bits [46:35] of the address */ vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5)); break; - case 2: /* use bits [45:34] of the address */ + case 2: /* use bits [45:34] of the address */ vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6)); break; - case 3: /* use bits [43:32] of the address */ + case 3: /* use bits [43:32] of the address */ vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8)); break; - default: /* Invalid mc_filter_type */ + default: /* Invalid mc_filter_type */ hw_dbg(hw, "MC filter type param set incorrectly\n"); break; } @@ -794,21 +1361,22 @@ static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr) **/ static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr) { - u32 rar_entries = hw->mac.num_rx_addrs; + u32 rar_entries = hw->mac.num_rar_entries; + u32 rar; hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n", - mc_addr[0], mc_addr[1], mc_addr[2], - mc_addr[3], mc_addr[4], mc_addr[5]); + mc_addr[0], mc_addr[1], mc_addr[2], + mc_addr[3], mc_addr[4], mc_addr[5]); /* * Place this multicast address in the RAR if there is room, * else put it in the MTA */ if (hw->addr_ctrl.rar_used_count < rar_entries) { - ixgbe_set_rar(hw, hw->addr_ctrl.rar_used_count, - mc_addr, 0, IXGBE_RAH_AV); - hw_dbg(hw, "Added a multicast address to RAR[%d]\n", - hw->addr_ctrl.rar_used_count); + /* use RAR from the end up for multicast */ + rar = rar_entries - hw->addr_ctrl.mc_addr_in_rar_count - 1; + hw->mac.ops.set_rar(hw, rar, mc_addr, 0, IXGBE_RAH_AV); + hw_dbg(hw, "Added a multicast address to RAR[%d]\n", rar); hw->addr_ctrl.rar_used_count++; hw->addr_ctrl.mc_addr_in_rar_count++; } else { @@ -819,22 +1387,23 @@ static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr) } /** - * ixgbe_update_mc_addr_list - Updates MAC list of multicast addresses + * ixgbe_update_mc_addr_list_generic - Updates MAC list of multicast addresses * @hw: pointer to hardware structure * @mc_addr_list: the list of new multicast addresses * @mc_addr_count: number of addresses - * @pad: number of bytes between addresses in the list + * @next: iterator function to walk the multicast address list * * The given list replaces any existing list. Clears the MC addrs from receive - * address registers and the multicast table. Uses unsed receive address + * address registers and the multicast table. Uses unused receive address * registers for the first multicast addresses, and hashes the rest into the * multicast table. **/ -s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, - u32 mc_addr_count, u32 pad) +s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, ixgbe_mc_addr_itr next) { u32 i; - u32 rar_entries = hw->mac.num_rx_addrs; + u32 rar_entries = hw->mac.num_rar_entries; + u32 vmdq; /* * Set the new number of MC addresses that we are being requested to @@ -846,7 +1415,8 @@ s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, hw->addr_ctrl.mta_in_use = 0; /* Zero out the other receive addresses. */ - hw_dbg(hw, "Clearing RAR[1-15]\n"); + hw_dbg(hw, "Clearing RAR[%d-%d]\n", hw->addr_ctrl.rar_used_count, + rar_entries - 1); for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) { IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); @@ -854,186 +1424,67 @@ s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, /* Clear the MTA */ hw_dbg(hw, " Clearing MTA\n"); - for (i = 0; i < IXGBE_MC_TBL_SIZE; i++) + for (i = 0; i < hw->mac.mcft_size; i++) IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); /* Add the new addresses */ for (i = 0; i < mc_addr_count; i++) { hw_dbg(hw, " Adding the multicast addresses:\n"); - ixgbe_add_mc_addr(hw, mc_addr_list + - (i * (IXGBE_ETH_LENGTH_OF_ADDRESS + pad))); + ixgbe_add_mc_addr(hw, next(hw, &mc_addr_list, &vmdq)); } /* Enable mta */ if (hw->addr_ctrl.mta_in_use > 0) IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, - IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type); + IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type); - hw_dbg(hw, "ixgbe_update_mc_addr_list Complete\n"); + hw_dbg(hw, "ixgbe_update_mc_addr_list_generic Complete\n"); return 0; } /** - * ixgbe_clear_vfta - Clear VLAN filter table + * ixgbe_enable_mc_generic - Enable multicast address in RAR * @hw: pointer to hardware structure * - * Clears the VLAN filer table, and the VMDq index associated with the filter + * Enables multicast address in RAR and the use of the multicast hash table. **/ -static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw) +s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw) { - u32 offset; - u32 vlanbyte; - - for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++) - IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0); - - for (vlanbyte = 0; vlanbyte < 4; vlanbyte++) - for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++) - IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset), - 0); + u32 i; + u32 rar_entries = hw->mac.num_rar_entries; + struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; - return 0; -} + if (a->mc_addr_in_rar_count > 0) + for (i = (rar_entries - a->mc_addr_in_rar_count); + i < rar_entries; i++) + ixgbe_enable_rar(hw, i); -/** - * ixgbe_set_vfta - Set VLAN filter table - * @hw: pointer to hardware structure - * @vlan: VLAN id to write to VLAN filter - * @vind: VMDq output index that maps queue to VLAN id in VFTA - * @vlan_on: boolean flag to turn on/off VLAN in VFTA - * - * Turn on/off specified VLAN in the VLAN filter table. - **/ -s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on) -{ - u32 VftaIndex; - u32 BitOffset; - u32 VftaReg; - u32 VftaByte; - - /* Determine 32-bit word position in array */ - VftaIndex = (vlan >> 5) & 0x7F; /* upper seven bits */ - - /* Determine the location of the (VMD) queue index */ - VftaByte = ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */ - BitOffset = (vlan & 0x7) << 2; /* lower 3 bits indicate nibble */ - - /* Set the nibble for VMD queue index */ - VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex)); - VftaReg &= (~(0x0F << BitOffset)); - VftaReg |= (vind << BitOffset); - IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex), VftaReg); - - /* Determine the location of the bit for this VLAN id */ - BitOffset = vlan & 0x1F; /* lower five bits */ - - VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTA(VftaIndex)); - if (vlan_on) - /* Turn on this VLAN id */ - VftaReg |= (1 << BitOffset); - else - /* Turn off this VLAN id */ - VftaReg &= ~(1 << BitOffset); - IXGBE_WRITE_REG(hw, IXGBE_VFTA(VftaIndex), VftaReg); + if (a->mta_in_use > 0) + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, IXGBE_MCSTCTRL_MFE | + hw->mac.mc_filter_type); return 0; } /** - * ixgbe_setup_fc - Configure flow control settings + * ixgbe_disable_mc_generic - Disable multicast address in RAR * @hw: pointer to hardware structure - * @packetbuf_num: packet buffer number (0-7) * - * Configures the flow control settings based on SW configuration. - * This function is used for 802.3x flow control configuration only. + * Disables multicast address in RAR and the use of the multicast hash table. **/ -s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) +s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) { - u32 frctl_reg; - u32 rmcs_reg; - - if (packetbuf_num < 0 || packetbuf_num > 7) - hw_dbg(hw, "Invalid packet buffer number [%d], expected range " - "is 0-7\n", packetbuf_num); - - frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); - frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); - - rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS); - rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X); - - /* - * We want to save off the original Flow Control configuration just in - * case we get disconnected and then reconnected into a different hub - * or switch with different Flow Control capabilities. - */ - hw->fc.type = hw->fc.original_type; - - /* - * The possible values of the "flow_control" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames but not - * send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but we do not - * support receiving pause frames) - * 3: Both Rx and TX flow control (symmetric) are enabled. - * other: Invalid. - */ - switch (hw->fc.type) { - case ixgbe_fc_none: - break; - case ixgbe_fc_rx_pause: - /* - * RX Flow control is enabled, - * and TX Flow control is disabled. - */ - frctl_reg |= IXGBE_FCTRL_RFCE; - break; - case ixgbe_fc_tx_pause: - /* - * TX Flow control is enabled, and RX Flow control is disabled, - * by a software over-ride. - */ - rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; - break; - case ixgbe_fc_full: - /* - * Flow control (both RX and TX) is enabled by a software - * over-ride. - */ - frctl_reg |= IXGBE_FCTRL_RFCE; - rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; - break; - default: - /* We should never get here. The value should be 0-3. */ - hw_dbg(hw, "Flow control param set incorrectly\n"); - break; - } - - /* Enable 802.3x based flow control settings. */ - IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg); - IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); + u32 i; + u32 rar_entries = hw->mac.num_rar_entries; + struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; - /* - * We need to set up the Receive Threshold high and low water - * marks as well as (optionally) enabling the transmission of - * XON frames. - */ - if (hw->fc.type & ixgbe_fc_tx_pause) { - if (hw->fc.send_xon) { - IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), - (hw->fc.low_water | IXGBE_FCRTL_XONE)); - } else { - IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), - hw->fc.low_water); - } - IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), - (hw->fc.high_water)|IXGBE_FCRTH_FCEN); - } + if (a->mc_addr_in_rar_count > 0) + for (i = (rar_entries - a->mc_addr_in_rar_count); + i < rar_entries; i++) + ixgbe_disable_rar(hw, i); - IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time); - IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); + if (a->mta_in_use > 0) + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); return 0; } @@ -1049,13 +1500,24 @@ s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) **/ s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) { - u32 ctrl; - s32 i; + u32 i; + u32 reg_val; + u32 number_of_queues; s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING; - ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); - ctrl |= IXGBE_CTRL_GIO_DIS; - IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl); + /* Disable the receive unit by stopping each queue */ + number_of_queues = hw->mac.max_rx_queues; + for (i = 0; i < number_of_queues; i++) { + reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); + if (reg_val & IXGBE_RXDCTL_ENABLE) { + reg_val &= ~IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), reg_val); + } + } + + reg_val = IXGBE_READ_REG(hw, IXGBE_CTRL); + reg_val |= IXGBE_CTRL_GIO_DIS; + IXGBE_WRITE_REG(hw, IXGBE_CTRL, reg_val); for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) { @@ -1070,11 +1532,11 @@ s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) /** - * ixgbe_acquire_swfw_sync - Aquire SWFW semaphore + * ixgbe_acquire_swfw_sync - Acquire SWFW semaphore * @hw: pointer to hardware structure - * @mask: Mask to specify wich semaphore to acquire + * @mask: Mask to specify which semaphore to acquire * - * Aquires the SWFW semaphore throught the GSSR register for the specified + * Acquires the SWFW semaphore thought the GSSR register for the specified * function (CSR, PHY0, PHY1, EEPROM, Flash) **/ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) @@ -1116,9 +1578,9 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) /** * ixgbe_release_swfw_sync - Release SWFW semaphore * @hw: pointer to hardware structure - * @mask: Mask to specify wich semaphore to release + * @mask: Mask to specify which semaphore to release * - * Releases the SWFW semaphore throught the GSSR register for the specified + * Releases the SWFW semaphore thought the GSSR register for the specified * function (CSR, PHY0, PHY1, EEPROM, Flash) **/ void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask) @@ -1135,45 +1597,3 @@ void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask) ixgbe_release_eeprom_semaphore(hw); } -/** - * ixgbe_read_analog_reg8 - Reads 8 bit Atlas analog register - * @hw: pointer to hardware structure - * @reg: analog register to read - * @val: read value - * - * Performs write operation to analog register specified. - **/ -s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val) -{ - u32 atlas_ctl; - - IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, - IXGBE_ATLASCTL_WRITE_CMD | (reg << 8)); - IXGBE_WRITE_FLUSH(hw); - udelay(10); - atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); - *val = (u8)atlas_ctl; - - return 0; -} - -/** - * ixgbe_write_analog_reg8 - Writes 8 bit Atlas analog register - * @hw: pointer to hardware structure - * @reg: atlas register to write - * @val: value to write - * - * Performs write operation to Atlas analog register specified. - **/ -s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val) -{ - u32 atlas_ctl; - - atlas_ctl = (reg << 8) | val; - IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl); - IXGBE_WRITE_FLUSH(hw); - udelay(10); - - return 0; -} - diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index de6ddd5d04a..192f8d01291 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2007 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -20,7 +20,6 @@ the file called "COPYING". Contact Information: - Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -31,34 +30,45 @@ #include "ixgbe_type.h" -s32 ixgbe_init_hw(struct ixgbe_hw *hw); -s32 ixgbe_start_hw(struct ixgbe_hw *hw); -s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr); -s32 ixgbe_stop_adapter(struct ixgbe_hw *hw); -s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num); +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_clear_hw_cntrs_generic(struct ixgbe_hw *hw); +s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num); +s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr); +s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw); +s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw); + +s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index); +s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); + +s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); +s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 *data); +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_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, + u32 enable_addr); +s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index); +s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw); +s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, + ixgbe_mc_addr_itr func); +s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, + u32 addr_count, ixgbe_mc_addr_itr func); +s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); +s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); -s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index); -s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index); - -s32 ixgbe_init_eeprom(struct ixgbe_hw *hw); -s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data); -s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val); - -s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind, - u32 enable_addr); -s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, - u32 mc_addr_count, u32 pad); -s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); s32 ixgbe_validate_mac_addr(u8 *mac_addr); - -s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packtetbuf_num); - s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask); void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask); s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw); -s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val); -s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val); +s32 ixgbe_read_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 *val); +s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val); #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 3efe5dda10a..81a9c4b8672 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2007 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -20,7 +20,6 @@ the file called "COPYING". Contact Information: - Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -48,7 +47,7 @@ struct ixgbe_stats { }; #define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \ - offsetof(struct ixgbe_adapter, m) + offsetof(struct ixgbe_adapter, m) static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"rx_packets", IXGBE_STAT(net_stats.rx_packets)}, {"tx_packets", IXGBE_STAT(net_stats.tx_packets)}, @@ -95,14 +94,15 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { }; #define IXGBE_QUEUE_STATS_LEN \ - ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ - ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ - (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) -#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) + ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ + ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ + (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) +#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) +#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) #define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) static int ixgbe_get_settings(struct net_device *netdev, - struct ethtool_cmd *ecmd) + struct ethtool_cmd *ecmd) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; @@ -114,7 +114,7 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_EXTERNAL; if (hw->phy.media_type == ixgbe_media_type_copper) { ecmd->supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_TP | SUPPORTED_Autoneg); + SUPPORTED_TP | SUPPORTED_Autoneg); ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) @@ -126,14 +126,15 @@ static int ixgbe_get_settings(struct net_device *netdev, } else { ecmd->supported |= SUPPORTED_FIBRE; ecmd->advertising = (ADVERTISED_10000baseT_Full | - ADVERTISED_FIBRE); + ADVERTISED_FIBRE); ecmd->port = PORT_FIBRE; + ecmd->autoneg = AUTONEG_DISABLE; } - adapter->hw.mac.ops.check_link(hw, &(link_speed), &link_up); + hw->mac.ops.check_link(hw, &link_speed, &link_up, false); if (link_up) { ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? - SPEED_10000 : SPEED_1000; + SPEED_10000 : SPEED_1000; ecmd->duplex = DUPLEX_FULL; } else { ecmd->speed = -1; @@ -144,7 +145,7 @@ static int ixgbe_get_settings(struct net_device *netdev, } static int ixgbe_set_settings(struct net_device *netdev, - struct ethtool_cmd *ecmd) + struct ethtool_cmd *ecmd) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; @@ -164,7 +165,7 @@ static int ixgbe_set_settings(struct net_device *netdev, } static void ixgbe_get_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) + struct ethtool_pauseparam *pause) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; @@ -182,7 +183,7 @@ static void ixgbe_get_pauseparam(struct net_device *netdev, } static int ixgbe_set_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) + struct ethtool_pauseparam *pause) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; @@ -233,15 +234,15 @@ static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data) static u32 ixgbe_get_tx_csum(struct net_device *netdev) { - return (netdev->features & NETIF_F_HW_CSUM) != 0; + return (netdev->features & NETIF_F_IP_CSUM) != 0; } static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data) { if (data) - netdev->features |= NETIF_F_HW_CSUM; + netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); else - netdev->features &= ~NETIF_F_HW_CSUM; + netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); return 0; } @@ -281,7 +282,7 @@ static int ixgbe_get_regs_len(struct net_device *netdev) #define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_ static void ixgbe_get_regs(struct net_device *netdev, - struct ethtool_regs *regs, void *p) + struct ethtool_regs *regs, void *p) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; @@ -315,7 +316,9 @@ static void ixgbe_get_regs(struct net_device *netdev, regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC); /* Interrupt */ - regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICR); + /* don't read EICR because it can clear interrupt causes, instead + * read EICS which is a shadow but doesn't clear EICR */ + regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICS); regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS); regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS); regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC); @@ -325,7 +328,7 @@ static void ixgbe_get_regs(struct net_device *netdev, regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0)); regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT); regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA); - regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL); + regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL(0)); regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE); /* Flow Control */ @@ -371,7 +374,7 @@ static void ixgbe_get_regs(struct net_device *netdev, regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i)); for (i = 0; i < 16; i++) regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i)); - regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE); + regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE(0)); regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL); regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL); @@ -419,7 +422,6 @@ static void ixgbe_get_regs(struct net_device *netdev, regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM); regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT); - /* DCE */ regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS); regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS); regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS); @@ -539,21 +541,17 @@ static void ixgbe_get_regs(struct net_device *netdev, /* Diagnostic */ regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL); for (i = 0; i < 8; i++) - regs_buff[1072] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i)); + regs_buff[1072 + i] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i)); regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN); - regs_buff[1081] = IXGBE_READ_REG(hw, IXGBE_RIC_DW0); - regs_buff[1082] = IXGBE_READ_REG(hw, IXGBE_RIC_DW1); - regs_buff[1083] = IXGBE_READ_REG(hw, IXGBE_RIC_DW2); - regs_buff[1084] = IXGBE_READ_REG(hw, IXGBE_RIC_DW3); + for (i = 0; i < 4; i++) + regs_buff[1081 + i] = IXGBE_READ_REG(hw, IXGBE_RIC_DW(i)); regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE); regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL); for (i = 0; i < 8; i++) - regs_buff[1087] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i)); + regs_buff[1087 + i] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i)); regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN); - regs_buff[1096] = IXGBE_READ_REG(hw, IXGBE_TIC_DW0); - regs_buff[1097] = IXGBE_READ_REG(hw, IXGBE_TIC_DW1); - regs_buff[1098] = IXGBE_READ_REG(hw, IXGBE_TIC_DW2); - regs_buff[1099] = IXGBE_READ_REG(hw, IXGBE_TIC_DW3); + for (i = 0; i < 4; i++) + regs_buff[1096 + i] = IXGBE_READ_REG(hw, IXGBE_TIC_DW(i)); regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE); regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL); regs_buff[1102] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA0); @@ -566,7 +564,7 @@ static void ixgbe_get_regs(struct net_device *netdev, regs_buff[1109] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA2); regs_buff[1110] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA3); for (i = 0; i < 8; i++) - regs_buff[1111] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i)); + regs_buff[1111 + i] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i)); regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL); regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1); regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2); @@ -585,7 +583,7 @@ static int ixgbe_get_eeprom_len(struct net_device *netdev) } static int ixgbe_get_eeprom(struct net_device *netdev, - struct ethtool_eeprom *eeprom, u8 *bytes) + struct ethtool_eeprom *eeprom, u8 *bytes) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; @@ -608,8 +606,8 @@ static int ixgbe_get_eeprom(struct net_device *netdev, return -ENOMEM; for (i = 0; i < eeprom_len; i++) { - if ((ret_val = ixgbe_read_eeprom(hw, first_word + i, - &eeprom_buff[i]))) + if ((ret_val = hw->eeprom.ops.read(hw, first_word + i, + &eeprom_buff[i]))) break; } @@ -624,7 +622,7 @@ static int ixgbe_get_eeprom(struct net_device *netdev, } static void ixgbe_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *drvinfo) + struct ethtool_drvinfo *drvinfo) { struct ixgbe_adapter *adapter = netdev_priv(netdev); @@ -637,7 +635,7 @@ static void ixgbe_get_drvinfo(struct net_device *netdev, } static void ixgbe_get_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ring) + struct ethtool_ringparam *ring) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_ring *tx_ring = adapter->tx_ring; @@ -654,15 +652,12 @@ static void ixgbe_get_ringparam(struct net_device *netdev, } static int ixgbe_set_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ring) + struct ethtool_ringparam *ring) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - struct ixgbe_tx_buffer *old_buf; - struct ixgbe_rx_buffer *old_rx_buf; - void *old_desc; + struct ixgbe_ring *temp_ring; int i, err; - u32 new_rx_count, new_tx_count, old_size; - dma_addr_t old_dma; + u32 new_rx_count, new_tx_count; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; @@ -681,6 +676,15 @@ static int ixgbe_set_ringparam(struct net_device *netdev, return 0; } + if (adapter->num_tx_queues > adapter->num_rx_queues) + temp_ring = vmalloc(adapter->num_tx_queues * + sizeof(struct ixgbe_ring)); + else + temp_ring = vmalloc(adapter->num_rx_queues * + sizeof(struct ixgbe_ring)); + if (!temp_ring) + return -ENOMEM; + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); @@ -693,66 +697,61 @@ static int ixgbe_set_ringparam(struct net_device *netdev, * to the tx and rx ring structs. */ if (new_tx_count != adapter->tx_ring->count) { + memcpy(temp_ring, adapter->tx_ring, + adapter->num_tx_queues * sizeof(struct ixgbe_ring)); + for (i = 0; i < adapter->num_tx_queues; i++) { - /* Save existing descriptor ring */ - old_buf = adapter->tx_ring[i].tx_buffer_info; - old_desc = adapter->tx_ring[i].desc; - old_size = adapter->tx_ring[i].size; - old_dma = adapter->tx_ring[i].dma; - /* Try to allocate a new one */ - adapter->tx_ring[i].tx_buffer_info = NULL; - adapter->tx_ring[i].desc = NULL; - adapter->tx_ring[i].count = new_tx_count; - err = ixgbe_setup_tx_resources(adapter, - &adapter->tx_ring[i]); + temp_ring[i].count = new_tx_count; + err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]); if (err) { - /* Restore the old one so at least - the adapter still works, even if - we failed the request */ - adapter->tx_ring[i].tx_buffer_info = old_buf; - adapter->tx_ring[i].desc = old_desc; - adapter->tx_ring[i].size = old_size; - adapter->tx_ring[i].dma = old_dma; + while (i) { + i--; + ixgbe_free_tx_resources(adapter, + &temp_ring[i]); + } goto err_setup; } - /* Free the old buffer manually */ - vfree(old_buf); - pci_free_consistent(adapter->pdev, old_size, - old_desc, old_dma); } + + for (i = 0; i < adapter->num_tx_queues; i++) + ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]); + + memcpy(adapter->tx_ring, temp_ring, + adapter->num_tx_queues * sizeof(struct ixgbe_ring)); + + adapter->tx_ring_count = new_tx_count; } if (new_rx_count != adapter->rx_ring->count) { - for (i = 0; i < adapter->num_rx_queues; i++) { + memcpy(temp_ring, adapter->rx_ring, + adapter->num_rx_queues * sizeof(struct ixgbe_ring)); - old_rx_buf = adapter->rx_ring[i].rx_buffer_info; - old_desc = adapter->rx_ring[i].desc; - old_size = adapter->rx_ring[i].size; - old_dma = adapter->rx_ring[i].dma; - - adapter->rx_ring[i].rx_buffer_info = NULL; - adapter->rx_ring[i].desc = NULL; - adapter->rx_ring[i].dma = 0; - adapter->rx_ring[i].count = new_rx_count; - err = ixgbe_setup_rx_resources(adapter, - &adapter->rx_ring[i]); + for (i = 0; i < adapter->num_rx_queues; i++) { + temp_ring[i].count = new_rx_count; + err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); if (err) { - adapter->rx_ring[i].rx_buffer_info = old_rx_buf; - adapter->rx_ring[i].desc = old_desc; - adapter->rx_ring[i].size = old_size; - adapter->rx_ring[i].dma = old_dma; + while (i) { + i--; + ixgbe_free_rx_resources(adapter, + &temp_ring[i]); + } goto err_setup; } - - vfree(old_rx_buf); - pci_free_consistent(adapter->pdev, old_size, old_desc, - old_dma); } + + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]); + + memcpy(adapter->rx_ring, temp_ring, + adapter->num_rx_queues * sizeof(struct ixgbe_ring)); + + adapter->rx_ring_count = new_rx_count; } + /* success! */ err = 0; err_setup: - if (netif_running(adapter->netdev)) + if (netif_running(netdev)) ixgbe_up(adapter); clear_bit(__IXGBE_RESETTING, &adapter->state); @@ -770,7 +769,7 @@ static int ixgbe_get_sset_count(struct net_device *netdev, int sset) } static void ixgbe_get_ethtool_stats(struct net_device *netdev, - struct ethtool_stats *stats, u64 *data) + struct ethtool_stats *stats, u64 *data) { struct ixgbe_adapter *adapter = netdev_priv(netdev); u64 *queue_stat; @@ -778,12 +777,20 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, int j, k; int i; u64 aggregated = 0, flushed = 0, no_desc = 0; + for (i = 0; i < adapter->num_rx_queues; i++) { + aggregated += adapter->rx_ring[i].lro_mgr.stats.aggregated; + flushed += adapter->rx_ring[i].lro_mgr.stats.flushed; + no_desc += adapter->rx_ring[i].lro_mgr.stats.no_desc; + } + adapter->lro_aggregated = aggregated; + adapter->lro_flushed = flushed; + adapter->lro_no_desc = no_desc; ixgbe_update_stats(adapter); for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset; data[i] = (ixgbe_gstrings_stats[i].sizeof_stat == - sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } for (j = 0; j < adapter->num_tx_queues; j++) { queue_stat = (u64 *)&adapter->tx_ring[j].stats; @@ -792,24 +799,18 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, i += k; } for (j = 0; j < adapter->num_rx_queues; j++) { - aggregated += adapter->rx_ring[j].lro_mgr.stats.aggregated; - flushed += adapter->rx_ring[j].lro_mgr.stats.flushed; - no_desc += adapter->rx_ring[j].lro_mgr.stats.no_desc; queue_stat = (u64 *)&adapter->rx_ring[j].stats; for (k = 0; k < stat_count; k++) data[i + k] = queue_stat[k]; i += k; } - adapter->lro_aggregated = aggregated; - adapter->lro_flushed = flushed; - adapter->lro_no_desc = no_desc; } static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, - u8 *data) + u8 *data) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - u8 *p = data; + char *p = (char *)data; int i; switch (stringset) { @@ -831,14 +832,14 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, sprintf(p, "rx_queue_%u_bytes", i); p += ETH_GSTRING_LEN; } -/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ + /* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ break; } } static void ixgbe_get_wol(struct net_device *netdev, - struct ethtool_wolinfo *wol) + struct ethtool_wolinfo *wol) { wol->supported = 0; wol->wolopts = 0; @@ -859,16 +860,17 @@ static int ixgbe_nway_reset(struct net_device *netdev) static int ixgbe_phys_id(struct net_device *netdev, u32 data) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - u32 led_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_LEDCTL); + struct ixgbe_hw *hw = &adapter->hw; + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); u32 i; if (!data || data > 300) data = 300; for (i = 0; i < (data * 1000); i += 400) { - ixgbe_led_on(&adapter->hw, IXGBE_LED_ON); + hw->mac.ops.led_on(hw, IXGBE_LED_ON); msleep_interruptible(200); - ixgbe_led_off(&adapter->hw, IXGBE_LED_ON); + hw->mac.ops.led_off(hw, IXGBE_LED_ON); msleep_interruptible(200); } @@ -879,67 +881,75 @@ static int ixgbe_phys_id(struct net_device *netdev, u32 data) } static int ixgbe_get_coalesce(struct net_device *netdev, - struct ethtool_coalesce *ec) + struct ethtool_coalesce *ec) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - if (adapter->rx_eitr < IXGBE_MIN_ITR_USECS) - ec->rx_coalesce_usecs = adapter->rx_eitr; - else - ec->rx_coalesce_usecs = 1000000 / adapter->rx_eitr; - - if (adapter->tx_eitr < IXGBE_MIN_ITR_USECS) - ec->tx_coalesce_usecs = adapter->tx_eitr; - else - ec->tx_coalesce_usecs = 1000000 / adapter->tx_eitr; - ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit; + + /* only valid if in constant ITR mode */ + switch (adapter->itr_setting) { + case 0: + /* throttling disabled */ + ec->rx_coalesce_usecs = 0; + break; + case 1: + /* dynamic ITR mode */ + ec->rx_coalesce_usecs = 1; + break; + default: + /* fixed interrupt rate mode */ + ec->rx_coalesce_usecs = 1000000/adapter->eitr_param; + break; + } return 0; } static int ixgbe_set_coalesce(struct net_device *netdev, - struct ethtool_coalesce *ec) + struct ethtool_coalesce *ec) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - - if ((ec->rx_coalesce_usecs > IXGBE_MAX_ITR_USECS) || - ((ec->rx_coalesce_usecs != 0) && - (ec->rx_coalesce_usecs != 1) && - (ec->rx_coalesce_usecs != 3) && - (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS))) - return -EINVAL; - if ((ec->tx_coalesce_usecs > IXGBE_MAX_ITR_USECS) || - ((ec->tx_coalesce_usecs != 0) && - (ec->tx_coalesce_usecs != 1) && - (ec->tx_coalesce_usecs != 3) && - (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS))) - return -EINVAL; - - /* convert to rate of irq's per second */ - if (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS) - adapter->rx_eitr = ec->rx_coalesce_usecs; - else - adapter->rx_eitr = (1000000 / ec->rx_coalesce_usecs); - - if (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS) - adapter->tx_eitr = ec->rx_coalesce_usecs; - else - adapter->tx_eitr = (1000000 / ec->tx_coalesce_usecs); + struct ixgbe_hw *hw = &adapter->hw; + int i; if (ec->tx_max_coalesced_frames_irq) - adapter->tx_ring[0].work_limit = - ec->tx_max_coalesced_frames_irq; + adapter->tx_ring[0].work_limit = ec->tx_max_coalesced_frames_irq; + + if (ec->rx_coalesce_usecs > 1) { + /* store the value in ints/second */ + adapter->eitr_param = 1000000/ec->rx_coalesce_usecs; + + /* static value of interrupt rate */ + adapter->itr_setting = adapter->eitr_param; + /* clear the lower bit */ + adapter->itr_setting &= ~1; + } else if (ec->rx_coalesce_usecs == 1) { + /* 1 means dynamic mode */ + adapter->eitr_param = 20000; + adapter->itr_setting = 1; + } else { + /* any other value means disable eitr, which is best + * served by setting the interrupt rate very high */ + adapter->eitr_param = 3000000; + adapter->itr_setting = 0; + } - if (netif_running(netdev)) { - ixgbe_down(adapter); - ixgbe_up(adapter); + for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { + struct ixgbe_q_vector *q_vector = &adapter->q_vector[i]; + if (q_vector->txr_count && !q_vector->rxr_count) + q_vector->eitr = (adapter->eitr_param >> 1); + else + /* rx only or mixed */ + q_vector->eitr = adapter->eitr_param; + IXGBE_WRITE_REG(hw, IXGBE_EITR(i), + EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); } return 0; } -static struct ethtool_ops ixgbe_ethtool_ops = { +static const struct ethtool_ops ixgbe_ethtool_ops = { .get_settings = ixgbe_get_settings, .set_settings = ixgbe_set_settings, .get_drvinfo = ixgbe_get_drvinfo, @@ -966,7 +976,7 @@ static struct ethtool_ops ixgbe_ethtool_ops = { .set_tso = ixgbe_set_tso, .get_strings = ixgbe_get_strings, .phys_id = ixgbe_phys_id, - .get_sset_count = ixgbe_get_sset_count, + .get_sset_count = ixgbe_get_sset_count, .get_ethtool_stats = ixgbe_get_ethtool_stats, .get_coalesce = ixgbe_get_coalesce, .set_coalesce = ixgbe_set_coalesce, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a417be7f8be..7548fb7360d 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2007 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -20,7 +20,6 @@ the file called "COPYING". Contact Information: - Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -46,15 +45,14 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = - "Intel(R) 10 Gigabit PCI Express Network Driver"; + "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "1.3.18-k4" +#define DRV_VERSION "1.3.30-k2" const char ixgbe_driver_version[] = DRV_VERSION; -static const char ixgbe_copyright[] = - "Copyright (c) 1999-2007 Intel Corporation."; +static char ixgbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation."; static const struct ixgbe_info *ixgbe_info_tbl[] = { - [board_82598] = &ixgbe_82598_info, + [board_82598] = &ixgbe_82598_info, }; /* ixgbe_pci_tbl - PCI Device ID Table @@ -74,15 +72,17 @@ static struct pci_device_id ixgbe_pci_tbl[] = { board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), + board_82598 }, /* required last entry */ {0, } }; MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl); -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA static int ixgbe_notify_dca(struct notifier_block *, unsigned long event, - void *p); + void *p); static struct notifier_block dca_notifier = { .notifier_call = ixgbe_notify_dca, .next = NULL, @@ -104,7 +104,7 @@ static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter) /* Let firmware take over control of h/w */ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, - ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD); + ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD); } static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter) @@ -114,24 +114,11 @@ static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter) /* Let firmware know the driver has taken over */ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, - ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD); -} - -#ifdef DEBUG -/** - * ixgbe_get_hw_dev_name - return device name string - * used by hardware layer to print debugging information - **/ -char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw) -{ - struct ixgbe_adapter *adapter = hw->back; - struct net_device *netdev = adapter->netdev; - return netdev->name; + ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD); } -#endif static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry, - u8 msix_vector) + u8 msix_vector) { u32 ivar, index; @@ -144,13 +131,12 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry, } static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, - struct ixgbe_tx_buffer - *tx_buffer_info) + struct ixgbe_tx_buffer + *tx_buffer_info) { if (tx_buffer_info->dma) { - pci_unmap_page(adapter->pdev, - tx_buffer_info->dma, - tx_buffer_info->length, PCI_DMA_TODEVICE); + pci_unmap_page(adapter->pdev, tx_buffer_info->dma, + tx_buffer_info->length, PCI_DMA_TODEVICE); tx_buffer_info->dma = 0; } if (tx_buffer_info->skb) { @@ -161,107 +147,120 @@ static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, } static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter, - struct ixgbe_ring *tx_ring, - unsigned int eop, - union ixgbe_adv_tx_desc *eop_desc) + struct ixgbe_ring *tx_ring, + unsigned int eop) { + struct ixgbe_hw *hw = &adapter->hw; + u32 head, tail; + /* Detect a transmit hang in hardware, this serializes the - * check with the clearing of time_stamp and movement of i */ + * check with the clearing of time_stamp and movement of eop */ + head = IXGBE_READ_REG(hw, tx_ring->head); + tail = IXGBE_READ_REG(hw, tx_ring->tail); adapter->detect_tx_hung = false; - if (tx_ring->tx_buffer_info[eop].dma && + if ((head != tail) && + tx_ring->tx_buffer_info[eop].time_stamp && time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) && !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) { /* detected Tx unit hang */ + union ixgbe_adv_tx_desc *tx_desc; + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" - " TDH <%x>\n" - " TDT <%x>\n" + " Tx Queue <%d>\n" + " TDH, TDT <%x>, <%x>\n" " next_to_use <%x>\n" " next_to_clean <%x>\n" "tx_buffer_info[next_to_clean]\n" " time_stamp <%lx>\n" - " next_to_watch <%x>\n" - " jiffies <%lx>\n" - " next_to_watch.status <%x>\n", - readl(adapter->hw.hw_addr + tx_ring->head), - readl(adapter->hw.hw_addr + tx_ring->tail), - tx_ring->next_to_use, - tx_ring->next_to_clean, - tx_ring->tx_buffer_info[eop].time_stamp, - eop, jiffies, eop_desc->wb.status); + " jiffies <%lx>\n", + tx_ring->queue_index, + head, tail, + tx_ring->next_to_use, eop, + tx_ring->tx_buffer_info[eop].time_stamp, jiffies); return true; } return false; } -#define IXGBE_MAX_TXD_PWR 14 -#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) +#define IXGBE_MAX_TXD_PWR 14 +#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) /* Tx Descriptors needed, worst case */ #define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \ (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0)) #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ - MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ + MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ + +#define GET_TX_HEAD_FROM_RING(ring) (\ + *(volatile u32 *) \ + ((union ixgbe_adv_tx_desc *)(ring)->desc + (ring)->count)) +static void ixgbe_tx_timeout(struct net_device *netdev); /** * ixgbe_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure + * @tx_ring: tx ring to clean **/ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, - struct ixgbe_ring *tx_ring) + struct ixgbe_ring *tx_ring) { - struct net_device *netdev = adapter->netdev; - union ixgbe_adv_tx_desc *tx_desc, *eop_desc; + union ixgbe_adv_tx_desc *tx_desc; struct ixgbe_tx_buffer *tx_buffer_info; - unsigned int i, eop; - bool cleaned = false; - unsigned int total_tx_bytes = 0, total_tx_packets = 0; + struct net_device *netdev = adapter->netdev; + struct sk_buff *skb; + unsigned int i; + u32 head, oldhead; + unsigned int count = 0; + unsigned int total_bytes = 0, total_packets = 0; + rmb(); + head = GET_TX_HEAD_FROM_RING(tx_ring); + head = le32_to_cpu(head); i = tx_ring->next_to_clean; - eop = tx_ring->tx_buffer_info[i].next_to_watch; - eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); - while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) { - cleaned = false; - while (!cleaned) { + while (1) { + while (i != head) { tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); tx_buffer_info = &tx_ring->tx_buffer_info[i]; - cleaned = (i == eop); + skb = tx_buffer_info->skb; - tx_ring->stats.bytes += tx_buffer_info->length; - if (cleaned) { - struct sk_buff *skb = tx_buffer_info->skb; + if (skb) { unsigned int segs, bytecount; + + /* gso_segs is currently only valid for tcp */ segs = skb_shinfo(skb)->gso_segs ?: 1; /* multiply data chunks by size of headers */ bytecount = ((segs - 1) * skb_headlen(skb)) + - skb->len; - total_tx_packets += segs; - total_tx_bytes += bytecount; + skb->len; + total_packets += segs; + total_bytes += bytecount; } + ixgbe_unmap_and_free_tx_resource(adapter, - tx_buffer_info); - tx_desc->wb.status = 0; + tx_buffer_info); i++; if (i == tx_ring->count) i = 0; - } - - tx_ring->stats.packets++; - - eop = tx_ring->tx_buffer_info[i].next_to_watch; - eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); - - /* weight of a sort for tx, avoid endless transmit cleanup */ - if (total_tx_packets >= tx_ring->work_limit) - break; - } + count++; + if (count == tx_ring->count) + goto done_cleaning; + } + oldhead = head; + rmb(); + head = GET_TX_HEAD_FROM_RING(tx_ring); + head = le32_to_cpu(head); + if (head == oldhead) + goto done_cleaning; + } /* while (1) */ + +done_cleaning: tx_ring->next_to_clean = i; #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) - if (total_tx_packets && netif_carrier_ok(netdev) && - (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) { + if (unlikely(count && netif_carrier_ok(netdev) && + (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) { /* Make sure that anybody stopping the queue after this * sees the new next_to_clean. */ @@ -269,59 +268,68 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) && !test_bit(__IXGBE_DOWN, &adapter->state)) { netif_wake_subqueue(netdev, tx_ring->queue_index); - adapter->restart_queue++; + ++adapter->restart_queue; } } - if (adapter->detect_tx_hung) - if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc)) - netif_stop_subqueue(netdev, tx_ring->queue_index); - - if (total_tx_packets >= tx_ring->work_limit) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value); + if (adapter->detect_tx_hung) { + if (ixgbe_check_tx_hang(adapter, tx_ring, i)) { + /* schedule immediate reset if we believe we hung */ + DPRINTK(PROBE, INFO, + "tx hang %d detected, resetting adapter\n", + adapter->tx_timeout_count + 1); + ixgbe_tx_timeout(adapter->netdev); + } + } - tx_ring->total_bytes += total_tx_bytes; - tx_ring->total_packets += total_tx_packets; - adapter->net_stats.tx_bytes += total_tx_bytes; - adapter->net_stats.tx_packets += total_tx_packets; - cleaned = total_tx_packets ? true : false; - return cleaned; + /* re-arm the interrupt */ + if ((total_packets >= tx_ring->work_limit) || + (count == tx_ring->count)) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->v_idx); + + tx_ring->total_bytes += total_bytes; + tx_ring->total_packets += total_packets; + tx_ring->stats.bytes += total_bytes; + tx_ring->stats.packets += total_packets; + adapter->net_stats.tx_bytes += total_bytes; + adapter->net_stats.tx_packets += total_packets; + return (total_packets ? true : false); } -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter, - struct ixgbe_ring *rxr) + struct ixgbe_ring *rx_ring) { u32 rxctrl; int cpu = get_cpu(); - int q = rxr - adapter->rx_ring; + int q = rx_ring - adapter->rx_ring; - if (rxr->cpu != cpu) { + if (rx_ring->cpu != cpu) { rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q)); rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK; - rxctrl |= dca_get_tag(cpu); + rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu); rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN; rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN; IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q), rxctrl); - rxr->cpu = cpu; + rx_ring->cpu = cpu; } put_cpu(); } static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter, - struct ixgbe_ring *txr) + struct ixgbe_ring *tx_ring) { u32 txctrl; int cpu = get_cpu(); - int q = txr - adapter->tx_ring; + int q = tx_ring - adapter->tx_ring; - if (txr->cpu != cpu) { + if (tx_ring->cpu != cpu) { txctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q)); txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK; - txctrl |= dca_get_tag(cpu); + txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu); txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q), txctrl); - txr->cpu = cpu; + tx_ring->cpu = cpu; } put_cpu(); } @@ -351,11 +359,14 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) switch (event) { case DCA_PROVIDER_ADD: - adapter->flags |= IXGBE_FLAG_DCA_ENABLED; + /* if we're already enabled, don't do it again */ + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) + break; /* Always use CB2 mode, difference is masked * in the CB driver. */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2); if (dca_add_requester(dev) == 0) { + adapter->flags |= IXGBE_FLAG_DCA_ENABLED; ixgbe_setup_dca(adapter); break; } @@ -372,7 +383,7 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) return 0; } -#endif /* CONFIG_DCA */ +#endif /* CONFIG_IXGBE_DCA */ /** * ixgbe_receive_skb - Send a completed packet up the stack * @adapter: board private structure @@ -382,8 +393,8 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) * @rx_desc: rx descriptor **/ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, - struct sk_buff *skb, u8 status, - struct ixgbe_ring *ring, + struct sk_buff *skb, u8 status, + struct ixgbe_ring *ring, union ixgbe_adv_rx_desc *rx_desc) { bool is_vlan = (status & IXGBE_RXD_STAT_VP); @@ -420,14 +431,12 @@ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, * @skb: skb currently being received and modified **/ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter, - u32 status_err, - struct sk_buff *skb) + u32 status_err, struct sk_buff *skb) { skb->ip_summed = CHECKSUM_NONE; - /* Ignore Checksum bit is set, or rx csum disabled */ - if ((status_err & IXGBE_RXD_STAT_IXSM) || - !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) + /* Rx csum disabled */ + if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) return; /* if IP and error */ @@ -455,37 +464,44 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter, * @adapter: address of board private structure **/ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, - struct ixgbe_ring *rx_ring, - int cleaned_count) + struct ixgbe_ring *rx_ring, + int cleaned_count) { - struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; union ixgbe_adv_rx_desc *rx_desc; - struct ixgbe_rx_buffer *rx_buffer_info; - struct sk_buff *skb; + struct ixgbe_rx_buffer *bi; unsigned int i; - unsigned int bufsz = adapter->rx_buf_len + NET_IP_ALIGN; + unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN; i = rx_ring->next_to_use; - rx_buffer_info = &rx_ring->rx_buffer_info[i]; + bi = &rx_ring->rx_buffer_info[i]; while (cleaned_count--) { rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); - if (!rx_buffer_info->page && - (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) { - rx_buffer_info->page = alloc_page(GFP_ATOMIC); - if (!rx_buffer_info->page) { - adapter->alloc_rx_page_failed++; - goto no_buffers; + if (!bi->page_dma && + (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) { + if (!bi->page) { + bi->page = alloc_page(GFP_ATOMIC); + if (!bi->page) { + adapter->alloc_rx_page_failed++; + goto no_buffers; + } + bi->page_offset = 0; + } else { + /* use a half page if we're re-using */ + bi->page_offset ^= (PAGE_SIZE / 2); } - rx_buffer_info->page_dma = - pci_map_page(pdev, rx_buffer_info->page, - 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); + + bi->page_dma = pci_map_page(pdev, bi->page, + bi->page_offset, + (PAGE_SIZE / 2), + PCI_DMA_FROMDEVICE); } - if (!rx_buffer_info->skb) { - skb = netdev_alloc_skb(netdev, bufsz); + if (!bi->skb) { + struct sk_buff *skb = netdev_alloc_skb(adapter->netdev, + bufsz); if (!skb) { adapter->alloc_rx_buff_failed++; @@ -499,28 +515,25 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, */ skb_reserve(skb, NET_IP_ALIGN); - rx_buffer_info->skb = skb; - rx_buffer_info->dma = pci_map_single(pdev, skb->data, - bufsz, - PCI_DMA_FROMDEVICE); + bi->skb = skb; + bi->dma = pci_map_single(pdev, skb->data, bufsz, + PCI_DMA_FROMDEVICE); } /* Refresh the desc even if buffer_addrs didn't change because * each write-back erases this info. */ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { - rx_desc->read.pkt_addr = - cpu_to_le64(rx_buffer_info->page_dma); - rx_desc->read.hdr_addr = - cpu_to_le64(rx_buffer_info->dma); + rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma); + rx_desc->read.hdr_addr = cpu_to_le64(bi->dma); } else { - rx_desc->read.pkt_addr = - cpu_to_le64(rx_buffer_info->dma); + rx_desc->read.pkt_addr = cpu_to_le64(bi->dma); } i++; if (i == rx_ring->count) i = 0; - rx_buffer_info = &rx_ring->rx_buffer_info[i]; + bi = &rx_ring->rx_buffer_info[i]; } + no_buffers: if (rx_ring->next_to_use != i) { rx_ring->next_to_use = i; @@ -538,46 +551,54 @@ no_buffers: } } +static inline u16 ixgbe_get_hdr_info(union ixgbe_adv_rx_desc *rx_desc) +{ + return rx_desc->wb.lower.lo_dword.hs_rss.hdr_info; +} + +static inline u16 ixgbe_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc) +{ + return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; +} + static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, - struct ixgbe_ring *rx_ring, - int *work_done, int work_to_do) + struct ixgbe_ring *rx_ring, + int *work_done, int work_to_do) { - struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; union ixgbe_adv_rx_desc *rx_desc, *next_rxd; struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer; struct sk_buff *skb; unsigned int i; - u32 upper_len, len, staterr; + u32 len, staterr; u16 hdr_info; bool cleaned = false; int cleaned_count = 0; unsigned int total_rx_bytes = 0, total_rx_packets = 0; i = rx_ring->next_to_clean; - upper_len = 0; rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); staterr = le32_to_cpu(rx_desc->wb.upper.status_error); rx_buffer_info = &rx_ring->rx_buffer_info[i]; while (staterr & IXGBE_RXD_STAT_DD) { + u32 upper_len = 0; if (*work_done >= work_to_do) break; (*work_done)++; if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { - hdr_info = - le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info); - len = - ((hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >> - IXGBE_RXDADV_HDRBUFLEN_SHIFT); + hdr_info = le16_to_cpu(ixgbe_get_hdr_info(rx_desc)); + len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >> + IXGBE_RXDADV_HDRBUFLEN_SHIFT; if (hdr_info & IXGBE_RXDADV_SPH) adapter->rx_hdr_split++; if (len > IXGBE_RX_HDR_SIZE) len = IXGBE_RX_HDR_SIZE; upper_len = le16_to_cpu(rx_desc->wb.upper.length); - } else + } else { len = le16_to_cpu(rx_desc->wb.upper.length); + } cleaned = true; skb = rx_buffer_info->skb; @@ -586,18 +607,25 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, if (len && !skb_shinfo(skb)->nr_frags) { pci_unmap_single(pdev, rx_buffer_info->dma, - adapter->rx_buf_len + NET_IP_ALIGN, - PCI_DMA_FROMDEVICE); + rx_ring->rx_buf_len + NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); skb_put(skb, len); } if (upper_len) { pci_unmap_page(pdev, rx_buffer_info->page_dma, - PAGE_SIZE, PCI_DMA_FROMDEVICE); + PAGE_SIZE / 2, PCI_DMA_FROMDEVICE); rx_buffer_info->page_dma = 0; skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, - rx_buffer_info->page, 0, upper_len); - rx_buffer_info->page = NULL; + rx_buffer_info->page, + rx_buffer_info->page_offset, + upper_len); + + if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) || + (page_count(rx_buffer_info->page) != 1)) + rx_buffer_info->page = NULL; + else + get_page(rx_buffer_info->page); skb->len += upper_len; skb->data_len += upper_len; @@ -620,6 +648,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, rx_buffer_info->skb = next_buffer->skb; rx_buffer_info->dma = next_buffer->dma; next_buffer->skb = skb; + next_buffer->dma = 0; adapter->non_eop_descs++; goto next_desc; } @@ -635,9 +664,9 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, total_rx_bytes += skb->len; total_rx_packets++; - skb->protocol = eth_type_trans(skb, netdev); + skb->protocol = eth_type_trans(skb, adapter->netdev); ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc); - netdev->last_rx = jiffies; + adapter->netdev->last_rx = jiffies; next_desc: rx_desc->wb.upper.status_error = 0; @@ -666,9 +695,6 @@ next_desc: if (cleaned_count) ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); - adapter->net_stats.rx_bytes += total_rx_bytes; - adapter->net_stats.rx_packets += total_rx_packets; - rx_ring->total_packets += total_rx_packets; rx_ring->total_bytes += total_rx_bytes; adapter->net_stats.rx_bytes += total_rx_bytes; @@ -700,43 +726,43 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) q_vector = &adapter->q_vector[v_idx]; /* XXX for_each_bit(...) */ r_idx = find_first_bit(q_vector->rxr_idx, - adapter->num_rx_queues); + adapter->num_rx_queues); for (i = 0; i < q_vector->rxr_count; i++) { j = adapter->rx_ring[r_idx].reg_idx; ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(j), v_idx); r_idx = find_next_bit(q_vector->rxr_idx, - adapter->num_rx_queues, - r_idx + 1); + adapter->num_rx_queues, + r_idx + 1); } r_idx = find_first_bit(q_vector->txr_idx, - adapter->num_tx_queues); + adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { j = adapter->tx_ring[r_idx].reg_idx; ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(j), v_idx); r_idx = find_next_bit(q_vector->txr_idx, - adapter->num_tx_queues, - r_idx + 1); + adapter->num_tx_queues, + r_idx + 1); } - /* if this is a tx only vector use half the irq (tx) rate */ + /* if this is a tx only vector halve the interrupt rate */ if (q_vector->txr_count && !q_vector->rxr_count) - q_vector->eitr = adapter->tx_eitr; + q_vector->eitr = (adapter->eitr_param >> 1); else - /* rx only or mixed */ - q_vector->eitr = adapter->rx_eitr; + /* rx only */ + q_vector->eitr = adapter->eitr_param; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), - EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); + EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); } ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX, v_idx); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), 1950); - /* set up to autoclear timer, lsc, and the vectors */ + /* set up to autoclear timer, and the vectors */ mask = IXGBE_EIMS_ENABLE_MASK; - mask &= ~IXGBE_EIMS_OTHER; + mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask); } @@ -766,8 +792,8 @@ enum latency_range { * parameter (see ixgbe_param.c) **/ static u8 ixgbe_update_itr(struct ixgbe_adapter *adapter, - u32 eitr, u8 itr_setting, - int packets, int bytes) + u32 eitr, u8 itr_setting, + int packets, int bytes) { unsigned int retval = itr_setting; u32 timepassed_us; @@ -814,40 +840,40 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) u32 new_itr; u8 current_itr, ret_itr; int i, r_idx, v_idx = ((void *)q_vector - (void *)(adapter->q_vector)) / - sizeof(struct ixgbe_q_vector); + sizeof(struct ixgbe_q_vector); struct ixgbe_ring *rx_ring, *tx_ring; r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { tx_ring = &(adapter->tx_ring[r_idx]); ret_itr = ixgbe_update_itr(adapter, q_vector->eitr, - q_vector->tx_eitr, - tx_ring->total_packets, - tx_ring->total_bytes); + q_vector->tx_itr, + tx_ring->total_packets, + tx_ring->total_bytes); /* if the result for this queue would decrease interrupt * rate for this vector then use that result */ - q_vector->tx_eitr = ((q_vector->tx_eitr > ret_itr) ? - q_vector->tx_eitr - 1 : ret_itr); + q_vector->tx_itr = ((q_vector->tx_itr > ret_itr) ? + q_vector->tx_itr - 1 : ret_itr); r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, - r_idx + 1); + r_idx + 1); } r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); for (i = 0; i < q_vector->rxr_count; i++) { rx_ring = &(adapter->rx_ring[r_idx]); ret_itr = ixgbe_update_itr(adapter, q_vector->eitr, - q_vector->rx_eitr, - rx_ring->total_packets, - rx_ring->total_bytes); + q_vector->rx_itr, + rx_ring->total_packets, + rx_ring->total_bytes); /* if the result for this queue would decrease interrupt * rate for this vector then use that result */ - q_vector->rx_eitr = ((q_vector->rx_eitr > ret_itr) ? - q_vector->rx_eitr - 1 : ret_itr); + q_vector->rx_itr = ((q_vector->rx_itr > ret_itr) ? + q_vector->rx_itr - 1 : ret_itr); r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, - r_idx + 1); + r_idx + 1); } - current_itr = max(q_vector->rx_eitr, q_vector->tx_eitr); + current_itr = max(q_vector->rx_itr, q_vector->tx_itr); switch (current_itr) { /* counts and packets in update_itr are dependent on these numbers */ @@ -871,13 +897,27 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr); /* must write high and low 16 bits to reset counter */ DPRINTK(TX_ERR, DEBUG, "writing eitr(%d): %08X\n", v_idx, - itr_reg); + itr_reg); IXGBE_WRITE_REG(hw, IXGBE_EITR(v_idx), itr_reg | (itr_reg)<<16); } return; } + +static void ixgbe_check_lsc(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + + adapter->lsc_int++; + adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; + adapter->link_check_timeout = jiffies; + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); + schedule_work(&adapter->watchdog_task); + } +} + static irqreturn_t ixgbe_msix_lsc(int irq, void *data) { struct net_device *netdev = data; @@ -885,11 +925,8 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) struct ixgbe_hw *hw = &adapter->hw; u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); - if (eicr & IXGBE_EICR_LSC) { - adapter->lsc_int++; - if (!test_bit(__IXGBE_DOWN, &adapter->state)) - mod_timer(&adapter->watchdog_timer, jiffies); - } + if (eicr & IXGBE_EICR_LSC) + ixgbe_check_lsc(adapter); if (!test_bit(__IXGBE_DOWN, &adapter->state)) IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); @@ -901,7 +938,7 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) { struct ixgbe_q_vector *q_vector = data; struct ixgbe_adapter *adapter = q_vector->adapter; - struct ixgbe_ring *txr; + struct ixgbe_ring *tx_ring; int i, r_idx; if (!q_vector->txr_count) @@ -909,16 +946,16 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { - txr = &(adapter->tx_ring[r_idx]); -#ifdef CONFIG_DCA + tx_ring = &(adapter->tx_ring[r_idx]); +#ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) - ixgbe_update_tx_dca(adapter, txr); + ixgbe_update_tx_dca(adapter, tx_ring); #endif - txr->total_bytes = 0; - txr->total_packets = 0; - ixgbe_clean_tx_irq(adapter, txr); + tx_ring->total_bytes = 0; + tx_ring->total_packets = 0; + ixgbe_clean_tx_irq(adapter, tx_ring); r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, - r_idx + 1); + r_idx + 1); } return IRQ_HANDLED; @@ -933,18 +970,26 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) { struct ixgbe_q_vector *q_vector = data; struct ixgbe_adapter *adapter = q_vector->adapter; - struct ixgbe_ring *rxr; + struct ixgbe_ring *rx_ring; int r_idx; + int i; r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + for (i = 0; i < q_vector->rxr_count; i++) { + rx_ring = &(adapter->rx_ring[r_idx]); + rx_ring->total_bytes = 0; + rx_ring->total_packets = 0; + r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, + r_idx + 1); + } + if (!q_vector->rxr_count) return IRQ_HANDLED; - rxr = &(adapter->rx_ring[r_idx]); + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + rx_ring = &(adapter->rx_ring[r_idx]); /* disable interrupts on this vector only */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->v_idx); - rxr->total_bytes = 0; - rxr->total_packets = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx); netif_rx_schedule(adapter->netdev, &q_vector->napi); return IRQ_HANDLED; @@ -963,39 +1008,90 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data) * @napi: napi struct with our devices info in it * @budget: amount of work driver is allowed to do this pass, in packets * + * This function is optimized for cleaning one queue only on a single + * q_vector!!! **/ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) { struct ixgbe_q_vector *q_vector = - container_of(napi, struct ixgbe_q_vector, napi); + container_of(napi, struct ixgbe_q_vector, napi); struct ixgbe_adapter *adapter = q_vector->adapter; - struct ixgbe_ring *rxr; + struct ixgbe_ring *rx_ring = NULL; int work_done = 0; long r_idx; r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); - rxr = &(adapter->rx_ring[r_idx]); -#ifdef CONFIG_DCA + rx_ring = &(adapter->rx_ring[r_idx]); +#ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) - ixgbe_update_rx_dca(adapter, rxr); + ixgbe_update_rx_dca(adapter, rx_ring); #endif - ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget); + ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget); /* If all Rx work done, exit the polling mode */ if (work_done < budget) { netif_rx_complete(adapter->netdev, napi); - if (adapter->rx_eitr < IXGBE_MIN_ITR_USECS) + if (adapter->itr_setting & 3) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rxr->v_idx); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rx_ring->v_idx); } return work_done; } +/** + * ixgbe_clean_rxonly_many - msix (aka one shot) rx clean routine + * @napi: napi struct with our devices info in it + * @budget: amount of work driver is allowed to do this pass, in packets + * + * This function will clean more than one rx queue associated with a + * q_vector. + **/ +static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) +{ + struct ixgbe_q_vector *q_vector = + container_of(napi, struct ixgbe_q_vector, napi); + struct ixgbe_adapter *adapter = q_vector->adapter; + struct ixgbe_ring *rx_ring = NULL; + int work_done = 0, i; + long r_idx; + u16 enable_mask = 0; + + /* attempt to distribute budget to each queue fairly, but don't allow + * the budget to go below 1 because we'll exit polling */ + budget /= (q_vector->rxr_count ?: 1); + budget = max(budget, 1); + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + for (i = 0; i < q_vector->rxr_count; i++) { + rx_ring = &(adapter->rx_ring[r_idx]); +#ifdef CONFIG_IXGBE_DCA + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) + ixgbe_update_rx_dca(adapter, rx_ring); +#endif + ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget); + enable_mask |= rx_ring->v_idx; + r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, + r_idx + 1); + } + + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + rx_ring = &(adapter->rx_ring[r_idx]); + /* If all Rx work done, exit the polling mode */ + if (work_done < budget) { + netif_rx_complete(adapter->netdev, napi); + if (adapter->itr_setting & 3) + ixgbe_set_itr_msix(q_vector); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, enable_mask); + return 0; + } + + return work_done; +} static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, - int r_idx) + int r_idx) { a->q_vector[v_idx].adapter = a; set_bit(r_idx, a->q_vector[v_idx].rxr_idx); @@ -1004,7 +1100,7 @@ static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, } static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, - int r_idx) + int r_idx) { a->q_vector[v_idx].adapter = a; set_bit(r_idx, a->q_vector[v_idx].txr_idx); @@ -1024,7 +1120,7 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, * mapping configurations in here. **/ static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter, - int vectors) + int vectors) { int v_start = 0; int rxr_idx = 0, txr_idx = 0; @@ -1101,28 +1197,28 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) goto out; #define SET_HANDLER(_v) ((!(_v)->rxr_count) ? &ixgbe_msix_clean_tx : \ - (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \ - &ixgbe_msix_clean_many) + (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \ + &ixgbe_msix_clean_many) for (vector = 0; vector < q_vectors; vector++) { handler = SET_HANDLER(&adapter->q_vector[vector]); sprintf(adapter->name[vector], "%s:v%d-%s", - netdev->name, vector, - (handler == &ixgbe_msix_clean_rx) ? "Rx" : - ((handler == &ixgbe_msix_clean_tx) ? "Tx" : "TxRx")); + netdev->name, vector, + (handler == &ixgbe_msix_clean_rx) ? "Rx" : + ((handler == &ixgbe_msix_clean_tx) ? "Tx" : "TxRx")); err = request_irq(adapter->msix_entries[vector].vector, - handler, 0, adapter->name[vector], - &(adapter->q_vector[vector])); + handler, 0, adapter->name[vector], + &(adapter->q_vector[vector])); if (err) { DPRINTK(PROBE, ERR, - "request_irq failed for MSIX interrupt " - "Error: %d\n", err); + "request_irq failed for MSIX interrupt " + "Error: %d\n", err); goto free_queue_irqs; } } sprintf(adapter->name[vector], "%s:lsc", netdev->name); err = request_irq(adapter->msix_entries[vector].vector, - &ixgbe_msix_lsc, 0, adapter->name[vector], netdev); + &ixgbe_msix_lsc, 0, adapter->name[vector], netdev); if (err) { DPRINTK(PROBE, ERR, "request_irq for msix_lsc failed: %d\n", err); @@ -1134,7 +1230,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) free_queue_irqs: for (i = vector - 1; i >= 0; i--) free_irq(adapter->msix_entries[--vector].vector, - &(adapter->q_vector[i])); + &(adapter->q_vector[i])); adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; pci_disable_msix(adapter->pdev); kfree(adapter->msix_entries); @@ -1152,16 +1248,16 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter) struct ixgbe_ring *rx_ring = &adapter->rx_ring[0]; struct ixgbe_ring *tx_ring = &adapter->tx_ring[0]; - q_vector->tx_eitr = ixgbe_update_itr(adapter, new_itr, - q_vector->tx_eitr, - tx_ring->total_packets, - tx_ring->total_bytes); - q_vector->rx_eitr = ixgbe_update_itr(adapter, new_itr, - q_vector->rx_eitr, - rx_ring->total_packets, - rx_ring->total_bytes); + q_vector->tx_itr = ixgbe_update_itr(adapter, new_itr, + q_vector->tx_itr, + tx_ring->total_packets, + tx_ring->total_bytes); + q_vector->rx_itr = ixgbe_update_itr(adapter, new_itr, + q_vector->rx_itr, + rx_ring->total_packets, + rx_ring->total_bytes); - current_itr = max(q_vector->rx_eitr, q_vector->tx_eitr); + current_itr = max(q_vector->rx_itr, q_vector->tx_itr); switch (current_itr) { /* counts and packets in update_itr are dependent on these numbers */ @@ -1206,19 +1302,19 @@ static irqreturn_t ixgbe_intr(int irq, void *data) struct ixgbe_hw *hw = &adapter->hw; u32 eicr; - /* for NAPI, using EIAM to auto-mask tx/rx interrupt bits on read * therefore no explict interrupt disable is necessary */ eicr = IXGBE_READ_REG(hw, IXGBE_EICR); - if (!eicr) + if (!eicr) { + /* shared interrupt alert! + * make sure interrupts are enabled because the read will + * have disabled interrupts due to EIAM */ + ixgbe_irq_enable(adapter); return IRQ_NONE; /* Not our interrupt */ - - if (eicr & IXGBE_EICR_LSC) { - adapter->lsc_int++; - if (!test_bit(__IXGBE_DOWN, &adapter->state)) - mod_timer(&adapter->watchdog_timer, jiffies); } + if (eicr & IXGBE_EICR_LSC) + ixgbe_check_lsc(adapter); if (netif_rx_schedule_prep(netdev, &adapter->q_vector[0].napi)) { adapter->tx_ring[0].total_packets = 0; @@ -1261,10 +1357,10 @@ static int ixgbe_request_irq(struct ixgbe_adapter *adapter) err = ixgbe_request_msix_irqs(adapter); } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { err = request_irq(adapter->pdev->irq, &ixgbe_intr, 0, - netdev->name, netdev); + netdev->name, netdev); } else { err = request_irq(adapter->pdev->irq, &ixgbe_intr, IRQF_SHARED, - netdev->name, netdev); + netdev->name, netdev); } if (err) @@ -1288,7 +1384,7 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter) i--; for (; i >= 0; i--) { free_irq(adapter->msix_entries[i].vector, - &(adapter->q_vector[i])); + &(adapter->q_vector[i])); } ixgbe_reset_q_vectors(adapter); @@ -1335,7 +1431,7 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; IXGBE_WRITE_REG(hw, IXGBE_EITR(0), - EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr)); + EITR_INTS_PER_SEC_TO_REG(adapter->eitr_param)); ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0); ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(0), 0); @@ -1347,26 +1443,31 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter) } /** - * ixgbe_configure_tx - Configure 8254x Transmit Unit after Reset + * ixgbe_configure_tx - Configure 8259x Transmit Unit after Reset * @adapter: board private structure * * Configure the Tx unit of the MAC after a reset. **/ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) { - u64 tdba; + u64 tdba, tdwba; struct ixgbe_hw *hw = &adapter->hw; u32 i, j, tdlen, txctrl; /* Setup the HW Tx Head and Tail descriptor pointers */ for (i = 0; i < adapter->num_tx_queues; i++) { - j = adapter->tx_ring[i].reg_idx; - tdba = adapter->tx_ring[i].dma; - tdlen = adapter->tx_ring[i].count * - sizeof(union ixgbe_adv_tx_desc); + struct ixgbe_ring *ring = &adapter->tx_ring[i]; + j = ring->reg_idx; + tdba = ring->dma; + tdlen = ring->count * sizeof(union ixgbe_adv_tx_desc); IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), - (tdba & DMA_32BIT_MASK)); + (tdba & DMA_32BIT_MASK)); IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); + tdwba = ring->dma + + (ring->count * sizeof(union ixgbe_adv_tx_desc)); + tdwba |= IXGBE_TDWBAL_HEAD_WB_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(j), tdwba & DMA_32BIT_MASK); + IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(j), (tdwba >> 32)); IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen); IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); @@ -1375,20 +1476,66 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) /* Disable Tx Head Writeback RO bit, since this hoses * bookkeeping if things aren't delivered in order. */ - txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; - IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl); + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); } } -#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ - (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) +#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 + +static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) +{ + struct ixgbe_ring *rx_ring; + u32 srrctl; + int queue0; + unsigned long mask; + + /* program one srrctl register per VMDq index */ + if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED) { + long shift, len; + mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask; + len = sizeof(adapter->ring_feature[RING_F_VMDQ].mask) * 8; + shift = find_first_bit(&mask, len); + queue0 = index & mask; + index = (index & mask) >> shift; + /* program one srrctl per RSS queue since RDRXCTL.MVMEN is enabled */ + } else { + mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask; + queue0 = index & mask; + index = index & mask; + } + + rx_ring = &adapter->rx_ring[queue0]; + + srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(index)); + + srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; + srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; + + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + srrctl |= IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; + srrctl |= ((IXGBE_RX_HDR_SIZE << + IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & + IXGBE_SRRCTL_BSIZEHDR_MASK); + } else { + srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; + + if (rx_ring->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE) + srrctl |= IXGBE_RXBUFFER_2048 >> + IXGBE_SRRCTL_BSIZEPKT_SHIFT; + else + srrctl |= rx_ring->rx_buf_len >> + IXGBE_SRRCTL_BSIZEPKT_SHIFT; + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl); +} -#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /** * ixgbe_get_skb_hdr - helper function for LRO header processing * @skb: pointer to sk_buff to be added to LRO packet - * @iphdr: pointer to tcp header structure + * @iphdr: pointer to ip header structure * @tcph: pointer to tcp header structure * @hdr_flags: pointer to header flags * @priv: private data @@ -1399,8 +1546,8 @@ static int ixgbe_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph, union ixgbe_adv_rx_desc *rx_desc = priv; /* Verify that this is a valid IPv4 TCP packet */ - if (!(rx_desc->wb.lower.lo_dword.pkt_info & - (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP))) + if (!((ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_IPV4) && + (ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_TCP))) return -1; /* Set network headers */ @@ -1412,8 +1559,11 @@ static int ixgbe_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph, return 0; } +#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) + /** - * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset + * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset * @adapter: board private structure * * Configure the Rx unit of the MAC after a reset. @@ -1426,25 +1576,26 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; int i, j; u32 rdlen, rxctrl, rxcsum; - u32 random[10]; + static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D, + 0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE, + 0x6A3E67EA, 0x14364D17, 0x3BED200D}; u32 fctrl, hlreg0; u32 pages; - u32 reta = 0, mrqc, srrctl; + u32 reta = 0, mrqc; + u32 rdrxctl; + int rx_buf_len; /* Decide whether to use packet split mode or not */ - if (netdev->mtu > ETH_DATA_LEN) - adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; - else - adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; + adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; /* Set the RX buffer length according to the mode */ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { - adapter->rx_buf_len = IXGBE_RX_HDR_SIZE; + rx_buf_len = IXGBE_RX_HDR_SIZE; } else { if (netdev->mtu <= ETH_DATA_LEN) - adapter->rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; + rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; else - adapter->rx_buf_len = ALIGN(max_frame, 1024); + rx_buf_len = ALIGN(max_frame, 1024); } fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); @@ -1461,28 +1612,6 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) pages = PAGE_USE_COUNT(adapter->netdev->mtu); - srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0)); - srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; - srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; - - if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { - srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; - srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; - srrctl |= ((IXGBE_RX_HDR_SIZE << - IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & - IXGBE_SRRCTL_BSIZEHDR_MASK); - } else { - srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; - - if (adapter->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE) - srrctl |= - IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; - else - srrctl |= - adapter->rx_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; - } - IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(0), srrctl); - rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); /* disable receives while setting up the descriptors */ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); @@ -1492,25 +1621,43 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) * the Base and Length of the Rx Descriptor Ring */ for (i = 0; i < adapter->num_rx_queues; i++) { rdba = adapter->rx_ring[i].dma; - IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & DMA_32BIT_MASK)); - IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); - IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), rdlen); - IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); - IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); - adapter->rx_ring[i].head = IXGBE_RDH(i); - adapter->rx_ring[i].tail = IXGBE_RDT(i); - } - - /* Intitial LRO Settings */ - adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE; - adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS; - adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr; - adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID; - if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) - adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI; - adapter->rx_ring[i].lro_mgr.dev = adapter->netdev; - adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; - adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + j = adapter->rx_ring[i].reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), (rdba & DMA_32BIT_MASK)); + IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), rdlen); + IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0); + IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0); + adapter->rx_ring[i].head = IXGBE_RDH(j); + adapter->rx_ring[i].tail = IXGBE_RDT(j); + adapter->rx_ring[i].rx_buf_len = rx_buf_len; + /* Intitial LRO Settings */ + adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE; + adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS; + adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr; + adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID; + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) + adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI; + adapter->rx_ring[i].lro_mgr.dev = adapter->netdev; + adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + + ixgbe_configure_srrctl(adapter, j); + } + + /* + * For VMDq support of different descriptor types or + * buffer sizes through the use of multiple SRRCTL + * registers, RDRXCTL.MVMEN must be set to 1 + * + * also, the manual doesn't mention it clearly but DCA hints + * will only use queue 0's tags unless this bit is set. Side + * effects of setting this bit are only that SRRCTL must be + * fully programmed [0..15] + */ + rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + rdrxctl |= IXGBE_RDRXCTL_MVMEN; + IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { /* Fill out redirection table */ @@ -1525,22 +1672,20 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) } /* Fill out hash function seeds */ - /* XXX use a random constant here to glue certain flows */ - get_random_bytes(&random[0], 40); for (i = 0; i < 10; i++) - IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random[i]); + IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]); mrqc = IXGBE_MRQC_RSSEN /* Perform hash on these packet types */ - | IXGBE_MRQC_RSS_FIELD_IPV4 - | IXGBE_MRQC_RSS_FIELD_IPV4_TCP - | IXGBE_MRQC_RSS_FIELD_IPV4_UDP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX - | IXGBE_MRQC_RSS_FIELD_IPV6 - | IXGBE_MRQC_RSS_FIELD_IPV6_TCP - | IXGBE_MRQC_RSS_FIELD_IPV6_UDP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; + | IXGBE_MRQC_RSS_FIELD_IPV4 + | IXGBE_MRQC_RSS_FIELD_IPV4_TCP + | IXGBE_MRQC_RSS_FIELD_IPV4_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX + | IXGBE_MRQC_RSS_FIELD_IPV6 + | IXGBE_MRQC_RSS_FIELD_IPV6_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); } @@ -1562,7 +1707,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) } static void ixgbe_vlan_rx_register(struct net_device *netdev, - struct vlan_group *grp) + struct vlan_group *grp) { struct ixgbe_adapter *adapter = netdev_priv(netdev); u32 ctrl; @@ -1586,14 +1731,16 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev, static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; /* add VID to filter table */ - ixgbe_set_vfta(&adapter->hw, vid, 0, true); + hw->mac.ops.set_vfta(&adapter->hw, vid, 0, true); } static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; if (!test_bit(__IXGBE_DOWN, &adapter->state)) ixgbe_irq_disable(adapter); @@ -1604,7 +1751,7 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) ixgbe_irq_enable(adapter); /* remove VID from filter table */ - ixgbe_set_vfta(&adapter->hw, vid, 0, false); + hw->mac.ops.set_vfta(&adapter->hw, vid, 0, false); } static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter) @@ -1621,23 +1768,37 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter) } } +static u8 *ixgbe_addr_list_itr(struct ixgbe_hw *hw, u8 **mc_addr_ptr, u32 *vmdq) +{ + struct dev_mc_list *mc_ptr; + u8 *addr = *mc_addr_ptr; + *vmdq = 0; + + mc_ptr = container_of(addr, struct dev_mc_list, dmi_addr[0]); + if (mc_ptr->next) + *mc_addr_ptr = mc_ptr->next->dmi_addr; + else + *mc_addr_ptr = NULL; + + return addr; +} + /** - * ixgbe_set_multi - Multicast and Promiscuous mode set + * ixgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set * @netdev: network interface device structure * - * The set_multi entry point is called whenever the multicast address - * list or the network interface flags are updated. This routine is - * responsible for configuring the hardware for proper multicast, - * promiscuous mode, and all-multi behavior. + * The set_rx_method entry point is called whenever the unicast/multicast + * address list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper unicast, multicast and + * promiscuous mode. **/ -static void ixgbe_set_multi(struct net_device *netdev) +static void ixgbe_set_rx_mode(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - struct dev_mc_list *mc_ptr; - u8 *mta_list; u32 fctrl, vlnctrl; - int i; + u8 *addr_list = NULL; + int addr_count = 0; /* Check for Promiscuous and All Multicast modes */ @@ -1645,6 +1806,7 @@ static void ixgbe_set_multi(struct net_device *netdev) vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); if (netdev->flags & IFF_PROMISC) { + hw->addr_ctrl.user_set_promisc = 1; fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); vlnctrl &= ~IXGBE_VLNCTRL_VFE; } else { @@ -1655,33 +1817,25 @@ static void ixgbe_set_multi(struct net_device *netdev) fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); } vlnctrl |= IXGBE_VLNCTRL_VFE; + hw->addr_ctrl.user_set_promisc = 0; } IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); - if (netdev->mc_count) { - mta_list = kcalloc(netdev->mc_count, ETH_ALEN, GFP_ATOMIC); - if (!mta_list) - return; - - /* Shared function expects packed array of only addresses. */ - mc_ptr = netdev->mc_list; - - for (i = 0; i < netdev->mc_count; i++) { - if (!mc_ptr) - break; - memcpy(mta_list + (i * ETH_ALEN), mc_ptr->dmi_addr, - ETH_ALEN); - mc_ptr = mc_ptr->next; - } - - ixgbe_update_mc_addr_list(hw, mta_list, i, 0); - kfree(mta_list); - } else { - ixgbe_update_mc_addr_list(hw, NULL, 0, 0); - } - + /* reprogram secondary unicast list */ + addr_count = netdev->uc_count; + if (addr_count) + addr_list = netdev->uc_list->dmi_addr; + hw->mac.ops.update_uc_addr_list(hw, addr_list, addr_count, + ixgbe_addr_list_itr); + + /* reprogram multicast list */ + addr_count = netdev->mc_count; + if (addr_count) + addr_list = netdev->mc_list->dmi_addr; + hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count, + ixgbe_addr_list_itr); } static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter) @@ -1695,10 +1849,16 @@ static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter) q_vectors = 1; for (q_idx = 0; q_idx < q_vectors; q_idx++) { + struct napi_struct *napi; q_vector = &adapter->q_vector[q_idx]; if (!q_vector->rxr_count) continue; - napi_enable(&q_vector->napi); + napi = &q_vector->napi; + if ((adapter->flags & IXGBE_FLAG_MSIX_ENABLED) && + (q_vector->rxr_count > 1)) + napi->poll = &ixgbe_clean_rxonly_many; + + napi_enable(napi); } } @@ -1725,7 +1885,7 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) struct net_device *netdev = adapter->netdev; int i; - ixgbe_set_multi(netdev); + ixgbe_set_rx_mode(netdev); ixgbe_restore_vlan(adapter); @@ -1733,7 +1893,7 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) ixgbe_configure_rx(adapter); for (i = 0; i < adapter->num_rx_queues; i++) ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i], - (adapter->rx_ring[i].count - 1)); + (adapter->rx_ring[i].count - 1)); } static int ixgbe_up_complete(struct ixgbe_adapter *adapter) @@ -1751,7 +1911,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) (adapter->flags & IXGBE_FLAG_MSI_ENABLED)) { if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME | - IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD); + IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD); } else { /* MSI only */ gpie = 0; @@ -1778,6 +1938,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) for (i = 0; i < adapter->num_tx_queues; i++) { j = adapter->tx_ring[i].reg_idx; txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); + /* enable WTHRESH=8 descriptors, to encourage burst writeback */ + txdctl |= (8 << 16); txdctl |= IXGBE_TXDCTL_ENABLE; IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl); } @@ -1812,6 +1974,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) /* bring the link up in the watchdog, this could race with our first * link up interrupt but shouldn't be a problem */ + adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; + adapter->link_check_timeout = jiffies; mod_timer(&adapter->watchdog_timer, jiffies); return 0; } @@ -1836,50 +2000,14 @@ int ixgbe_up(struct ixgbe_adapter *adapter) void ixgbe_reset(struct ixgbe_adapter *adapter) { - if (ixgbe_init_hw(&adapter->hw)) - DPRINTK(PROBE, ERR, "Hardware Error\n"); + struct ixgbe_hw *hw = &adapter->hw; + if (hw->mac.ops.init_hw(hw)) + dev_err(&adapter->pdev->dev, "Hardware Error\n"); /* reprogram the RAR[0] in case user changed it. */ - ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); - -} - -#ifdef CONFIG_PM -static int ixgbe_resume(struct pci_dev *pdev) -{ - struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgbe_adapter *adapter = netdev_priv(netdev); - u32 err; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "ixgbe: Cannot enable PCI device from " \ - "suspend\n"); - return err; - } - pci_set_master(pdev); + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); - - if (netif_running(netdev)) { - err = ixgbe_request_irq(adapter); - if (err) - return err; - } - - ixgbe_reset(adapter); - - if (netif_running(netdev)) - ixgbe_up(adapter); - - netif_device_attach(netdev); - - return 0; } -#endif /** * ixgbe_clean_rx_ring - Free Rx Buffers per Queue @@ -1887,7 +2015,7 @@ static int ixgbe_resume(struct pci_dev *pdev) * @rx_ring: ring to free buffers from **/ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, - struct ixgbe_ring *rx_ring) + struct ixgbe_ring *rx_ring) { struct pci_dev *pdev = adapter->pdev; unsigned long size; @@ -1901,8 +2029,8 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, rx_buffer_info = &rx_ring->rx_buffer_info[i]; if (rx_buffer_info->dma) { pci_unmap_single(pdev, rx_buffer_info->dma, - adapter->rx_buf_len, - PCI_DMA_FROMDEVICE); + rx_ring->rx_buf_len, + PCI_DMA_FROMDEVICE); rx_buffer_info->dma = 0; } if (rx_buffer_info->skb) { @@ -1911,12 +2039,12 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, } if (!rx_buffer_info->page) continue; - pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE, - PCI_DMA_FROMDEVICE); + pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE / 2, + PCI_DMA_FROMDEVICE); rx_buffer_info->page_dma = 0; - put_page(rx_buffer_info->page); rx_buffer_info->page = NULL; + rx_buffer_info->page_offset = 0; } size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count; @@ -1938,7 +2066,7 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, * @tx_ring: ring to be cleaned **/ static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter, - struct ixgbe_ring *tx_ring) + struct ixgbe_ring *tx_ring) { struct ixgbe_tx_buffer *tx_buffer_info; unsigned long size; @@ -1991,75 +2119,64 @@ static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter) void ixgbe_down(struct ixgbe_adapter *adapter) { struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; u32 rxctrl; + u32 txdctl; + int i, j; /* signal that we are down to the interrupt handler */ set_bit(__IXGBE_DOWN, &adapter->state); /* disable receives */ - rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, - rxctrl & ~IXGBE_RXCTRL_RXEN); + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); netif_tx_disable(netdev); - /* disable transmits in the hardware */ - - /* flush both disables */ - IXGBE_WRITE_FLUSH(&adapter->hw); + IXGBE_WRITE_FLUSH(hw); msleep(10); + netif_tx_stop_all_queues(netdev); + ixgbe_irq_disable(adapter); ixgbe_napi_disable_all(adapter); + del_timer_sync(&adapter->watchdog_timer); + cancel_work_sync(&adapter->watchdog_task); + + /* disable transmits in the hardware now that interrupts are off */ + for (i = 0; i < adapter->num_tx_queues; i++) { + j = adapter->tx_ring[i].reg_idx; + txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), + (txdctl & ~IXGBE_TXDCTL_ENABLE)); + } netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); +#ifdef CONFIG_IXGBE_DCA + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { + adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED; + dca_remove_requester(&adapter->pdev->dev); + } + +#endif if (!pci_channel_offline(adapter->pdev)) ixgbe_reset(adapter); ixgbe_clean_all_tx_rings(adapter); ixgbe_clean_all_rx_rings(adapter); -} - -static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgbe_adapter *adapter = netdev_priv(netdev); -#ifdef CONFIG_PM - int retval = 0; -#endif - - netif_device_detach(netdev); - - if (netif_running(netdev)) { - ixgbe_down(adapter); - ixgbe_free_irq(adapter); +#ifdef CONFIG_IXGBE_DCA + /* since we reset the hardware DCA settings were cleared */ + if (dca_add_requester(&adapter->pdev->dev) == 0) { + adapter->flags |= IXGBE_FLAG_DCA_ENABLED; + /* always use CB2 mode, difference is masked + * in the CB driver */ + IXGBE_WRITE_REG(hw, IXGBE_DCA_CTRL, 2); + ixgbe_setup_dca(adapter); } - -#ifdef CONFIG_PM - retval = pci_save_state(pdev); - if (retval) - return retval; #endif - - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); - - ixgbe_release_hw_control(adapter); - - pci_disable_device(pdev); - - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} - -static void ixgbe_shutdown(struct pci_dev *pdev) -{ - ixgbe_suspend(pdev, PMSG_SUSPEND); } /** @@ -2072,11 +2189,11 @@ static void ixgbe_shutdown(struct pci_dev *pdev) static int ixgbe_poll(struct napi_struct *napi, int budget) { struct ixgbe_q_vector *q_vector = container_of(napi, - struct ixgbe_q_vector, napi); + struct ixgbe_q_vector, napi); struct ixgbe_adapter *adapter = q_vector->adapter; - int tx_cleaned = 0, work_done = 0; + int tx_cleaned, work_done = 0; -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { ixgbe_update_tx_dca(adapter, adapter->tx_ring); ixgbe_update_rx_dca(adapter, adapter->rx_ring); @@ -2092,12 +2209,11 @@ static int ixgbe_poll(struct napi_struct *napi, int budget) /* If budget not fully consumed, exit the polling mode */ if (work_done < budget) { netif_rx_complete(adapter->netdev, napi); - if (adapter->rx_eitr < IXGBE_MIN_ITR_USECS) + if (adapter->itr_setting & 3) ixgbe_set_itr(adapter); if (!test_bit(__IXGBE_DOWN, &adapter->state)) ixgbe_irq_enable(adapter); } - return work_done; } @@ -2123,8 +2239,48 @@ static void ixgbe_reset_task(struct work_struct *work) ixgbe_reinit_locked(adapter); } +static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) +{ + int nrq = 1, ntq = 1; + int feature_mask = 0, rss_i, rss_m; + + /* Number of supported queues */ + switch (adapter->hw.mac.type) { + case ixgbe_mac_82598EB: + rss_i = adapter->ring_feature[RING_F_RSS].indices; + rss_m = 0; + feature_mask |= IXGBE_FLAG_RSS_ENABLED; + + switch (adapter->flags & feature_mask) { + case (IXGBE_FLAG_RSS_ENABLED): + rss_m = 0xF; + nrq = rss_i; + ntq = rss_i; + break; + case 0: + default: + rss_i = 0; + rss_m = 0; + nrq = 1; + ntq = 1; + break; + } + + adapter->ring_feature[RING_F_RSS].indices = rss_i; + adapter->ring_feature[RING_F_RSS].mask = rss_m; + break; + default: + nrq = 1; + ntq = 1; + break; + } + + adapter->num_rx_queues = nrq; + adapter->num_tx_queues = ntq; +} + static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, - int vectors) + int vectors) { int err, vector_threshold; @@ -2143,7 +2299,7 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, */ while (vectors >= vector_threshold) { err = pci_enable_msix(adapter->pdev, adapter->msix_entries, - vectors); + vectors); if (!err) /* Success in acquiring all requested vectors. */ break; else if (err < 0) @@ -2162,54 +2318,13 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, kfree(adapter->msix_entries); adapter->msix_entries = NULL; adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; - adapter->num_tx_queues = 1; - adapter->num_rx_queues = 1; + ixgbe_set_num_queues(adapter); } else { adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; /* Woot! */ adapter->num_msix_vectors = vectors; } } -static void __devinit ixgbe_set_num_queues(struct ixgbe_adapter *adapter) -{ - int nrq, ntq; - int feature_mask = 0, rss_i, rss_m; - - /* Number of supported queues */ - switch (adapter->hw.mac.type) { - case ixgbe_mac_82598EB: - rss_i = adapter->ring_feature[RING_F_RSS].indices; - rss_m = 0; - feature_mask |= IXGBE_FLAG_RSS_ENABLED; - - switch (adapter->flags & feature_mask) { - case (IXGBE_FLAG_RSS_ENABLED): - rss_m = 0xF; - nrq = rss_i; - ntq = rss_i; - break; - case 0: - default: - rss_i = 0; - rss_m = 0; - nrq = 1; - ntq = 1; - break; - } - - adapter->ring_feature[RING_F_RSS].indices = rss_i; - adapter->ring_feature[RING_F_RSS].mask = rss_m; - break; - default: - nrq = 1; - ntq = 1; - break; - } - - adapter->num_rx_queues = nrq; - adapter->num_tx_queues = ntq; -} - /** * ixgbe_cache_ring_register - Descriptor ring to register mapping * @adapter: board private structure to initialize @@ -2219,9 +2334,6 @@ static void __devinit ixgbe_set_num_queues(struct ixgbe_adapter *adapter) **/ static void __devinit ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) { - /* TODO: Remove all uses of the indices in the cases where multiple - * features are OR'd together, if the feature set makes sense. - */ int feature_mask = 0, rss_i; int i, txr_idx, rxr_idx; @@ -2262,21 +2374,22 @@ static int __devinit ixgbe_alloc_queues(struct ixgbe_adapter *adapter) int i; adapter->tx_ring = kcalloc(adapter->num_tx_queues, - sizeof(struct ixgbe_ring), GFP_KERNEL); + sizeof(struct ixgbe_ring), GFP_KERNEL); if (!adapter->tx_ring) goto err_tx_ring_allocation; adapter->rx_ring = kcalloc(adapter->num_rx_queues, - sizeof(struct ixgbe_ring), GFP_KERNEL); + sizeof(struct ixgbe_ring), GFP_KERNEL); if (!adapter->rx_ring) goto err_rx_ring_allocation; for (i = 0; i < adapter->num_tx_queues; i++) { - adapter->tx_ring[i].count = IXGBE_DEFAULT_TXD; + adapter->tx_ring[i].count = adapter->tx_ring_count; adapter->tx_ring[i].queue_index = i; } + for (i = 0; i < adapter->num_rx_queues; i++) { - adapter->rx_ring[i].count = IXGBE_DEFAULT_RXD; + adapter->rx_ring[i].count = adapter->rx_ring_count; adapter->rx_ring[i].queue_index = i; } @@ -2298,25 +2411,19 @@ err_tx_ring_allocation: * capabilities of the hardware and the kernel. **/ static int __devinit ixgbe_set_interrupt_capability(struct ixgbe_adapter - *adapter) + *adapter) { int err = 0; int vector, v_budget; /* - * Set the default interrupt throttle rate. - */ - adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS); - adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS); - - /* * It's easy to be greedy for MSI-X vectors, but it really * doesn't do us much good if we have a lot more vectors * than CPU's. So let's be conservative and only ask for * (roughly) twice the number of vectors as there are CPU's. */ v_budget = min(adapter->num_rx_queues + adapter->num_tx_queues, - (int)(num_online_cpus() * 2)) + NON_Q_VECTORS; + (int)(num_online_cpus() * 2)) + NON_Q_VECTORS; /* * At the same time, hardware can only support a maximum of @@ -2330,7 +2437,7 @@ static int __devinit ixgbe_set_interrupt_capability(struct ixgbe_adapter /* A failure in MSI-X entry allocation isn't fatal, but it does * mean we disable MSI-X capabilities of the adapter. */ adapter->msix_entries = kcalloc(v_budget, - sizeof(struct msix_entry), GFP_KERNEL); + sizeof(struct msix_entry), GFP_KERNEL); if (!adapter->msix_entries) { adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; ixgbe_set_num_queues(adapter); @@ -2339,7 +2446,7 @@ static int __devinit ixgbe_set_interrupt_capability(struct ixgbe_adapter err = ixgbe_alloc_queues(adapter); if (err) { DPRINTK(PROBE, ERR, "Unable to allocate memory " - "for queues\n"); + "for queues\n"); goto out; } @@ -2360,7 +2467,7 @@ try_msi: adapter->flags |= IXGBE_FLAG_MSI_ENABLED; } else { DPRINTK(HW, DEBUG, "Unable to allocate MSI interrupt, " - "falling back to legacy. Error: %d\n", err); + "falling back to legacy. Error: %d\n", err); /* reset err */ err = 0; } @@ -2416,9 +2523,9 @@ static int __devinit ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) } DPRINTK(DRV, INFO, "Multiqueue %s: Rx Queue count = %u, " - "Tx Queue count = %u\n", - (adapter->num_rx_queues > 1) ? "Enabled" : - "Disabled", adapter->num_rx_queues, adapter->num_tx_queues); + "Tx Queue count = %u\n", + (adapter->num_rx_queues > 1) ? "Enabled" : + "Disabled", adapter->num_rx_queues, adapter->num_tx_queues); set_bit(__IXGBE_DOWN, &adapter->state); @@ -2445,33 +2552,44 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) struct pci_dev *pdev = adapter->pdev; unsigned int rss; + /* PCI config space info */ + + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->revision_id = pdev->revision; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_device_id = pdev->subsystem_device; + /* Set capability flags */ rss = min(IXGBE_MAX_RSS_INDICES, (int)num_online_cpus()); adapter->ring_feature[RING_F_RSS].indices = rss; adapter->flags |= IXGBE_FLAG_RSS_ENABLED; - /* Enable Dynamic interrupt throttling by default */ - adapter->rx_eitr = 1; - adapter->tx_eitr = 1; - /* default flow control settings */ - hw->fc.original_type = ixgbe_fc_full; - hw->fc.type = ixgbe_fc_full; + hw->fc.original_type = ixgbe_fc_none; + hw->fc.type = ixgbe_fc_none; + hw->fc.high_water = IXGBE_DEFAULT_FCRTH; + hw->fc.low_water = IXGBE_DEFAULT_FCRTL; + hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; + hw->fc.send_xon = true; /* select 10G link by default */ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN; - if (hw->mac.ops.reset(hw)) { - dev_err(&pdev->dev, "HW Init failed\n"); - return -EIO; - } - if (hw->mac.ops.setup_link_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true, - false)) { - dev_err(&pdev->dev, "Link Speed setup failed\n"); - return -EIO; - } + + /* enable itr by default in dynamic mode */ + adapter->itr_setting = 1; + adapter->eitr_param = 20000; + + /* set defaults for eitr in MegaBytes */ + adapter->eitr_low = 10; + adapter->eitr_high = 20; + + /* set default ring sizes */ + adapter->tx_ring_count = IXGBE_DEFAULT_TXD; + adapter->rx_ring_count = IXGBE_DEFAULT_RXD; /* initialize eeprom parameters */ - if (ixgbe_init_eeprom(hw)) { + if (ixgbe_init_eeprom_params_generic(hw)) { dev_err(&pdev->dev, "EEPROM initialization failed\n"); return -EIO; } @@ -2487,105 +2605,157 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) /** * ixgbe_setup_tx_resources - allocate Tx resources (Descriptors) * @adapter: board private structure - * @txdr: tx descriptor ring (for a specific queue) to setup + * @tx_ring: tx descriptor ring (for a specific queue) to setup * * Return 0 on success, negative on failure **/ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, - struct ixgbe_ring *txdr) + struct ixgbe_ring *tx_ring) { struct pci_dev *pdev = adapter->pdev; int size; - size = sizeof(struct ixgbe_tx_buffer) * txdr->count; - txdr->tx_buffer_info = vmalloc(size); - if (!txdr->tx_buffer_info) { - DPRINTK(PROBE, ERR, - "Unable to allocate memory for the transmit descriptor ring\n"); - return -ENOMEM; - } - memset(txdr->tx_buffer_info, 0, size); + size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count; + tx_ring->tx_buffer_info = vmalloc(size); + if (!tx_ring->tx_buffer_info) + goto err; + memset(tx_ring->tx_buffer_info, 0, size); /* round up to nearest 4K */ - txdr->size = txdr->count * sizeof(union ixgbe_adv_tx_desc); - txdr->size = ALIGN(txdr->size, 4096); + tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc) + + sizeof(u32); + tx_ring->size = ALIGN(tx_ring->size, 4096); - txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); - if (!txdr->desc) { - vfree(txdr->tx_buffer_info); - DPRINTK(PROBE, ERR, - "Memory allocation failed for the tx desc ring\n"); - return -ENOMEM; - } - - txdr->next_to_use = 0; - txdr->next_to_clean = 0; - txdr->work_limit = txdr->count; + tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, + &tx_ring->dma); + if (!tx_ring->desc) + goto err; + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + tx_ring->work_limit = tx_ring->count; return 0; + +err: + vfree(tx_ring->tx_buffer_info); + tx_ring->tx_buffer_info = NULL; + DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit " + "descriptor ring\n"); + return -ENOMEM; +} + +/** + * ixgbe_setup_all_tx_resources - allocate all queues Tx resources + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ +static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]); + if (!err) + continue; + DPRINTK(PROBE, ERR, "Allocation for Tx Queue %u failed\n", i); + break; + } + + return err; } /** * ixgbe_setup_rx_resources - allocate Rx resources (Descriptors) * @adapter: board private structure - * @rxdr: rx descriptor ring (for a specific queue) to setup + * @rx_ring: rx descriptor ring (for a specific queue) to setup * * Returns 0 on success, negative on failure **/ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, - struct ixgbe_ring *rxdr) + struct ixgbe_ring *rx_ring) { struct pci_dev *pdev = adapter->pdev; int size; size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS; - rxdr->lro_mgr.lro_arr = vmalloc(size); - if (!rxdr->lro_mgr.lro_arr) + rx_ring->lro_mgr.lro_arr = vmalloc(size); + if (!rx_ring->lro_mgr.lro_arr) return -ENOMEM; - memset(rxdr->lro_mgr.lro_arr, 0, size); + memset(rx_ring->lro_mgr.lro_arr, 0, size); - size = sizeof(struct ixgbe_rx_buffer) * rxdr->count; - rxdr->rx_buffer_info = vmalloc(size); - if (!rxdr->rx_buffer_info) { + size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count; + rx_ring->rx_buffer_info = vmalloc(size); + if (!rx_ring->rx_buffer_info) { DPRINTK(PROBE, ERR, - "vmalloc allocation failed for the rx desc ring\n"); + "vmalloc allocation failed for the rx desc ring\n"); goto alloc_failed; } - memset(rxdr->rx_buffer_info, 0, size); + memset(rx_ring->rx_buffer_info, 0, size); /* Round up to nearest 4K */ - rxdr->size = rxdr->count * sizeof(union ixgbe_adv_rx_desc); - rxdr->size = ALIGN(rxdr->size, 4096); + rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc); + rx_ring->size = ALIGN(rx_ring->size, 4096); - rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); + rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, &rx_ring->dma); - if (!rxdr->desc) { + if (!rx_ring->desc) { DPRINTK(PROBE, ERR, - "Memory allocation failed for the rx desc ring\n"); - vfree(rxdr->rx_buffer_info); + "Memory allocation failed for the rx desc ring\n"); + vfree(rx_ring->rx_buffer_info); goto alloc_failed; } - rxdr->next_to_clean = 0; - rxdr->next_to_use = 0; + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; return 0; alloc_failed: - vfree(rxdr->lro_mgr.lro_arr); - rxdr->lro_mgr.lro_arr = NULL; + vfree(rx_ring->lro_mgr.lro_arr); + rx_ring->lro_mgr.lro_arr = NULL; return -ENOMEM; } /** + * ixgbe_setup_all_rx_resources - allocate all queues Rx resources + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ + +static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]); + if (!err) + continue; + DPRINTK(PROBE, ERR, "Allocation for Rx Queue %u failed\n", i); + break; + } + + return err; +} + +/** * ixgbe_free_tx_resources - Free Tx Resources per Queue * @adapter: board private structure * @tx_ring: Tx descriptor ring for a specific queue * * Free all transmit software resources **/ -static void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter, - struct ixgbe_ring *tx_ring) +void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring) { struct pci_dev *pdev = adapter->pdev; @@ -2620,8 +2790,8 @@ static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter) * * Free all receive software resources **/ -static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, - struct ixgbe_ring *rx_ring) +void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring) { struct pci_dev *pdev = adapter->pdev; @@ -2653,59 +2823,6 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter) } /** - * ixgbe_setup_all_tx_resources - allocate all queues Tx resources - * @adapter: board private structure - * - * If this function returns with an error, then it's possible one or - * more of the rings is populated (while the rest are not). It is the - * callers duty to clean those orphaned rings. - * - * Return 0 on success, negative on failure - **/ -static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) -{ - int i, err = 0; - - for (i = 0; i < adapter->num_tx_queues; i++) { - err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]); - if (err) { - DPRINTK(PROBE, ERR, - "Allocation for Tx Queue %u failed\n", i); - break; - } - } - - return err; -} - -/** - * ixgbe_setup_all_rx_resources - allocate all queues Rx resources - * @adapter: board private structure - * - * If this function returns with an error, then it's possible one or - * more of the rings is populated (while the rest are not). It is the - * callers duty to clean those orphaned rings. - * - * Return 0 on success, negative on failure - **/ - -static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter) -{ - int i, err = 0; - - for (i = 0; i < adapter->num_rx_queues; i++) { - err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]); - if (err) { - DPRINTK(PROBE, ERR, - "Allocation for Rx Queue %u failed\n", i); - break; - } - } - - return err; -} - -/** * ixgbe_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure * @new_mtu: new value for maximum frame size @@ -2717,12 +2834,12 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu) struct ixgbe_adapter *adapter = netdev_priv(netdev); int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; - if ((max_frame < (ETH_ZLEN + ETH_FCS_LEN)) || - (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE)) + /* MTU < 68 is an error and causes problems on some kernels */ + if ((new_mtu < 68) || (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE)) return -EINVAL; DPRINTK(PROBE, INFO, "changing MTU from %d to %d\n", - netdev->mtu, new_mtu); + netdev->mtu, new_mtu); /* must set new MTU before calling down or up */ netdev->mtu = new_mtu; @@ -2817,6 +2934,135 @@ static int ixgbe_close(struct net_device *netdev) } /** + * ixgbe_napi_add_all - prep napi structs for use + * @adapter: private struct + * helper function to napi_add each possible q_vector->napi + */ +static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) +{ + int q_idx, q_vectors; + int (*poll)(struct napi_struct *, int); + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + poll = &ixgbe_clean_rxonly; + /* Only enable as many vectors as we have rx queues. */ + q_vectors = adapter->num_rx_queues; + } else { + poll = &ixgbe_poll; + /* only one q_vector for legacy modes */ + q_vectors = 1; + } + + for (q_idx = 0; q_idx < q_vectors; q_idx++) { + struct ixgbe_q_vector *q_vector = &adapter->q_vector[q_idx]; + netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64); + } +} + +static void ixgbe_napi_del_all(struct ixgbe_adapter *adapter) +{ + int q_idx; + int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + + /* legacy and MSI only use one vector */ + if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) + q_vectors = 1; + + for (q_idx = 0; q_idx < q_vectors; q_idx++) { + struct ixgbe_q_vector *q_vector = &adapter->q_vector[q_idx]; + if (!q_vector->rxr_count) + continue; + netif_napi_del(&q_vector->napi); + } +} + +#ifdef CONFIG_PM +static int ixgbe_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "ixgbe: Cannot enable PCI device from " + "suspend\n"); + return err; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + err = ixgbe_init_interrupt_scheme(adapter); + if (err) { + printk(KERN_ERR "ixgbe: Cannot initialize interrupts for " + "device\n"); + return err; + } + + ixgbe_napi_add_all(adapter); + ixgbe_reset(adapter); + + if (netif_running(netdev)) { + err = ixgbe_open(adapter->netdev); + if (err) + return err; + } + + netif_device_attach(netdev); + + return 0; +} + +#endif /* CONFIG_PM */ +static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev_priv(netdev); +#ifdef CONFIG_PM + int retval = 0; +#endif + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_free_irq(adapter); + ixgbe_free_all_tx_resources(adapter); + ixgbe_free_all_rx_resources(adapter); + } + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + +#ifdef CONFIG_PM + retval = pci_save_state(pdev); + if (retval) + return retval; +#endif + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + ixgbe_release_hw_control(adapter); + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static void ixgbe_shutdown(struct pci_dev *pdev) +{ + ixgbe_suspend(pdev, PMSG_SUSPEND); +} + +/** * ixgbe_update_stats - Update the board statistics counters. * @adapter: board private structure **/ @@ -2889,7 +3135,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) /* Rx Errors */ adapter->net_stats.rx_errors = adapter->stats.crcerrs + - adapter->stats.rlec; + adapter->stats.rlec; adapter->net_stats.rx_dropped = 0; adapter->net_stats.rx_length_errors = adapter->stats.rlec; adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; @@ -2903,27 +3149,74 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) static void ixgbe_watchdog(unsigned long data) { struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; - struct net_device *netdev = adapter->netdev; - bool link_up; - u32 link_speed = 0; + struct ixgbe_hw *hw = &adapter->hw; + + /* Do the watchdog outside of interrupt context due to the lovely + * delays that some of the newer hardware requires */ + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + /* Cause software interrupt to ensure rx rings are cleaned */ + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + u32 eics = + (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1; + IXGBE_WRITE_REG(hw, IXGBE_EICS, eics); + } else { + /* For legacy and MSI interrupts don't set any bits that + * are enabled for EIAM, because this operation would + * set *both* EIMS and EICS for any bit in EIAM */ + IXGBE_WRITE_REG(hw, IXGBE_EICS, + (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); + } + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 2 * HZ)); + } - adapter->hw.mac.ops.check_link(&adapter->hw, &(link_speed), &link_up); + schedule_work(&adapter->watchdog_task); +} + +/** + * ixgbe_watchdog_task - worker thread to bring link up + * @work: pointer to work_struct containing our data + **/ +static void ixgbe_watchdog_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + watchdog_task); + struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; + u32 link_speed = adapter->link_speed; + bool link_up = adapter->link_up; + + adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; + + if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { + hw->mac.ops.check_link(hw, &link_speed, &link_up, false); + if (link_up || + time_after(jiffies, (adapter->link_check_timeout + + IXGBE_TRY_LINK_TIMEOUT))) { + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; + } + adapter->link_up = link_up; + adapter->link_speed = link_speed; + } if (link_up) { if (!netif_carrier_ok(netdev)) { - u32 frctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); - u32 rmcs = IXGBE_READ_REG(&adapter->hw, IXGBE_RMCS); + u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); #define FLOW_RX (frctl & IXGBE_FCTRL_RFCE) #define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X) DPRINTK(LINK, INFO, "NIC Link is Up %s, " - "Flow Control: %s\n", - (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? - "10 Gbps" : - (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? - "1 Gbps" : "unknown speed")), - ((FLOW_RX && FLOW_TX) ? "RX/TX" : - (FLOW_RX ? "RX" : - (FLOW_TX ? "TX" : "None")))); + "Flow Control: %s\n", + (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? + "10 Gbps" : + (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? + "1 Gbps" : "unknown speed")), + ((FLOW_RX && FLOW_TX) ? "RX/TX" : + (FLOW_RX ? "RX" : + (FLOW_TX ? "TX" : "None")))); netif_carrier_on(netdev); netif_tx_wake_all_queues(netdev); @@ -2932,6 +3225,8 @@ static void ixgbe_watchdog(unsigned long data) adapter->detect_tx_hung = true; } } else { + adapter->link_up = false; + adapter->link_speed = 0; if (netif_carrier_ok(netdev)) { DPRINTK(LINK, INFO, "NIC Link is Down\n"); netif_carrier_off(netdev); @@ -2940,36 +3235,19 @@ static void ixgbe_watchdog(unsigned long data) } ixgbe_update_stats(adapter); - - if (!test_bit(__IXGBE_DOWN, &adapter->state)) { - /* Cause software interrupt to ensure rx rings are cleaned */ - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - u32 eics = - (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, eics); - } else { - /* for legacy and MSI interrupts don't set any bits that - * are enabled for EIAM, because this operation would - * set *both* EIMS and EICS for any bit in EIAM */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, - (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); - } - /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, - round_jiffies(jiffies + 2 * HZ)); - } + adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; } static int ixgbe_tso(struct ixgbe_adapter *adapter, - struct ixgbe_ring *tx_ring, struct sk_buff *skb, - u32 tx_flags, u8 *hdr_len) + struct ixgbe_ring *tx_ring, struct sk_buff *skb, + u32 tx_flags, u8 *hdr_len) { struct ixgbe_adv_tx_context_desc *context_desc; unsigned int i; int err; struct ixgbe_tx_buffer *tx_buffer_info; - u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; - u32 mss_l4len_idx = 0, l4len; + u32 vlan_macip_lens = 0, type_tucmd_mlhl; + u32 mss_l4len_idx, l4len; if (skb_is_gso(skb)) { if (skb_header_cloned(skb)) { @@ -2985,16 +3263,16 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, iph->tot_len = 0; iph->check = 0; tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, - iph->daddr, 0, - IPPROTO_TCP, - 0); + iph->daddr, 0, + IPPROTO_TCP, + 0); adapter->hw_tso_ctxt++; } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { ipv6_hdr(skb)->payload_len = 0; tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0); adapter->hw_tso6_ctxt++; } @@ -3008,7 +3286,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, vlan_macip_lens |= (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); vlan_macip_lens |= ((skb_network_offset(skb)) << - IXGBE_ADVTXD_MACLEN_SHIFT); + IXGBE_ADVTXD_MACLEN_SHIFT); *hdr_len += skb_network_offset(skb); vlan_macip_lens |= (skb_transport_header(skb) - skb_network_header(skb)); @@ -3018,8 +3296,8 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, context_desc->seqnum_seed = 0; /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ - type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | - IXGBE_ADVTXD_DTYP_CTXT); + type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT | + IXGBE_ADVTXD_DTYP_CTXT); if (skb->protocol == htons(ETH_P_IP)) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; @@ -3027,9 +3305,11 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); /* MSS L4LEN IDX */ - mss_l4len_idx |= + mss_l4len_idx = (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT); mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT); + /* use index 1 for TSO */ + mss_l4len_idx |= (1 << IXGBE_ADVTXD_IDX_SHIFT); context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); tx_buffer_info->time_stamp = jiffies; @@ -3046,8 +3326,8 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, } static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, - struct ixgbe_ring *tx_ring, - struct sk_buff *skb, u32 tx_flags) + struct ixgbe_ring *tx_ring, + struct sk_buff *skb, u32 tx_flags) { struct ixgbe_adv_tx_context_desc *context_desc; unsigned int i; @@ -3064,16 +3344,16 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, vlan_macip_lens |= (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); vlan_macip_lens |= (skb_network_offset(skb) << - IXGBE_ADVTXD_MACLEN_SHIFT); + IXGBE_ADVTXD_MACLEN_SHIFT); if (skb->ip_summed == CHECKSUM_PARTIAL) vlan_macip_lens |= (skb_transport_header(skb) - - skb_network_header(skb)); + skb_network_header(skb)); context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); context_desc->seqnum_seed = 0; type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | - IXGBE_ADVTXD_DTYP_CTXT); + IXGBE_ADVTXD_DTYP_CTXT); if (skb->ip_summed == CHECKSUM_PARTIAL) { switch (skb->protocol) { @@ -3081,16 +3361,14 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; if (ip_hdr(skb)->protocol == IPPROTO_TCP) type_tucmd_mlhl |= - IXGBE_ADVTXD_TUCMD_L4T_TCP; + IXGBE_ADVTXD_TUCMD_L4T_TCP; break; - case __constant_htons(ETH_P_IPV6): /* XXX what about other V6 headers?? */ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) type_tucmd_mlhl |= - IXGBE_ADVTXD_TUCMD_L4T_TCP; + IXGBE_ADVTXD_TUCMD_L4T_TCP; break; - default: if (unlikely(net_ratelimit())) { DPRINTK(PROBE, WARNING, @@ -3102,10 +3380,12 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, } context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); + /* use index zero for tx checksum offload */ context_desc->mss_l4len_idx = 0; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; + adapter->hw_csum_tx_good++; i++; if (i == tx_ring->count) @@ -3114,12 +3394,13 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, return true; } + return false; } static int ixgbe_tx_map(struct ixgbe_adapter *adapter, - struct ixgbe_ring *tx_ring, - struct sk_buff *skb, unsigned int first) + struct ixgbe_ring *tx_ring, + struct sk_buff *skb, unsigned int first) { struct ixgbe_tx_buffer *tx_buffer_info; unsigned int len = skb->len; @@ -3137,8 +3418,8 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, tx_buffer_info->length = size; tx_buffer_info->dma = pci_map_single(adapter->pdev, - skb->data + offset, - size, PCI_DMA_TODEVICE); + skb->data + offset, + size, PCI_DMA_TODEVICE); tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; @@ -3163,9 +3444,10 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, tx_buffer_info->length = size; tx_buffer_info->dma = pci_map_page(adapter->pdev, - frag->page, - offset, - size, PCI_DMA_TODEVICE); + frag->page, + offset, + size, + PCI_DMA_TODEVICE); tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; @@ -3188,8 +3470,8 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, } static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, - struct ixgbe_ring *tx_ring, - int tx_flags, int count, u32 paylen, u8 hdr_len) + struct ixgbe_ring *tx_ring, + int tx_flags, int count, u32 paylen, u8 hdr_len) { union ixgbe_adv_tx_desc *tx_desc = NULL; struct ixgbe_tx_buffer *tx_buffer_info; @@ -3208,15 +3490,17 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; olinfo_status |= IXGBE_TXD_POPTS_TXSM << - IXGBE_ADVTXD_POPTS_SHIFT; + IXGBE_ADVTXD_POPTS_SHIFT; + /* use index 1 context for tso */ + olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT); if (tx_flags & IXGBE_TX_FLAGS_IPV4) olinfo_status |= IXGBE_TXD_POPTS_IXSM << - IXGBE_ADVTXD_POPTS_SHIFT; + IXGBE_ADVTXD_POPTS_SHIFT; } else if (tx_flags & IXGBE_TX_FLAGS_CSUM) olinfo_status |= IXGBE_TXD_POPTS_TXSM << - IXGBE_ADVTXD_POPTS_SHIFT; + IXGBE_ADVTXD_POPTS_SHIFT; olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT); @@ -3226,9 +3510,8 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma); tx_desc->read.cmd_type_len = - cpu_to_le32(cmd_type_len | tx_buffer_info->length); + cpu_to_le32(cmd_type_len | tx_buffer_info->length); tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); - i++; if (i == tx_ring->count) i = 0; @@ -3249,7 +3532,7 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, } static int __ixgbe_maybe_stop_tx(struct net_device *netdev, - struct ixgbe_ring *tx_ring, int size) + struct ixgbe_ring *tx_ring, int size) { struct ixgbe_adapter *adapter = netdev_priv(netdev); @@ -3265,61 +3548,52 @@ static int __ixgbe_maybe_stop_tx(struct net_device *netdev, return -EBUSY; /* A reprieve! - use start_queue because it doesn't call schedule */ - netif_wake_subqueue(netdev, tx_ring->queue_index); + netif_start_subqueue(netdev, tx_ring->queue_index); ++adapter->restart_queue; return 0; } static int ixgbe_maybe_stop_tx(struct net_device *netdev, - struct ixgbe_ring *tx_ring, int size) + struct ixgbe_ring *tx_ring, int size) { if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size)) return 0; return __ixgbe_maybe_stop_tx(netdev, tx_ring, size); } - static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_ring *tx_ring; - unsigned int len = skb->len; unsigned int first; unsigned int tx_flags = 0; u8 hdr_len = 0; int r_idx = 0, tso; - unsigned int mss = 0; int count = 0; unsigned int f; - unsigned int nr_frags = skb_shinfo(skb)->nr_frags; - len -= skb->data_len; + r_idx = (adapter->num_tx_queues - 1) & skb->queue_mapping; tx_ring = &adapter->tx_ring[r_idx]; - - if (skb->len <= 0) { - dev_kfree_skb(skb); - return NETDEV_TX_OK; + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + tx_flags |= vlan_tx_tag_get(skb); + tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; + tx_flags |= IXGBE_TX_FLAGS_VLAN; } - mss = skb_shinfo(skb)->gso_size; - - if (mss) - count++; - else if (skb->ip_summed == CHECKSUM_PARTIAL) + /* three things can cause us to need a context descriptor */ + if (skb_is_gso(skb) || + (skb->ip_summed == CHECKSUM_PARTIAL) || + (tx_flags & IXGBE_TX_FLAGS_VLAN)) count++; - count += TXD_USE_COUNT(len); - for (f = 0; f < nr_frags; f++) + count += TXD_USE_COUNT(skb_headlen(skb)); + for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size); if (ixgbe_maybe_stop_tx(netdev, tx_ring, count)) { adapter->tx_busy++; return NETDEV_TX_BUSY; } - if (adapter->vlgrp && vlan_tx_tag_present(skb)) { - tx_flags |= IXGBE_TX_FLAGS_VLAN; - tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT); - } if (skb->protocol == htons(ETH_P_IP)) tx_flags |= IXGBE_TX_FLAGS_IPV4; @@ -3333,12 +3607,12 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (tso) tx_flags |= IXGBE_TX_FLAGS_TSO; else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) && - (skb->ip_summed == CHECKSUM_PARTIAL)) + (skb->ip_summed == CHECKSUM_PARTIAL)) tx_flags |= IXGBE_TX_FLAGS_CSUM; ixgbe_tx_queue(adapter, tx_ring, tx_flags, - ixgbe_tx_map(adapter, tx_ring, skb, first), - skb->len, hdr_len); + ixgbe_tx_map(adapter, tx_ring, skb, first), + skb->len, hdr_len); netdev->trans_start = jiffies; @@ -3372,15 +3646,16 @@ static struct net_device_stats *ixgbe_get_stats(struct net_device *netdev) static int ixgbe_set_mac(struct net_device *netdev, void *p) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); + memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len); - ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); return 0; } @@ -3404,28 +3679,19 @@ static void ixgbe_netpoll(struct net_device *netdev) #endif /** - * ixgbe_napi_add_all - prep napi structs for use - * @adapter: private struct - * helper function to napi_add each possible q_vector->napi - */ -static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) + * ixgbe_link_config - set up initial link with default speed and duplex + * @hw: pointer to private hardware struct + * + * Returns 0 on success, negative on failure + **/ +static int ixgbe_link_config(struct ixgbe_hw *hw) { - int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; - int (*poll)(struct napi_struct *, int); + u32 autoneg = IXGBE_LINK_SPEED_10GB_FULL; - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - poll = &ixgbe_clean_rxonly; - } else { - poll = &ixgbe_poll; - /* only one q_vector for legacy modes */ - q_vectors = 1; - } + /* must always autoneg for both 1G and 10G link */ + hw->mac.autoneg = true; - for (i = 0; i < q_vectors; i++) { - struct ixgbe_q_vector *q_vector = &adapter->q_vector[i]; - netif_napi_add(adapter->netdev, &q_vector->napi, - (*poll), 64); - } + return hw->mac.ops.setup_link_speed(hw, autoneg, true, true); } /** @@ -3440,17 +3706,16 @@ static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) * and a hardware reset occur. **/ static int __devinit ixgbe_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) + const struct pci_device_id *ent) { struct net_device *netdev; struct ixgbe_adapter *adapter = NULL; struct ixgbe_hw *hw; const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data]; - unsigned long mmio_start, mmio_len; static int cards_found; int i, err, pci_using_dac; u16 link_status, link_speed, link_width; - u32 part_num; + u32 part_num, eec; err = pci_enable_device(pdev); if (err) @@ -3465,7 +3730,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (err) { dev_err(&pdev->dev, "No usable DMA " - "configuration, aborting\n"); + "configuration, aborting\n"); goto err_dma; } } @@ -3498,10 +3763,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, hw->back = adapter; adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; - mmio_start = pci_resource_start(pdev, 0); - mmio_len = pci_resource_len(pdev, 0); - - hw->hw_addr = ioremap(mmio_start, mmio_len); + hw->hw_addr = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); if (!hw->hw_addr) { err = -EIO; goto err_ioremap; @@ -3516,7 +3779,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->stop = &ixgbe_close; netdev->hard_start_xmit = &ixgbe_xmit_frame; netdev->get_stats = &ixgbe_get_stats; - netdev->set_multicast_list = &ixgbe_set_multi; + netdev->set_rx_mode = &ixgbe_set_rx_mode; + netdev->set_multicast_list = &ixgbe_set_rx_mode; netdev->set_mac_address = &ixgbe_set_mac; netdev->change_mtu = &ixgbe_change_mtu; ixgbe_set_ethtool_ops(netdev); @@ -3530,22 +3794,23 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, #endif strcpy(netdev->name, pci_name(pdev)); - netdev->mem_start = mmio_start; - netdev->mem_end = mmio_start + mmio_len; - adapter->bd_number = cards_found; - /* PCI config space info */ - hw->vendor_id = pdev->vendor; - hw->device_id = pdev->device; - hw->revision_id = pdev->revision; - hw->subsystem_vendor_id = pdev->subsystem_vendor; - hw->subsystem_device_id = pdev->subsystem_device; - /* Setup hw api */ memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops)); hw->mac.type = ii->mac; + /* EEPROM */ + memcpy(&hw->eeprom.ops, ii->eeprom_ops, sizeof(hw->eeprom.ops)); + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + /* If EEPROM is valid (bit 8 = 1), use default otherwise use bit bang */ + if (!(eec & (1 << 8))) + hw->eeprom.ops.read = &ixgbe_read_eeprom_bit_bang_generic; + + /* PHY */ + memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); + /* phy->sfp_type = ixgbe_sfp_type_unknown; */ + err = ii->get_invariants(hw); if (err) goto err_hw_init; @@ -3555,26 +3820,34 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (err) goto err_sw_init; + /* reset_hw fills in the perm_addr as well */ + err = hw->mac.ops.reset_hw(hw); + if (err) { + dev_err(&adapter->pdev->dev, "HW Init failed: %d\n", err); + goto err_sw_init; + } + 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_IP_CSUM | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; - netdev->features |= NETIF_F_LRO; + netdev->features |= NETIF_F_IPV6_CSUM; netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; + netdev->features |= NETIF_F_LRO; netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; - netdev->vlan_features |= NETIF_F_HW_CSUM; + netdev->vlan_features |= NETIF_F_IP_CSUM; netdev->vlan_features |= NETIF_F_SG; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; /* make sure the EEPROM is good */ - if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { + if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) { dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n"); err = -EIO; goto err_eeprom; @@ -3583,7 +3856,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len); memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len); - if (ixgbe_validate_mac_addr(netdev->dev_addr)) { + if (ixgbe_validate_mac_addr(netdev->perm_addr)) { + dev_err(&pdev->dev, "invalid MAC address\n"); err = -EIO; goto err_eeprom; } @@ -3593,13 +3867,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, adapter->watchdog_timer.data = (unsigned long)adapter; INIT_WORK(&adapter->reset_task, ixgbe_reset_task); - - /* initialize default flow control settings */ - hw->fc.original_type = ixgbe_fc_full; - hw->fc.type = ixgbe_fc_full; - hw->fc.high_water = IXGBE_DEFAULT_FCRTH; - hw->fc.low_water = IXGBE_DEFAULT_FCRTL; - hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; + INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task); err = ixgbe_init_interrupt_scheme(adapter); if (err) @@ -3610,32 +3878,39 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, link_speed = link_status & IXGBE_PCI_LINK_SPEED; link_width = link_status & IXGBE_PCI_LINK_WIDTH; dev_info(&pdev->dev, "(PCI Express:%s:%s) " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" : - (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" : - "Unknown"), - ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" : - (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" : - (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" : - (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" : - "Unknown"), - netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], - netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); - ixgbe_read_part_num(hw, &part_num); + "%02x:%02x:%02x:%02x:%02x:%02x\n", + ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" : + (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" : + "Unknown"), + ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" : + (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" : + (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" : + (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" : + "Unknown"), + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + ixgbe_read_pba_num_generic(hw, &part_num); dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n", - hw->mac.type, hw->phy.type, - (part_num >> 8), (part_num & 0xff)); + hw->mac.type, hw->phy.type, + (part_num >> 8), (part_num & 0xff)); if (link_width <= IXGBE_PCI_LINK_WIDTH_4) { dev_warn(&pdev->dev, "PCI-Express bandwidth available for " - "this card is not sufficient for optimal " - "performance.\n"); + "this card is not sufficient for optimal " + "performance.\n"); dev_warn(&pdev->dev, "For optimal performance a x8 " - "PCI-Express slot is required.\n"); + "PCI-Express slot is required.\n"); } /* reset the hardware with the new settings */ - ixgbe_start_hw(hw); + hw->mac.ops.start_hw(hw); + + /* link_config depends on start_hw being called at least once */ + err = ixgbe_link_config(hw); + if (err) { + dev_err(&pdev->dev, "setup_link_speed FAILED %d\n", err); + goto err_register; + } netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); @@ -3647,7 +3922,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (err) goto err_register; -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; /* always use CB2 mode, difference is masked @@ -3697,7 +3972,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) flush_scheduled_work(); -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED; dca_remove_requester(&pdev->dev); @@ -3715,6 +3990,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) pci_release_regions(pdev); DPRINTK(PROBE, INFO, "complete\n"); + ixgbe_napi_del_all(adapter); kfree(adapter->tx_ring); kfree(adapter->rx_ring); @@ -3732,7 +4008,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) * this device has been detected. */ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) + pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct ixgbe_adapter *adapter = netdev->priv; @@ -3743,7 +4019,7 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, ixgbe_down(adapter); pci_disable_device(pdev); - /* Request a slot slot reset. */ + /* Request a slot reset. */ return PCI_ERS_RESULT_NEED_RESET; } @@ -3760,7 +4036,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) if (pci_enable_device(pdev)) { DPRINTK(PROBE, ERR, - "Cannot re-enable PCI device after reset.\n"); + "Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } pci_set_master(pdev); @@ -3794,7 +4070,6 @@ static void ixgbe_io_resume(struct pci_dev *pdev) } netif_device_attach(netdev); - } static struct pci_error_handlers ixgbe_err_handler = { @@ -3830,13 +4105,14 @@ static int __init ixgbe_init_module(void) printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright); -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA dca_register_notify(&dca_notifier); - #endif + ret = pci_register_driver(&ixgbe_driver); return ret; } + module_init(ixgbe_init_module); /** @@ -3847,24 +4123,24 @@ module_init(ixgbe_init_module); **/ static void __exit ixgbe_exit_module(void) { -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA dca_unregister_notify(&dca_notifier); #endif pci_unregister_driver(&ixgbe_driver); } -#ifdef CONFIG_DCA +#ifdef CONFIG_IXGBE_DCA static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event, - void *p) + void *p) { int ret_val; ret_val = driver_for_each_device(&ixgbe_driver.driver, NULL, &event, - __ixgbe_notify_dca); + __ixgbe_notify_dca); return ret_val ? NOTIFY_BAD : NOTIFY_DONE; } -#endif /* CONFIG_DCA */ +#endif /* CONFIG_IXGBE_DCA */ module_exit(ixgbe_exit_module); diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 8002931ae82..764035a8c9a 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2007 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -20,7 +20,6 @@ the file called "COPYING". Contact Information: - Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -33,32 +32,36 @@ #include "ixgbe_common.h" #include "ixgbe_phy.h" +static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr); static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id); static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw); -static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr); -static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, - u32 device_type, u16 phy_data); /** - * ixgbe_identify_phy - Get physical layer module + * ixgbe_identify_phy_generic - Get physical layer module * @hw: pointer to hardware structure * * Determines the physical layer module found on the current adapter. **/ -s32 ixgbe_identify_phy(struct ixgbe_hw *hw) +s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_PHY_ADDR_INVALID; u32 phy_addr; - for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { - if (ixgbe_validate_phy_addr(hw, phy_addr)) { - hw->phy.addr = phy_addr; - ixgbe_get_phy_id(hw); - hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); - status = 0; - break; + if (hw->phy.type == ixgbe_phy_unknown) { + for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { + if (ixgbe_validate_phy_addr(hw, phy_addr)) { + hw->phy.addr = phy_addr; + ixgbe_get_phy_id(hw); + hw->phy.type = + ixgbe_get_phy_type_from_id(hw->phy.id); + status = 0; + break; + } } + } else { + status = 0; } + return status; } @@ -73,10 +76,8 @@ static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr) bool valid = false; hw->phy.addr = phy_addr; - ixgbe_read_phy_reg(hw, - IXGBE_MDIO_PHY_ID_HIGH, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, - &phy_id); + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id); if (phy_id != 0xFFFF && phy_id != 0x0) valid = true; @@ -95,21 +96,18 @@ static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) u16 phy_id_high = 0; u16 phy_id_low = 0; - status = ixgbe_read_phy_reg(hw, - IXGBE_MDIO_PHY_ID_HIGH, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, - &phy_id_high); + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id_high); if (status == 0) { hw->phy.id = (u32)(phy_id_high << 16); - status = ixgbe_read_phy_reg(hw, - IXGBE_MDIO_PHY_ID_LOW, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, - &phy_id_low); + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id_low); hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); } - return status; } @@ -123,9 +121,6 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) enum ixgbe_phy_type phy_type; switch (phy_id) { - case TN1010_PHY_ID: - phy_type = ixgbe_phy_tn; - break; case QT2022_PHY_ID: phy_type = ixgbe_phy_qt; break; @@ -138,32 +133,31 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) } /** - * ixgbe_reset_phy - Performs a PHY reset + * ixgbe_reset_phy_generic - Performs a PHY reset * @hw: pointer to hardware structure **/ -s32 ixgbe_reset_phy(struct ixgbe_hw *hw) +s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) { /* * Perform soft PHY reset to the PHY_XS. * This will cause a soft reset to the PHY */ - return ixgbe_write_phy_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, - IXGBE_MDIO_PHY_XS_DEV_TYPE, - IXGBE_MDIO_PHY_XS_RESET); + return hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, + IXGBE_MDIO_PHY_XS_RESET); } /** - * ixgbe_read_phy_reg - Reads a value from a specified PHY register + * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register * @hw: pointer to hardware structure * @reg_addr: 32 bit address of PHY register to read * @phy_data: Pointer to read data from PHY register **/ -s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, - u32 device_type, u16 *phy_data) +s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data) { u32 command; u32 i; - u32 timeout = 10; u32 data; s32 status = 0; u16 gssr; @@ -179,9 +173,9 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, if (status == 0) { /* Setup and write the address cycle command */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | - (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | - (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -190,7 +184,7 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, * The MDI Command bit will clear when the operation is * complete */ - for (i = 0; i < timeout; i++) { + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { udelay(10); command = IXGBE_READ_REG(hw, IXGBE_MSCA); @@ -210,9 +204,9 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, * command */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | - (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | - (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -221,7 +215,7 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, * completed. The MDI Command bit will clear when the * operation is complete */ - for (i = 0; i < timeout; i++) { + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { udelay(10); command = IXGBE_READ_REG(hw, IXGBE_MSCA); @@ -231,8 +225,7 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, } if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { - hw_dbg(hw, - "PHY read command didn't complete\n"); + hw_dbg(hw, "PHY read command didn't complete\n"); status = IXGBE_ERR_PHY; } else { /* @@ -247,22 +240,22 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, ixgbe_release_swfw_sync(hw, gssr); } + return status; } /** - * ixgbe_write_phy_reg - Writes a value to specified PHY register + * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register * @hw: pointer to hardware structure * @reg_addr: 32 bit PHY register to write * @device_type: 5 bit device type * @phy_data: Data to write to the PHY register **/ -static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, - u32 device_type, u16 phy_data) +s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data) { u32 command; u32 i; - u32 timeout = 10; s32 status = 0; u16 gssr; @@ -280,9 +273,9 @@ static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, /* Setup and write the address cycle command */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | - (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | - (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -291,19 +284,19 @@ static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, * The MDI Command bit will clear when the operation is * complete */ - for (i = 0; i < timeout; i++) { + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { udelay(10); command = IXGBE_READ_REG(hw, IXGBE_MSCA); - if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { - hw_dbg(hw, "PHY address cmd didn't complete\n"); + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) break; - } } - if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + hw_dbg(hw, "PHY address cmd didn't complete\n"); status = IXGBE_ERR_PHY; + } if (status == 0) { /* @@ -311,9 +304,9 @@ static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, * command */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | - (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | - (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -322,20 +315,19 @@ static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, * completed. The MDI Command bit will clear when the * operation is complete */ - for (i = 0; i < timeout; i++) { + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { udelay(10); command = IXGBE_READ_REG(hw, IXGBE_MSCA); - if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { - hw_dbg(hw, "PHY write command did not " - "complete.\n"); + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) break; - } } - if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + hw_dbg(hw, "PHY address cmd didn't complete\n"); status = IXGBE_ERR_PHY; + } } ixgbe_release_swfw_sync(hw, gssr); @@ -345,67 +337,54 @@ static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, } /** - * ixgbe_setup_tnx_phy_link - Set and restart autoneg + * ixgbe_setup_phy_link_generic - Set and restart autoneg * @hw: pointer to hardware structure * * Restart autonegotiation and PHY and waits for completion. **/ -s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw) +s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) { s32 status = IXGBE_NOT_IMPLEMENTED; u32 time_out; u32 max_time_out = 10; - u16 autoneg_speed_selection_register = 0x10; - u16 autoneg_restart_mask = 0x0200; - u16 autoneg_complete_mask = 0x0020; - u16 autoneg_reg = 0; + u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; /* * Set advertisement settings in PHY based on autoneg_advertised * settings. If autoneg_advertised = 0, then advertise default values - * txn devices cannot be "forced" to a autoneg 10G and fail. But can + * tnx devices cannot be "forced" to a autoneg 10G and fail. But can * for a 1G. */ - ixgbe_read_phy_reg(hw, - autoneg_speed_selection_register, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_reg); + hw->phy.ops.read_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL) autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */ else autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */ - ixgbe_write_phy_reg(hw, - autoneg_speed_selection_register, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - autoneg_reg); - + hw->phy.ops.write_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); /* Restart PHY autonegotiation and wait for completion */ - ixgbe_read_phy_reg(hw, - IXGBE_MDIO_AUTO_NEG_CONTROL, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_reg); + hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); - autoneg_reg |= autoneg_restart_mask; + autoneg_reg |= IXGBE_MII_RESTART; - ixgbe_write_phy_reg(hw, - IXGBE_MDIO_AUTO_NEG_CONTROL, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - autoneg_reg); + hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); /* Wait for autonegotiation to finish */ for (time_out = 0; time_out < max_time_out; time_out++) { udelay(10); /* Restart PHY autonegotiation and wait for completion */ - status = ixgbe_read_phy_reg(hw, - IXGBE_MDIO_AUTO_NEG_STATUS, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_reg); + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); - autoneg_reg &= autoneg_complete_mask; - if (autoneg_reg == autoneg_complete_mask) { + autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE; + if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) { status = 0; break; } @@ -418,64 +397,17 @@ s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw) } /** - * ixgbe_check_tnx_phy_link - Determine link and speed status - * @hw: pointer to hardware structure - * - * Reads the VS1 register to determine if link is up and the current speed for - * the PHY. - **/ -s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, - bool *link_up) -{ - s32 status = 0; - u32 time_out; - u32 max_time_out = 10; - u16 phy_link = 0; - u16 phy_speed = 0; - u16 phy_data = 0; - - /* Initialize speed and link to default case */ - *link_up = false; - *speed = IXGBE_LINK_SPEED_10GB_FULL; - - /* - * Check current speed and link status of the PHY register. - * This is a vendor specific register and may have to - * be changed for other copper PHYs. - */ - for (time_out = 0; time_out < max_time_out; time_out++) { - udelay(10); - if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { - *link_up = true; - if (phy_speed == - IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) - *speed = IXGBE_LINK_SPEED_1GB_FULL; - break; - } else { - status = ixgbe_read_phy_reg(hw, - IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, - IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, - &phy_data); - phy_link = phy_data & - IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; - phy_speed = phy_data & - IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; - } - } - - return status; -} - -/** - * ixgbe_setup_tnx_phy_link_speed - Sets the auto advertised capabilities + * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if autonegotiation enabled **/ -s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, - bool autoneg, - bool autoneg_wait_to_complete) +s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) { + /* * Clear autoneg_advertised and set new values based on input link * speed. @@ -484,11 +416,13 @@ s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, if (speed & IXGBE_LINK_SPEED_10GB_FULL) hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; + if (speed & IXGBE_LINK_SPEED_1GB_FULL) hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; /* Setup link based on the new speed settings */ - ixgbe_setup_tnx_phy_link(hw); + hw->phy.ops.setup_link(hw); return 0; } + diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h index aa3ea72e678..9bfe3f2b1d8 100644 --- a/drivers/net/ixgbe/ixgbe_phy.h +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2007 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -20,7 +20,6 @@ the file called "COPYING". Contact Information: - Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -30,20 +29,52 @@ #define _IXGBE_PHY_H_ #include "ixgbe_type.h" +#define IXGBE_I2C_EEPROM_DEV_ADDR 0xA0 -s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw); -s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up); -s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg, - bool autoneg_wait_to_complete); -s32 ixgbe_identify_phy(struct ixgbe_hw *hw); -s32 ixgbe_reset_phy(struct ixgbe_hw *hw); -s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, - u32 device_type, u16 *phy_data); - -/* PHY specific */ -s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw); -s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up); -s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg, - bool autoneg_wait_to_complete); +/* EEPROM byte offsets */ +#define IXGBE_SFF_IDENTIFIER 0x0 +#define IXGBE_SFF_IDENTIFIER_SFP 0x3 +#define IXGBE_SFF_VENDOR_OUI_BYTE0 0x25 +#define IXGBE_SFF_VENDOR_OUI_BYTE1 0x26 +#define IXGBE_SFF_VENDOR_OUI_BYTE2 0x27 +#define IXGBE_SFF_1GBE_COMP_CODES 0x6 +#define IXGBE_SFF_10GBE_COMP_CODES 0x3 +#define IXGBE_SFF_TRANSMISSION_MEDIA 0x9 + +/* Bitmasks */ +#define IXGBE_SFF_TWIN_AX_CAPABLE 0x80 +#define IXGBE_SFF_1GBASESX_CAPABLE 0x1 +#define IXGBE_SFF_10GBASESR_CAPABLE 0x10 +#define IXGBE_SFF_10GBASELR_CAPABLE 0x20 +#define IXGBE_I2C_EEPROM_READ_MASK 0x100 +#define IXGBE_I2C_EEPROM_STATUS_MASK 0x3 +#define IXGBE_I2C_EEPROM_STATUS_NO_OPERATION 0x0 +#define IXGBE_I2C_EEPROM_STATUS_PASS 0x1 +#define IXGBE_I2C_EEPROM_STATUS_FAIL 0x2 +#define IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS 0x3 + +/* Bit-shift macros */ +#define IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT 12 +#define IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT 8 +#define IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT 4 + +/* Vendor OUIs: format of OUI is 0x[byte0][byte1][byte2][00] */ +#define IXGBE_SFF_VENDOR_OUI_TYCO 0x00407600 +#define IXGBE_SFF_VENDOR_OUI_FTL 0x00906500 +#define IXGBE_SFF_VENDOR_OUI_AVAGO 0x00176A00 + + +s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw); +s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw); +s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw); +s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data); +s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data); +s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw); +s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); #endif /* _IXGBE_PHY_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index c0282a223df..c6f8fa1c4e5 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2007 Intel Corporation. + Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -20,7 +20,6 @@ the file called "COPYING". Contact Information: - Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -37,9 +36,9 @@ /* Device IDs */ #define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 -#define IXGBE_DEV_ID_82598AT_DUAL_PORT 0x10C8 #define IXGBE_DEV_ID_82598EB_CX4 0x10DD #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC +#define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 /* General Registers */ #define IXGBE_CTRL 0x00000 @@ -70,11 +69,11 @@ #define IXGBE_EIMC 0x00888 #define IXGBE_EIAC 0x00810 #define IXGBE_EIAM 0x00890 -#define IXGBE_EITR(_i) (0x00820 + ((_i) * 4)) /* 0x820-0x86c */ -#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */ +#define IXGBE_EITR(_i) (((_i) <= 23) ? (0x00820 + ((_i) * 4)) : (0x012300 + ((_i) * 4))) +#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */ #define IXGBE_MSIXT 0x00000 /* MSI-X Table. 0x0000 - 0x01C */ #define IXGBE_MSIXPBA 0x02000 /* MSI-X Pending bit array */ -#define IXGBE_PBACL 0x11068 +#define IXGBE_PBACL(_i) (((_i) == 0) ? (0x11068) : (0x110C0 + ((_i) * 4))) #define IXGBE_GPIE 0x00898 /* Flow Control Registers */ @@ -86,20 +85,33 @@ #define IXGBE_TFCS 0x0CE00 /* Receive DMA Registers */ -#define IXGBE_RDBAL(_i) (0x01000 + ((_i) * 0x40)) /* 64 of each (0-63)*/ -#define IXGBE_RDBAH(_i) (0x01004 + ((_i) * 0x40)) -#define IXGBE_RDLEN(_i) (0x01008 + ((_i) * 0x40)) -#define IXGBE_RDH(_i) (0x01010 + ((_i) * 0x40)) -#define IXGBE_RDT(_i) (0x01018 + ((_i) * 0x40)) -#define IXGBE_RXDCTL(_i) (0x01028 + ((_i) * 0x40)) -#define IXGBE_RSCCTL(_i) (0x0102C + ((_i) * 0x40)) -#define IXGBE_SRRCTL(_i) (0x02100 + ((_i) * 4)) - /* array of 16 (0x02100-0x0213C) */ -#define IXGBE_DCA_RXCTRL(_i) (0x02200 + ((_i) * 4)) - /* array of 16 (0x02200-0x0223C) */ -#define IXGBE_RDRXCTL 0x02F00 +#define IXGBE_RDBAL(_i) (((_i) < 64) ? (0x01000 + ((_i) * 0x40)) : (0x0D000 + ((_i - 64) * 0x40))) +#define IXGBE_RDBAH(_i) (((_i) < 64) ? (0x01004 + ((_i) * 0x40)) : (0x0D004 + ((_i - 64) * 0x40))) +#define IXGBE_RDLEN(_i) (((_i) < 64) ? (0x01008 + ((_i) * 0x40)) : (0x0D008 + ((_i - 64) * 0x40))) +#define IXGBE_RDH(_i) (((_i) < 64) ? (0x01010 + ((_i) * 0x40)) : (0x0D010 + ((_i - 64) * 0x40))) +#define IXGBE_RDT(_i) (((_i) < 64) ? (0x01018 + ((_i) * 0x40)) : (0x0D018 + ((_i - 64) * 0x40))) +#define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : (0x0D028 + ((_i - 64) * 0x40))) +/* + * Split and Replication Receive Control Registers + * 00-15 : 0x02100 + n*4 + * 16-64 : 0x01014 + n*0x40 + * 64-127: 0x0D014 + (n-64)*0x40 + */ +#define IXGBE_SRRCTL(_i) (((_i) <= 15) ? (0x02100 + ((_i) * 4)) : \ + (((_i) < 64) ? (0x01014 + ((_i) * 0x40)) : \ + (0x0D014 + ((_i - 64) * 0x40)))) +/* + * Rx DCA Control Register: + * 00-15 : 0x02200 + n*4 + * 16-64 : 0x0100C + n*0x40 + * 64-127: 0x0D00C + (n-64)*0x40 + */ +#define IXGBE_DCA_RXCTRL(_i) (((_i) <= 15) ? (0x02200 + ((_i) * 4)) : \ + (((_i) < 64) ? (0x0100C + ((_i) * 0x40)) : \ + (0x0D00C + ((_i - 64) * 0x40)))) +#define IXGBE_RDRXCTL 0x02F00 #define IXGBE_RXPBSIZE(_i) (0x03C00 + ((_i) * 4)) - /* 8 of these 0x03C00 - 0x03C1C */ + /* 8 of these 0x03C00 - 0x03C1C */ #define IXGBE_RXCTRL 0x03000 #define IXGBE_DROPEN 0x03D04 #define IXGBE_RXPBSIZE_SHIFT 10 @@ -107,29 +119,32 @@ /* Receive Registers */ #define IXGBE_RXCSUM 0x05000 #define IXGBE_RFCTL 0x05008 +#define IXGBE_DRECCCTL 0x02F08 +#define IXGBE_DRECCCTL_DISABLE 0 +/* Multicast Table Array - 128 entries */ #define IXGBE_MTA(_i) (0x05200 + ((_i) * 4)) - /* Multicast Table Array - 128 entries */ -#define IXGBE_RAL(_i) (0x05400 + ((_i) * 8)) /* 16 of these (0-15) */ -#define IXGBE_RAH(_i) (0x05404 + ((_i) * 8)) /* 16 of these (0-15) */ -#define IXGBE_PSRTYPE 0x05480 - /* 0x5480-0x54BC Packet split receive type */ +#define IXGBE_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : (0x0A200 + ((_i) * 8))) +#define IXGBE_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : (0x0A204 + ((_i) * 8))) +/* Packet split receive type */ +#define IXGBE_PSRTYPE(_i) (((_i) <= 15) ? (0x05480 + ((_i) * 4)) : (0x0EA00 + ((_i) * 4))) +/* array of 4096 1-bit vlan filters */ #define IXGBE_VFTA(_i) (0x0A000 + ((_i) * 4)) - /* array of 4096 1-bit vlan filters */ +/*array of 4096 4-bit vlan vmdq indices */ #define IXGBE_VFTAVIND(_j, _i) (0x0A200 + ((_j) * 0x200) + ((_i) * 4)) - /*array of 4096 4-bit vlan vmdq indicies */ #define IXGBE_FCTRL 0x05080 #define IXGBE_VLNCTRL 0x05088 #define IXGBE_MCSTCTRL 0x05090 #define IXGBE_MRQC 0x05818 -#define IXGBE_VMD_CTL 0x0581C #define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */ #define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */ #define IXGBE_IMIRVP 0x05AC0 +#define IXGBE_VMD_CTL 0x0581C #define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */ #define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */ + /* Transmit DMA registers */ -#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40))/* 32 of these (0-31)*/ +#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40)) /* 32 of these (0-31)*/ #define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40)) #define IXGBE_TDLEN(_i) (0x06008 + ((_i) * 0x40)) #define IXGBE_TDH(_i) (0x06010 + ((_i) * 0x40)) @@ -138,11 +153,10 @@ #define IXGBE_TDWBAL(_i) (0x06038 + ((_i) * 0x40)) #define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40)) #define IXGBE_DTXCTL 0x07E00 -#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) - /* there are 16 of these (0-15) */ + +#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */ #define IXGBE_TIPG 0x0CB00 -#define IXGBE_TXPBSIZE(_i) (0x0CC00 + ((_i) *0x04)) - /* there are 8 of these */ +#define IXGBE_TXPBSIZE(_i) (0x0CC00 + ((_i) * 4)) /* 8 of these */ #define IXGBE_MNGTXMAP 0x0CD10 #define IXGBE_TIPG_FIBER_DEFAULT 3 #define IXGBE_TXPBSIZE_SHIFT 10 @@ -154,6 +168,7 @@ #define IXGBE_IPAV 0x05838 #define IXGBE_IP4AT 0x05840 /* IPv4 table 0x5840-0x5858 */ #define IXGBE_IP6AT 0x05880 /* IPv6 table 0x5880-0x588F */ + #define IXGBE_WUPL 0x05900 #define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */ #define IXGBE_FHFT 0x09000 /* Flex host filter table 9000-93FC */ @@ -170,6 +185,8 @@ #define IXGBE_TDPT2TCCR(_i) (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */ #define IXGBE_TDPT2TCSR(_i) (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */ + + /* Stats registers */ #define IXGBE_CRCERRS 0x04000 #define IXGBE_ILLERRC 0x04004 @@ -224,7 +241,7 @@ #define IXGBE_XEC 0x04120 #define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */ -#define IXGBE_TQSMR(_i) (0x07300 + ((_i) * 4)) /* 8 of these */ +#define IXGBE_TQSMR(_i) (((_i) <= 7) ? (0x07300 + ((_i) * 4)) : (0x08600 + ((_i) * 4))) #define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */ #define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */ @@ -275,23 +292,17 @@ #define IXGBE_DCA_CTRL 0x11074 /* Diagnostic Registers */ -#define IXGBE_RDSTATCTL 0x02C20 -#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */ -#define IXGBE_RDHMPN 0x02F08 -#define IXGBE_RIC_DW0 0x02F10 -#define IXGBE_RIC_DW1 0x02F14 -#define IXGBE_RIC_DW2 0x02F18 -#define IXGBE_RIC_DW3 0x02F1C -#define IXGBE_RDPROBE 0x02F20 -#define IXGBE_TDSTATCTL 0x07C20 -#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */ -#define IXGBE_TDHMPN 0x07F08 -#define IXGBE_TIC_DW0 0x07F10 -#define IXGBE_TIC_DW1 0x07F14 -#define IXGBE_TIC_DW2 0x07F18 -#define IXGBE_TIC_DW3 0x07F1C -#define IXGBE_TDPROBE 0x07F20 -#define IXGBE_TXBUFCTRL 0x0C600 +#define IXGBE_RDSTATCTL 0x02C20 +#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */ +#define IXGBE_RDHMPN 0x02F08 +#define IXGBE_RIC_DW(_i) (0x02F10 + ((_i) * 4)) +#define IXGBE_RDPROBE 0x02F20 +#define IXGBE_TDSTATCTL 0x07C20 +#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */ +#define IXGBE_TDHMPN 0x07F08 +#define IXGBE_TIC_DW(_i) (0x07F10 + ((_i) * 4)) +#define IXGBE_TDPROBE 0x07F20 +#define IXGBE_TXBUFCTRL 0x0C600 #define IXGBE_TXBUFDATA0 0x0C610 #define IXGBE_TXBUFDATA1 0x0C614 #define IXGBE_TXBUFDATA2 0x0C618 @@ -356,12 +367,10 @@ #define IXGBE_ANLP2 0x042B4 #define IXGBE_ATLASCTL 0x04800 -/* RSCCTL Bit Masks */ -#define IXGBE_RSCCTL_RSCEN 0x01 -#define IXGBE_RSCCTL_MAXDESC_1 0x00 -#define IXGBE_RSCCTL_MAXDESC_4 0x04 -#define IXGBE_RSCCTL_MAXDESC_8 0x08 -#define IXGBE_RSCCTL_MAXDESC_16 0x0C +/* RDRXCTL Bit Masks */ +#define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000 /* Rx Desc Min Threshold Size */ +#define IXGBE_RDRXCTL_MVMEN 0x00000020 +#define IXGBE_RDRXCTL_DMAIDONE 0x00000008 /* DMA init cycle done */ /* CTRL Bit Masks */ #define IXGBE_CTRL_GIO_DIS 0x00000004 /* Global IO Master Disable bit */ @@ -394,7 +403,7 @@ #define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */ #define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */ -#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */ +#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */ #define IXGBE_DCA_MAX_QUEUES_82598 16 /* DCA regs only on 16 queues */ /* MSCA Bit Masks */ @@ -418,10 +427,10 @@ #define IXGBE_MSCA_MDI_IN_PROG_EN 0x80000000 /* MDI in progress enable */ /* MSRWD bit masks */ -#define IXGBE_MSRWD_WRITE_DATA_MASK 0x0000FFFF -#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0 -#define IXGBE_MSRWD_READ_DATA_MASK 0xFFFF0000 -#define IXGBE_MSRWD_READ_DATA_SHIFT 16 +#define IXGBE_MSRWD_WRITE_DATA_MASK 0x0000FFFF +#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0 +#define IXGBE_MSRWD_READ_DATA_MASK 0xFFFF0000 +#define IXGBE_MSRWD_READ_DATA_SHIFT 16 /* Atlas registers */ #define IXGBE_ATLAS_PDN_LPBK 0x24 @@ -436,6 +445,7 @@ #define IXGBE_ATLAS_PDN_TX_1G_QL_ALL 0xF0 #define IXGBE_ATLAS_PDN_TX_AN_QL_ALL 0xF0 + /* Device Type definitions for new protocol MDIO commands */ #define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1 #define IXGBE_MDIO_PCS_DEV_TYPE 0x3 @@ -443,6 +453,8 @@ #define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ +#define IXGBE_MDIO_COMMAND_TIMEOUT 100 /* PHY Timeout for 1 GB mode */ + #define IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL 0x0 /* VS1 Control Reg */ #define IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS 0x1 /* VS1 Status Reg */ #define IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS 0x0008 /* 1 = Link Up */ @@ -456,23 +468,39 @@ #define IXGBE_MDIO_PHY_XS_RESET 0x8000 /* PHY_XS Reset */ #define IXGBE_MDIO_PHY_ID_HIGH 0x2 /* PHY ID High Reg*/ #define IXGBE_MDIO_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/ -#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Abilty Reg */ +#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Ability Reg */ #define IXGBE_MDIO_PHY_SPEED_10G 0x0001 /* 10G capable */ #define IXGBE_MDIO_PHY_SPEED_1G 0x0010 /* 1G capable */ +#define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR 0xC30A /* PHY_XS SDA/SCL Address Reg */ +#define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA 0xC30B /* PHY_XS SDA/SCL Data Reg */ +#define IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT 0xC30C /* PHY_XS SDA/SCL Status Reg */ + +/* MII clause 22/28 definitions */ +#define IXGBE_MDIO_PHY_LOW_POWER_MODE 0x0800 + +#define IXGBE_MII_SPEED_SELECTION_REG 0x10 +#define IXGBE_MII_RESTART 0x200 +#define IXGBE_MII_AUTONEG_COMPLETE 0x20 +#define IXGBE_MII_AUTONEG_REG 0x0 + #define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0 #define IXGBE_MAX_PHY_ADDR 32 /* PHY IDs*/ -#define TN1010_PHY_ID 0x00A19410 #define QT2022_PHY_ID 0x0043A400 +/* PHY Types */ +#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 + /* General purpose Interrupt Enable */ -#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */ -#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */ -#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ -#define IXGBE_GPIE_EIAME 0x40000000 -#define IXGBE_GPIE_PBA_SUPPORT 0x80000000 +#define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */ +#define IXGBE_SDP1_GPIEN 0x00000002 /* SDP1 */ +#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */ +#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */ +#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ +#define IXGBE_GPIE_EIAME 0x40000000 +#define IXGBE_GPIE_PBA_SUPPORT 0x80000000 /* Transmit Flow Control status */ #define IXGBE_TFCS_TXOFF 0x00000001 @@ -533,7 +561,7 @@ #define IXGBE_PAP_TXPAUSECNT_MASK 0x0000FFFF /* Pause counter mask */ /* RMCS Bit Masks */ -#define IXGBE_RMCS_RRM 0x00000002 /* Receive Recylce Mode enable */ +#define IXGBE_RMCS_RRM 0x00000002 /* Receive Recycle Mode enable */ /* Receive Arbitration Control: 0 Round Robin, 1 DFP */ #define IXGBE_RMCS_RAC 0x00000004 #define IXGBE_RMCS_DFP IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */ @@ -541,12 +569,15 @@ #define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */ #define IXGBE_RMCS_ARBDIS 0x00000040 /* Arbitration disable bit */ + /* Interrupt register bitmasks */ /* Extended Interrupt Cause Read */ #define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */ #define IXGBE_EICR_LSC 0x00100000 /* Link Status Change */ -#define IXGBE_EICR_MNG 0x00400000 /* Managability Event Interrupt */ +#define IXGBE_EICR_MNG 0x00400000 /* Manageability Event Interrupt */ +#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */ +#define IXGBE_EICR_GPI_SDP1 0x02000000 /* Gen Purpose Interrupt on SDP1 */ #define IXGBE_EICR_PBUR 0x10000000 /* Packet Buffer Handler Error */ #define IXGBE_EICR_DHER 0x20000000 /* Descriptor Handler Error */ #define IXGBE_EICR_TCP_TIMER 0x40000000 /* TCP Timer */ @@ -554,11 +585,12 @@ /* Extended Interrupt Cause Set */ #define IXGBE_EICS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ -#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */ -#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */ -#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ -#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ -#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */ +#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EICS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */ +#define IXGBE_EICS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */ +#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Err */ +#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */ #define IXGBE_EICS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ #define IXGBE_EICS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ @@ -566,7 +598,9 @@ #define IXGBE_EIMS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ #define IXGBE_EIMS_LSC IXGBE_EICR_LSC /* Link Status Change */ #define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ -#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EIMS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */ +#define IXGBE_EIMS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */ +#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Err */ #define IXGBE_EIMS_DHER IXGBE_EICR_DHER /* Descr Handler Error */ #define IXGBE_EIMS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ #define IXGBE_EIMS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ @@ -575,18 +609,20 @@ #define IXGBE_EIMC_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ #define IXGBE_EIMC_LSC IXGBE_EICR_LSC /* Link Status Change */ #define IXGBE_EIMC_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ -#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ -#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Error */ +#define IXGBE_EIMC_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */ +#define IXGBE_EIMC_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */ +#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Err */ +#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Err */ #define IXGBE_EIMC_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ #define IXGBE_EIMC_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ -#define IXGBE_EIMS_ENABLE_MASK (\ - IXGBE_EIMS_RTX_QUEUE | \ - IXGBE_EIMS_LSC | \ - IXGBE_EIMS_TCP_TIMER | \ - IXGBE_EIMS_OTHER) +#define IXGBE_EIMS_ENABLE_MASK ( \ + IXGBE_EIMS_RTX_QUEUE | \ + IXGBE_EIMS_LSC | \ + IXGBE_EIMS_TCP_TIMER | \ + IXGBE_EIMS_OTHER) -/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */ +/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */ #define IXGBE_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */ #define IXGBE_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */ #define IXGBE_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */ @@ -623,6 +659,7 @@ #define IXGBE_VLNCTRL_VFE 0x40000000 /* bit 30 */ #define IXGBE_VLNCTRL_VME 0x80000000 /* bit 31 */ + #define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.1q protocol */ /* STATUS Bit Masks */ @@ -670,16 +707,16 @@ #define IXGBE_AUTOC_AN_RESTART 0x00001000 #define IXGBE_AUTOC_FLU 0x00000001 #define IXGBE_AUTOC_LMS_SHIFT 13 -#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT) -#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN (0x0 << IXGBE_AUTOC_LMS_SHIFT) -#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT) -#define IXGBE_AUTOC_LMS_1G_AN (0x2 << IXGBE_AUTOC_LMS_SHIFT) -#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT) -#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT) -#define IXGBE_AUTOC_LMS_ATTACH_TYPE (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) - -#define IXGBE_AUTOC_1G_PMA_PMD 0x00000200 -#define IXGBE_AUTOC_10G_PMA_PMD 0x00000180 +#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN (0x0 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_1G_AN (0x2 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_ATTACH_TYPE (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) + +#define IXGBE_AUTOC_1G_PMA_PMD 0x00000200 +#define IXGBE_AUTOC_10G_PMA_PMD 0x00000180 #define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7 #define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9 #define IXGBE_AUTOC_10G_XAUI (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) @@ -705,6 +742,7 @@ #define IXGBE_LINKS_TL_FAULT 0x00001000 #define IXGBE_LINKS_SIGNAL 0x00000F00 +#define IXGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ #define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ /* SW Semaphore Register bitmasks */ @@ -759,6 +797,11 @@ #define IXGBE_PBANUM0_PTR 0x15 #define IXGBE_PBANUM1_PTR 0x16 +/* Legacy EEPROM word offsets */ +#define IXGBE_ISCSI_BOOT_CAPS 0x0033 +#define IXGBE_ISCSI_SETUP_PORT_0 0x0030 +#define IXGBE_ISCSI_SETUP_PORT_1 0x0034 + /* EEPROM Commands - SPI */ #define IXGBE_EEPROM_MAX_RETRY_SPI 5000 /* Max wait 5ms for RDY signal */ #define IXGBE_EEPROM_STATUS_RDY_SPI 0x01 @@ -766,7 +809,7 @@ #define IXGBE_EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */ #define IXGBE_EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = addr bit-8 */ #define IXGBE_EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Ena latch */ -/* EEPROM reset Write Enbale latch */ +/* EEPROM reset Write Enable latch */ #define IXGBE_EEPROM_WRDI_OPCODE_SPI 0x04 #define IXGBE_EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status reg */ #define IXGBE_EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status reg */ @@ -805,26 +848,20 @@ /* Number of 100 microseconds we wait for PCI Express master disable */ #define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800 -/* PHY Types */ -#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 - /* Check whether address is multicast. This is little-endian specific check.*/ #define IXGBE_IS_MULTICAST(Address) \ - (bool)(((u8 *)(Address))[0] & ((u8)0x01)) + (bool)(((u8 *)(Address))[0] & ((u8)0x01)) /* Check whether an address is broadcast. */ #define IXGBE_IS_BROADCAST(Address) \ - ((((u8 *)(Address))[0] == ((u8)0xff)) && \ - (((u8 *)(Address))[1] == ((u8)0xff))) + ((((u8 *)(Address))[0] == ((u8)0xff)) && \ + (((u8 *)(Address))[1] == ((u8)0xff))) /* RAH */ #define IXGBE_RAH_VIND_MASK 0x003C0000 #define IXGBE_RAH_VIND_SHIFT 18 #define IXGBE_RAH_AV 0x80000000 - -/* Filters */ -#define IXGBE_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ -#define IXGBE_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ +#define IXGBE_CLEAR_VMDQ_ALL 0xFFFFFFFF /* Header split receive */ #define IXGBE_RFCTL_ISCSI_DIS 0x00000001 @@ -853,7 +890,7 @@ #define IXGBE_MAX_FRAME_SZ 0x40040000 #define IXGBE_TDWBAL_HEAD_WB_ENABLE 0x1 /* Tx head write-back enable */ -#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2 /* Tx seq. # write-back enable */ +#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2 /* Tx seq# write-back enable */ /* Receive Config masks */ #define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */ @@ -866,7 +903,7 @@ #define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */ #define IXGBE_FCTRL_PMCF 0x00001000 /* Pass MAC Control Frames */ #define IXGBE_FCTRL_DPF 0x00002000 /* Discard Pause Frame */ -/* Receive Priority Flow Control Enbale */ +/* Receive Priority Flow Control Enable */ #define IXGBE_FCTRL_RPFCE 0x00004000 #define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */ @@ -896,9 +933,8 @@ /* Receive Descriptor bit definitions */ #define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */ #define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */ -#define IXGBE_RXD_STAT_IXSM 0x04 /* Ignore checksum */ #define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ -#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ +#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ #define IXGBE_RXD_STAT_L4CS 0x20 /* L4 xsum calculated */ #define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ #define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */ @@ -914,7 +950,7 @@ #define IXGBE_RXD_ERR_USE 0x20 /* Undersize Error */ #define IXGBE_RXD_ERR_TCPE 0x40 /* TCP/UDP Checksum Error */ #define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ -#define IXGBE_RXDADV_HBO 0x00800000 +#define IXGBE_RXDADV_ERR_HBO 0x00800000 /*Header Buffer Overflow */ #define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */ #define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */ #define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */ @@ -928,15 +964,17 @@ #define IXGBE_RXD_CFI_MASK 0x1000 /* CFI is bit 12 */ #define IXGBE_RXD_CFI_SHIFT 12 + /* SRRCTL bit definitions */ -#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ -#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F -#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00 -#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000 +#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ +#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F +#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00 +#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000 #define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 #define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000 #define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000 #define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000 +#define IXGBE_SRRCTL_DESCTYPE_MASK 0x0E000000 #define IXGBE_RXDPS_HDRSTAT_HDRSP 0x00008000 #define IXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF @@ -970,21 +1008,20 @@ #define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */ #define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */ #define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */ - /* Masks to determine if packets should be dropped due to frame errors */ -#define IXGBE_RXD_ERR_FRAME_ERR_MASK (\ - IXGBE_RXD_ERR_CE | \ - IXGBE_RXD_ERR_LE | \ - IXGBE_RXD_ERR_PE | \ - IXGBE_RXD_ERR_OSE | \ - IXGBE_RXD_ERR_USE) - -#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK (\ - IXGBE_RXDADV_ERR_CE | \ - IXGBE_RXDADV_ERR_LE | \ - IXGBE_RXDADV_ERR_PE | \ - IXGBE_RXDADV_ERR_OSE | \ - IXGBE_RXDADV_ERR_USE) +#define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \ + IXGBE_RXD_ERR_CE | \ + IXGBE_RXD_ERR_LE | \ + IXGBE_RXD_ERR_PE | \ + IXGBE_RXD_ERR_OSE | \ + IXGBE_RXD_ERR_USE) + +#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK ( \ + IXGBE_RXDADV_ERR_CE | \ + IXGBE_RXDADV_ERR_LE | \ + IXGBE_RXDADV_ERR_PE | \ + IXGBE_RXDADV_ERR_OSE | \ + IXGBE_RXDADV_ERR_USE) /* Multicast bit mask */ #define IXGBE_MCSTCTRL_MFE 0x4 @@ -1000,6 +1037,7 @@ #define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */ #define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT IXGBE_RX_DESC_SPECIAL_PRI_SHIFT + /* Transmit Descriptor - Legacy */ struct ixgbe_legacy_tx_desc { u64 buffer_addr; /* Address of the descriptor's data buffer */ @@ -1007,15 +1045,15 @@ struct ixgbe_legacy_tx_desc { __le32 data; struct { __le16 length; /* Data buffer length */ - u8 cso; /* Checksum offset */ - u8 cmd; /* Descriptor control */ + u8 cso; /* Checksum offset */ + u8 cmd; /* Descriptor control */ } flags; } lower; union { __le32 data; struct { - u8 status; /* Descriptor status */ - u8 css; /* Checksum start */ + u8 status; /* Descriptor status */ + u8 css; /* Checksum start */ __le16 vlan; } fields; } upper; @@ -1024,7 +1062,7 @@ struct ixgbe_legacy_tx_desc { /* Transmit Descriptor - Advanced */ union ixgbe_adv_tx_desc { struct { - __le64 buffer_addr; /* Address of descriptor's data buf */ + __le64 buffer_addr; /* Address of descriptor's data buf */ __le32 cmd_type_len; __le32 olinfo_status; } read; @@ -1039,9 +1077,9 @@ union ixgbe_adv_tx_desc { struct ixgbe_legacy_rx_desc { __le64 buffer_addr; /* Address of the descriptor's data buffer */ __le16 length; /* Length of data DMAed into data buffer */ - u16 csum; /* Packet checksum */ - u8 status; /* Descriptor status */ - u8 errors; /* Descriptor Errors */ + __le16 csum; /* Packet checksum */ + u8 status; /* Descriptor status */ + u8 errors; /* Descriptor Errors */ __le16 vlan; }; @@ -1053,15 +1091,18 @@ union ixgbe_adv_rx_desc { } read; struct { struct { - struct { - __le16 pkt_info; /* RSS type, Packet type */ - __le16 hdr_info; /* Split Header, header len */ + union { + __le32 data; + struct { + __le16 pkt_info; /* RSS, Pkt type */ + __le16 hdr_info; /* Splithdr, hdrlen */ + } hs_rss; } lo_dword; union { __le32 rss; /* RSS Hash */ struct { __le16 ip_id; /* IP id */ - u16 csum; /* Packet Checksum */ + __le16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; @@ -1082,49 +1123,69 @@ struct ixgbe_adv_tx_context_desc { }; /* Adv Transmit Descriptor Config Masks */ -#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buffer length(bytes) */ +#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buf length(bytes) */ #define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */ #define IXGBE_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Desc */ #define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ #define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */ #define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */ -#define IXGBE_ADVTXD_DCMD_RDMA 0x04000000 /* RDMA */ #define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */ -#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */ +#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */ #define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */ #define IXGBE_ADVTXD_DCMD_VLE IXGBE_TXD_CMD_VLE /* VLAN pkt enable */ #define IXGBE_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ #define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */ -#define IXGBE_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */ +#define IXGBE_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED pres in WB */ #define IXGBE_ADVTXD_STAT_RSV 0x0000000C /* STA Reserved */ #define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */ +#define IXGBE_ADVTXD_CC 0x00000080 /* Check Context */ #define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */ #define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \ - IXGBE_ADVTXD_POPTS_SHIFT) + IXGBE_ADVTXD_POPTS_SHIFT) #define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \ - IXGBE_ADVTXD_POPTS_SHIFT) -#define IXGBE_ADVTXD_POPTS_EOM 0x00000400 /* Enable L bit-RDMA DDP hdr */ -#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */ -#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */ -#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */ -#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/ -#define IXGBE_ADVTXD_POPTS_RSV 0x00002000 /* POPTS Reserved */ -#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ -#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ -#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */ -#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ -#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */ -#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ -#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ -#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */ -#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ -#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ - + IXGBE_ADVTXD_POPTS_SHIFT) +#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_RSV 0x00002000 /* POPTS Reserved */ +#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ +#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ +#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */ +#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ +#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */ +#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ +#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ +#define IXGBE_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */ +#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /*Req requires Markers and CRC*/ +#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ +#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ + +/* Autonegotiation advertised speeds */ +typedef u32 ixgbe_autoneg_advertised; /* Link speed */ +typedef u32 ixgbe_link_speed; #define IXGBE_LINK_SPEED_UNKNOWN 0 #define IXGBE_LINK_SPEED_100_FULL 0x0008 #define IXGBE_LINK_SPEED_1GB_FULL 0x0020 #define IXGBE_LINK_SPEED_10GB_FULL 0x0080 +#define IXGBE_LINK_SPEED_82598_AUTONEG (IXGBE_LINK_SPEED_1GB_FULL | \ + IXGBE_LINK_SPEED_10GB_FULL) + +/* Physical layer type */ +typedef u32 ixgbe_physical_layer; +#define IXGBE_PHYSICAL_LAYER_UNKNOWN 0 +#define IXGBE_PHYSICAL_LAYER_10GBASE_T 0x0001 +#define IXGBE_PHYSICAL_LAYER_1000BASE_T 0x0002 +#define IXGBE_PHYSICAL_LAYER_100BASE_T 0x0004 +#define IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU 0x0008 +#define IXGBE_PHYSICAL_LAYER_10GBASE_LR 0x0010 +#define IXGBE_PHYSICAL_LAYER_10GBASE_LRM 0x0020 +#define IXGBE_PHYSICAL_LAYER_10GBASE_SR 0x0040 +#define IXGBE_PHYSICAL_LAYER_10GBASE_KX4 0x0080 +#define IXGBE_PHYSICAL_LAYER_10GBASE_CX4 0x0100 +#define IXGBE_PHYSICAL_LAYER_1000BASE_KX 0x0200 +#define IXGBE_PHYSICAL_LAYER_1000BASE_BX 0x0400 enum ixgbe_eeprom_type { @@ -1141,16 +1202,38 @@ enum ixgbe_mac_type { enum ixgbe_phy_type { ixgbe_phy_unknown = 0, - ixgbe_phy_tn, ixgbe_phy_qt, - ixgbe_phy_xaui + ixgbe_phy_xaui, + ixgbe_phy_tw_tyco, + ixgbe_phy_tw_unknown, + ixgbe_phy_sfp_avago, + ixgbe_phy_sfp_ftl, + ixgbe_phy_sfp_unknown, + ixgbe_phy_generic +}; + +/* + * SFP+ module type IDs: + * + * ID Module Type + * ============= + * 0 SFP_DA_CU + * 1 SFP_SR + * 2 SFP_LR + */ +enum ixgbe_sfp_type { + ixgbe_sfp_type_da_cu = 0, + ixgbe_sfp_type_sr = 1, + ixgbe_sfp_type_lr = 2, + ixgbe_sfp_type_unknown = 0xFFFF }; enum ixgbe_media_type { ixgbe_media_type_unknown = 0, ixgbe_media_type_fiber, ixgbe_media_type_copper, - ixgbe_media_type_backplane + ixgbe_media_type_backplane, + ixgbe_media_type_virtual }; /* Flow Control Settings */ @@ -1167,6 +1250,8 @@ struct ixgbe_addr_filter_info { u32 rar_used_count; u32 mc_addr_in_rar_count; u32 mta_in_use; + u32 overflow_promisc; + bool user_set_promisc; }; /* Flow control parameters */ @@ -1242,57 +1327,118 @@ struct ixgbe_hw_stats { /* forward declaration */ struct ixgbe_hw; +/* iterator type for walking multicast address lists */ +typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr, + u32 *vmdq); + +/* Function pointer table */ +struct ixgbe_eeprom_operations { + s32 (*init_params)(struct ixgbe_hw *); + s32 (*read)(struct ixgbe_hw *, u16, u16 *); + s32 (*write)(struct ixgbe_hw *, u16, u16); + s32 (*validate_checksum)(struct ixgbe_hw *, u16 *); + s32 (*update_checksum)(struct ixgbe_hw *); +}; + struct ixgbe_mac_operations { - s32 (*reset)(struct ixgbe_hw *); + s32 (*init_hw)(struct ixgbe_hw *); + s32 (*reset_hw)(struct ixgbe_hw *); + s32 (*start_hw)(struct ixgbe_hw *); + s32 (*clear_hw_cntrs)(struct ixgbe_hw *); enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); + s32 (*get_supported_physical_layer)(struct ixgbe_hw *); + s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); + s32 (*stop_adapter)(struct ixgbe_hw *); + s32 (*get_bus_info)(struct ixgbe_hw *); + s32 (*read_analog_reg8)(struct ixgbe_hw*, u32, u8*); + s32 (*write_analog_reg8)(struct ixgbe_hw*, u32, u8); + + /* Link */ s32 (*setup_link)(struct ixgbe_hw *); - s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *); - s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool); - s32 (*get_link_settings)(struct ixgbe_hw *, u32 *, bool *); + s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, + bool); + s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); + s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, + bool *); + + /* LED */ + s32 (*led_on)(struct ixgbe_hw *, u32); + s32 (*led_off)(struct ixgbe_hw *, u32); + s32 (*blink_led_start)(struct ixgbe_hw *, u32); + s32 (*blink_led_stop)(struct ixgbe_hw *, u32); + + /* RAR, Multicast, VLAN */ + s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32, u32); + s32 (*clear_rar)(struct ixgbe_hw *, u32); + s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32); + s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32); + s32 (*init_rx_addrs)(struct ixgbe_hw *); + s32 (*update_uc_addr_list)(struct ixgbe_hw *, u8 *, u32, + ixgbe_mc_addr_itr); + s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32, + ixgbe_mc_addr_itr); + s32 (*enable_mc)(struct ixgbe_hw *); + s32 (*disable_mc)(struct ixgbe_hw *); + s32 (*clear_vfta)(struct ixgbe_hw *); + s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool); + s32 (*init_uta_tables)(struct ixgbe_hw *); + + /* Flow Control */ + s32 (*setup_fc)(struct ixgbe_hw *, s32); }; struct ixgbe_phy_operations { + s32 (*identify)(struct ixgbe_hw *); + s32 (*identify_sfp)(struct ixgbe_hw *); + s32 (*reset)(struct ixgbe_hw *); + s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *); + s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16); s32 (*setup_link)(struct ixgbe_hw *); - s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *); - s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool); -}; - -struct ixgbe_mac_info { - struct ixgbe_mac_operations ops; - enum ixgbe_mac_type type; - u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; - u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; - s32 mc_filter_type; - u32 num_rx_queues; - u32 num_tx_queues; - u32 num_rx_addrs; - u32 link_attach_type; - u32 link_mode_select; - bool link_settings_loaded; + s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, + bool); + s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *); + s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8); + s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *); + s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8); }; struct ixgbe_eeprom_info { - enum ixgbe_eeprom_type type; - u16 word_size; - u16 address_bits; + struct ixgbe_eeprom_operations ops; + enum ixgbe_eeprom_type type; + u32 semaphore_delay; + u16 word_size; + u16 address_bits; }; -struct ixgbe_phy_info { - struct ixgbe_phy_operations ops; - - enum ixgbe_phy_type type; - u32 addr; - u32 id; - u32 revision; - enum ixgbe_media_type media_type; - u32 autoneg_advertised; - bool autoneg_wait_to_complete; +struct ixgbe_mac_info { + struct ixgbe_mac_operations ops; + enum ixgbe_mac_type type; + u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + s32 mc_filter_type; + u32 mcft_size; + u32 vft_size; + u32 num_rar_entries; + u32 max_tx_queues; + u32 max_rx_queues; + u32 link_attach_type; + u32 link_mode_select; + bool link_settings_loaded; + bool autoneg; + bool autoneg_failed; }; -struct ixgbe_info { - enum ixgbe_mac_type mac; - s32 (*get_invariants)(struct ixgbe_hw *); - struct ixgbe_mac_operations *mac_ops; +struct ixgbe_phy_info { + struct ixgbe_phy_operations ops; + enum ixgbe_phy_type type; + u32 addr; + u32 id; + enum ixgbe_sfp_type sfp_type; + u32 revision; + enum ixgbe_media_type media_type; + bool reset_disable; + ixgbe_autoneg_advertised autoneg_advertised; + bool autoneg_wait_to_complete; }; struct ixgbe_hw { @@ -1311,6 +1457,15 @@ struct ixgbe_hw { bool adapter_stopped; }; +struct ixgbe_info { + enum ixgbe_mac_type mac; + s32 (*get_invariants)(struct ixgbe_hw *); + struct ixgbe_mac_operations *mac_ops; + struct ixgbe_eeprom_operations *eeprom_ops; + struct ixgbe_phy_operations *phy_ops; +}; + + /* Error Codes */ #define IXGBE_ERR_EEPROM -1 #define IXGBE_ERR_EEPROM_CHECKSUM -2 @@ -1329,6 +1484,8 @@ struct ixgbe_hw { #define IXGBE_ERR_RESET_FAILED -15 #define IXGBE_ERR_SWFW_SYNC -16 #define IXGBE_ERR_PHY_ADDR_INVALID -17 +#define IXGBE_ERR_I2C -18 +#define IXGBE_ERR_SFP_NOT_SUPPORTED -19 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #endif /* _IXGBE_TYPE_H_ */ diff --git a/drivers/net/jme.c b/drivers/net/jme.c new file mode 100644 index 00000000000..81c6cdc3851 --- /dev/null +++ b/drivers/net/jme.c @@ -0,0 +1,3038 @@ +/* + * JMicron JMC2x0 series PCIe Ethernet Linux Device Driver + * + * Copyright 2008 JMicron Technology Corporation + * http://www.jmicron.com/ + * + * Author: Guo-Fu Tseng <cooldavid@cooldavid.org> + * + * 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. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/crc32.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/if_vlan.h> +#include <net/ip6_checksum.h> +#include "jme.h" + +static int force_pseudohp = -1; +static int no_pseudohp = -1; +static int no_extplug = -1; +module_param(force_pseudohp, int, 0); +MODULE_PARM_DESC(force_pseudohp, + "Enable pseudo hot-plug feature manually by driver instead of BIOS."); +module_param(no_pseudohp, int, 0); +MODULE_PARM_DESC(no_pseudohp, "Disable pseudo hot-plug feature."); +module_param(no_extplug, int, 0); +MODULE_PARM_DESC(no_extplug, + "Do not use external plug signal for pseudo hot-plug."); + +static int +jme_mdio_read(struct net_device *netdev, int phy, int reg) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int i, val, again = (reg == MII_BMSR) ? 1 : 0; + +read_again: + jwrite32(jme, JME_SMI, SMI_OP_REQ | + smi_phy_addr(phy) | + smi_reg_addr(reg)); + + wmb(); + for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) { + udelay(20); + val = jread32(jme, JME_SMI); + if ((val & SMI_OP_REQ) == 0) + break; + } + + if (i == 0) { + jeprintk(jme->pdev, "phy(%d) read timeout : %d\n", phy, reg); + return 0; + } + + if (again--) + goto read_again; + + return (val & SMI_DATA_MASK) >> SMI_DATA_SHIFT; +} + +static void +jme_mdio_write(struct net_device *netdev, + int phy, int reg, int val) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int i; + + jwrite32(jme, JME_SMI, SMI_OP_WRITE | SMI_OP_REQ | + ((val << SMI_DATA_SHIFT) & SMI_DATA_MASK) | + smi_phy_addr(phy) | smi_reg_addr(reg)); + + wmb(); + for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) { + udelay(20); + if ((jread32(jme, JME_SMI) & SMI_OP_REQ) == 0) + break; + } + + if (i == 0) + jeprintk(jme->pdev, "phy(%d) write timeout : %d\n", phy, reg); + + return; +} + +static inline void +jme_reset_phy_processor(struct jme_adapter *jme) +{ + u32 val; + + jme_mdio_write(jme->dev, + jme->mii_if.phy_id, + MII_ADVERTISE, ADVERTISE_ALL | + ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + + if (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) + jme_mdio_write(jme->dev, + jme->mii_if.phy_id, + MII_CTRL1000, + ADVERTISE_1000FULL | ADVERTISE_1000HALF); + + val = jme_mdio_read(jme->dev, + jme->mii_if.phy_id, + MII_BMCR); + + jme_mdio_write(jme->dev, + jme->mii_if.phy_id, + MII_BMCR, val | BMCR_RESET); + + return; +} + +static void +jme_setup_wakeup_frame(struct jme_adapter *jme, + u32 *mask, u32 crc, int fnr) +{ + int i; + + /* + * Setup CRC pattern + */ + jwrite32(jme, JME_WFOI, WFOI_CRC_SEL | (fnr & WFOI_FRAME_SEL)); + wmb(); + jwrite32(jme, JME_WFODP, crc); + wmb(); + + /* + * Setup Mask + */ + for (i = 0 ; i < WAKEUP_FRAME_MASK_DWNR ; ++i) { + jwrite32(jme, JME_WFOI, + ((i << WFOI_MASK_SHIFT) & WFOI_MASK_SEL) | + (fnr & WFOI_FRAME_SEL)); + wmb(); + jwrite32(jme, JME_WFODP, mask[i]); + wmb(); + } +} + +static inline void +jme_reset_mac_processor(struct jme_adapter *jme) +{ + u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0}; + u32 crc = 0xCDCDCDCD; + u32 gpreg0; + int i; + + jwrite32(jme, JME_GHC, jme->reg_ghc | GHC_SWRST); + udelay(2); + jwrite32(jme, JME_GHC, jme->reg_ghc); + + jwrite32(jme, JME_RXDBA_LO, 0x00000000); + jwrite32(jme, JME_RXDBA_HI, 0x00000000); + jwrite32(jme, JME_RXQDC, 0x00000000); + jwrite32(jme, JME_RXNDA, 0x00000000); + jwrite32(jme, JME_TXDBA_LO, 0x00000000); + jwrite32(jme, JME_TXDBA_HI, 0x00000000); + jwrite32(jme, JME_TXQDC, 0x00000000); + jwrite32(jme, JME_TXNDA, 0x00000000); + + jwrite32(jme, JME_RXMCHT_LO, 0x00000000); + jwrite32(jme, JME_RXMCHT_HI, 0x00000000); + for (i = 0 ; i < WAKEUP_FRAME_NR ; ++i) + jme_setup_wakeup_frame(jme, mask, crc, i); + if (jme->fpgaver) + gpreg0 = GPREG0_DEFAULT | GPREG0_LNKINTPOLL; + else + gpreg0 = GPREG0_DEFAULT; + jwrite32(jme, JME_GPREG0, gpreg0); + jwrite32(jme, JME_GPREG1, GPREG1_DEFAULT); +} + +static inline void +jme_reset_ghc_speed(struct jme_adapter *jme) +{ + jme->reg_ghc &= ~(GHC_SPEED_1000M | GHC_DPX); + jwrite32(jme, JME_GHC, jme->reg_ghc); +} + +static inline void +jme_clear_pm(struct jme_adapter *jme) +{ + jwrite32(jme, JME_PMCS, 0xFFFF0000 | jme->reg_pmcs); + pci_set_power_state(jme->pdev, PCI_D0); + pci_enable_wake(jme->pdev, PCI_D0, false); +} + +static int +jme_reload_eeprom(struct jme_adapter *jme) +{ + u32 val; + int i; + + val = jread32(jme, JME_SMBCSR); + + if (val & SMBCSR_EEPROMD) { + val |= SMBCSR_CNACK; + jwrite32(jme, JME_SMBCSR, val); + val |= SMBCSR_RELOAD; + jwrite32(jme, JME_SMBCSR, val); + mdelay(12); + + for (i = JME_EEPROM_RELOAD_TIMEOUT; i > 0; --i) { + mdelay(1); + if ((jread32(jme, JME_SMBCSR) & SMBCSR_RELOAD) == 0) + break; + } + + if (i == 0) { + jeprintk(jme->pdev, "eeprom reload timeout\n"); + return -EIO; + } + } + + return 0; +} + +static void +jme_load_macaddr(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + unsigned char macaddr[6]; + u32 val; + + spin_lock_bh(&jme->macaddr_lock); + val = jread32(jme, JME_RXUMA_LO); + macaddr[0] = (val >> 0) & 0xFF; + macaddr[1] = (val >> 8) & 0xFF; + macaddr[2] = (val >> 16) & 0xFF; + macaddr[3] = (val >> 24) & 0xFF; + val = jread32(jme, JME_RXUMA_HI); + macaddr[4] = (val >> 0) & 0xFF; + macaddr[5] = (val >> 8) & 0xFF; + memcpy(netdev->dev_addr, macaddr, 6); + spin_unlock_bh(&jme->macaddr_lock); +} + +static inline void +jme_set_rx_pcc(struct jme_adapter *jme, int p) +{ + switch (p) { + case PCC_OFF: + jwrite32(jme, JME_PCCRX0, + ((PCC_OFF_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | + ((PCC_OFF_CNT << PCCRX_SHIFT) & PCCRX_MASK)); + break; + case PCC_P1: + jwrite32(jme, JME_PCCRX0, + ((PCC_P1_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | + ((PCC_P1_CNT << PCCRX_SHIFT) & PCCRX_MASK)); + break; + case PCC_P2: + jwrite32(jme, JME_PCCRX0, + ((PCC_P2_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | + ((PCC_P2_CNT << PCCRX_SHIFT) & PCCRX_MASK)); + break; + case PCC_P3: + jwrite32(jme, JME_PCCRX0, + ((PCC_P3_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | + ((PCC_P3_CNT << PCCRX_SHIFT) & PCCRX_MASK)); + break; + default: + break; + } + wmb(); + + if (!(test_bit(JME_FLAG_POLL, &jme->flags))) + msg_rx_status(jme, "Switched to PCC_P%d\n", p); +} + +static void +jme_start_irq(struct jme_adapter *jme) +{ + register struct dynpcc_info *dpi = &(jme->dpi); + + jme_set_rx_pcc(jme, PCC_P1); + dpi->cur = PCC_P1; + dpi->attempt = PCC_P1; + dpi->cnt = 0; + + jwrite32(jme, JME_PCCTX, + ((PCC_TX_TO << PCCTXTO_SHIFT) & PCCTXTO_MASK) | + ((PCC_TX_CNT << PCCTX_SHIFT) & PCCTX_MASK) | + PCCTXQ0_EN + ); + + /* + * Enable Interrupts + */ + jwrite32(jme, JME_IENS, INTR_ENABLE); +} + +static inline void +jme_stop_irq(struct jme_adapter *jme) +{ + /* + * Disable Interrupts + */ + jwrite32f(jme, JME_IENC, INTR_ENABLE); +} + +static inline void +jme_enable_shadow(struct jme_adapter *jme) +{ + jwrite32(jme, + JME_SHBA_LO, + ((u32)jme->shadow_dma & ~((u32)0x1F)) | SHBA_POSTEN); +} + +static inline void +jme_disable_shadow(struct jme_adapter *jme) +{ + jwrite32(jme, JME_SHBA_LO, 0x0); +} + +static u32 +jme_linkstat_from_phy(struct jme_adapter *jme) +{ + u32 phylink, bmsr; + + phylink = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 17); + bmsr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMSR); + if (bmsr & BMSR_ANCOMP) + phylink |= PHY_LINK_AUTONEG_COMPLETE; + + return phylink; +} + +static inline void +jme_set_phyfifoa(struct jme_adapter *jme) +{ + jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0004); +} + +static inline void +jme_set_phyfifob(struct jme_adapter *jme) +{ + jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0000); +} + +static int +jme_check_link(struct net_device *netdev, int testonly) +{ + struct jme_adapter *jme = netdev_priv(netdev); + u32 phylink, ghc, cnt = JME_SPDRSV_TIMEOUT, bmcr, gpreg1; + char linkmsg[64]; + int rc = 0; + + linkmsg[0] = '\0'; + + if (jme->fpgaver) + phylink = jme_linkstat_from_phy(jme); + else + phylink = jread32(jme, JME_PHY_LINK); + + if (phylink & PHY_LINK_UP) { + if (!(phylink & PHY_LINK_AUTONEG_COMPLETE)) { + /* + * If we did not enable AN + * Speed/Duplex Info should be obtained from SMI + */ + phylink = PHY_LINK_UP; + + bmcr = jme_mdio_read(jme->dev, + jme->mii_if.phy_id, + MII_BMCR); + + phylink |= ((bmcr & BMCR_SPEED1000) && + (bmcr & BMCR_SPEED100) == 0) ? + PHY_LINK_SPEED_1000M : + (bmcr & BMCR_SPEED100) ? + PHY_LINK_SPEED_100M : + PHY_LINK_SPEED_10M; + + phylink |= (bmcr & BMCR_FULLDPLX) ? + PHY_LINK_DUPLEX : 0; + + strcat(linkmsg, "Forced: "); + } else { + /* + * Keep polling for speed/duplex resolve complete + */ + while (!(phylink & PHY_LINK_SPEEDDPU_RESOLVED) && + --cnt) { + + udelay(1); + + if (jme->fpgaver) + phylink = jme_linkstat_from_phy(jme); + else + phylink = jread32(jme, JME_PHY_LINK); + } + if (!cnt) + jeprintk(jme->pdev, + "Waiting speed resolve timeout.\n"); + + strcat(linkmsg, "ANed: "); + } + + if (jme->phylink == phylink) { + rc = 1; + goto out; + } + if (testonly) + goto out; + + jme->phylink = phylink; + + ghc = jme->reg_ghc & ~(GHC_SPEED_10M | + GHC_SPEED_100M | + GHC_SPEED_1000M | + GHC_DPX); + switch (phylink & PHY_LINK_SPEED_MASK) { + case PHY_LINK_SPEED_10M: + ghc |= GHC_SPEED_10M; + strcat(linkmsg, "10 Mbps, "); + break; + case PHY_LINK_SPEED_100M: + ghc |= GHC_SPEED_100M; + strcat(linkmsg, "100 Mbps, "); + break; + case PHY_LINK_SPEED_1000M: + ghc |= GHC_SPEED_1000M; + strcat(linkmsg, "1000 Mbps, "); + break; + default: + break; + } + + if (phylink & PHY_LINK_DUPLEX) { + jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT); + ghc |= GHC_DPX; + } else { + jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT | + TXMCS_BACKOFF | + TXMCS_CARRIERSENSE | + TXMCS_COLLISION); + jwrite32(jme, JME_TXTRHD, TXTRHD_TXPEN | + ((0x2000 << TXTRHD_TXP_SHIFT) & TXTRHD_TXP) | + TXTRHD_TXREN | + ((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL)); + } + strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ? + "Full-Duplex, " : + "Half-Duplex, "); + + if (phylink & PHY_LINK_MDI_STAT) + strcat(linkmsg, "MDI-X"); + else + strcat(linkmsg, "MDI"); + + gpreg1 = GPREG1_DEFAULT; + if (is_buggy250(jme->pdev->device, jme->chiprev)) { + if (!(phylink & PHY_LINK_DUPLEX)) + gpreg1 |= GPREG1_HALFMODEPATCH; + switch (phylink & PHY_LINK_SPEED_MASK) { + case PHY_LINK_SPEED_10M: + jme_set_phyfifoa(jme); + gpreg1 |= GPREG1_RSSPATCH; + break; + case PHY_LINK_SPEED_100M: + jme_set_phyfifob(jme); + gpreg1 |= GPREG1_RSSPATCH; + break; + case PHY_LINK_SPEED_1000M: + jme_set_phyfifoa(jme); + break; + default: + break; + } + } + jwrite32(jme, JME_GPREG1, gpreg1); + + jme->reg_ghc = ghc; + jwrite32(jme, JME_GHC, ghc); + + msg_link(jme, "Link is up at %s.\n", linkmsg); + netif_carrier_on(netdev); + } else { + if (testonly) + goto out; + + msg_link(jme, "Link is down.\n"); + jme->phylink = 0; + netif_carrier_off(netdev); + } + +out: + return rc; +} + +static int +jme_setup_tx_resources(struct jme_adapter *jme) +{ + struct jme_ring *txring = &(jme->txring[0]); + + txring->alloc = dma_alloc_coherent(&(jme->pdev->dev), + TX_RING_ALLOC_SIZE(jme->tx_ring_size), + &(txring->dmaalloc), + GFP_ATOMIC); + + if (!txring->alloc) { + txring->desc = NULL; + txring->dmaalloc = 0; + txring->dma = 0; + return -ENOMEM; + } + + /* + * 16 Bytes align + */ + txring->desc = (void *)ALIGN((unsigned long)(txring->alloc), + RING_DESC_ALIGN); + txring->dma = ALIGN(txring->dmaalloc, RING_DESC_ALIGN); + txring->next_to_use = 0; + atomic_set(&txring->next_to_clean, 0); + atomic_set(&txring->nr_free, jme->tx_ring_size); + + /* + * Initialize Transmit Descriptors + */ + memset(txring->alloc, 0, TX_RING_ALLOC_SIZE(jme->tx_ring_size)); + memset(txring->bufinf, 0, + sizeof(struct jme_buffer_info) * jme->tx_ring_size); + + return 0; +} + +static void +jme_free_tx_resources(struct jme_adapter *jme) +{ + int i; + struct jme_ring *txring = &(jme->txring[0]); + struct jme_buffer_info *txbi = txring->bufinf; + + if (txring->alloc) { + for (i = 0 ; i < jme->tx_ring_size ; ++i) { + txbi = txring->bufinf + i; + if (txbi->skb) { + dev_kfree_skb(txbi->skb); + txbi->skb = NULL; + } + txbi->mapping = 0; + txbi->len = 0; + txbi->nr_desc = 0; + txbi->start_xmit = 0; + } + + dma_free_coherent(&(jme->pdev->dev), + TX_RING_ALLOC_SIZE(jme->tx_ring_size), + txring->alloc, + txring->dmaalloc); + + txring->alloc = NULL; + txring->desc = NULL; + txring->dmaalloc = 0; + txring->dma = 0; + } + txring->next_to_use = 0; + atomic_set(&txring->next_to_clean, 0); + atomic_set(&txring->nr_free, 0); + +} + +static inline void +jme_enable_tx_engine(struct jme_adapter *jme) +{ + /* + * Select Queue 0 + */ + jwrite32(jme, JME_TXCS, TXCS_DEFAULT | TXCS_SELECT_QUEUE0); + wmb(); + + /* + * Setup TX Queue 0 DMA Bass Address + */ + jwrite32(jme, JME_TXDBA_LO, (__u64)jme->txring[0].dma & 0xFFFFFFFFUL); + jwrite32(jme, JME_TXDBA_HI, (__u64)(jme->txring[0].dma) >> 32); + jwrite32(jme, JME_TXNDA, (__u64)jme->txring[0].dma & 0xFFFFFFFFUL); + + /* + * Setup TX Descptor Count + */ + jwrite32(jme, JME_TXQDC, jme->tx_ring_size); + + /* + * Enable TX Engine + */ + wmb(); + jwrite32(jme, JME_TXCS, jme->reg_txcs | + TXCS_SELECT_QUEUE0 | + TXCS_ENABLE); + +} + +static inline void +jme_restart_tx_engine(struct jme_adapter *jme) +{ + /* + * Restart TX Engine + */ + jwrite32(jme, JME_TXCS, jme->reg_txcs | + TXCS_SELECT_QUEUE0 | + TXCS_ENABLE); +} + +static inline void +jme_disable_tx_engine(struct jme_adapter *jme) +{ + int i; + u32 val; + + /* + * Disable TX Engine + */ + jwrite32(jme, JME_TXCS, jme->reg_txcs | TXCS_SELECT_QUEUE0); + wmb(); + + val = jread32(jme, JME_TXCS); + for (i = JME_TX_DISABLE_TIMEOUT ; (val & TXCS_ENABLE) && i > 0 ; --i) { + mdelay(1); + val = jread32(jme, JME_TXCS); + rmb(); + } + + if (!i) + jeprintk(jme->pdev, "Disable TX engine timeout.\n"); +} + +static void +jme_set_clean_rxdesc(struct jme_adapter *jme, int i) +{ + struct jme_ring *rxring = jme->rxring; + register struct rxdesc *rxdesc = rxring->desc; + struct jme_buffer_info *rxbi = rxring->bufinf; + rxdesc += i; + rxbi += i; + + rxdesc->dw[0] = 0; + rxdesc->dw[1] = 0; + rxdesc->desc1.bufaddrh = cpu_to_le32((__u64)rxbi->mapping >> 32); + rxdesc->desc1.bufaddrl = cpu_to_le32( + (__u64)rxbi->mapping & 0xFFFFFFFFUL); + rxdesc->desc1.datalen = cpu_to_le16(rxbi->len); + if (jme->dev->features & NETIF_F_HIGHDMA) + rxdesc->desc1.flags = RXFLAG_64BIT; + wmb(); + rxdesc->desc1.flags |= RXFLAG_OWN | RXFLAG_INT; +} + +static int +jme_make_new_rx_buf(struct jme_adapter *jme, int i) +{ + struct jme_ring *rxring = &(jme->rxring[0]); + struct jme_buffer_info *rxbi = rxring->bufinf + i; + struct sk_buff *skb; + + skb = netdev_alloc_skb(jme->dev, + jme->dev->mtu + RX_EXTRA_LEN); + if (unlikely(!skb)) + return -ENOMEM; + + rxbi->skb = skb; + rxbi->len = skb_tailroom(skb); + rxbi->mapping = pci_map_page(jme->pdev, + virt_to_page(skb->data), + offset_in_page(skb->data), + rxbi->len, + PCI_DMA_FROMDEVICE); + + return 0; +} + +static void +jme_free_rx_buf(struct jme_adapter *jme, int i) +{ + struct jme_ring *rxring = &(jme->rxring[0]); + struct jme_buffer_info *rxbi = rxring->bufinf; + rxbi += i; + + if (rxbi->skb) { + pci_unmap_page(jme->pdev, + rxbi->mapping, + rxbi->len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxbi->skb); + rxbi->skb = NULL; + rxbi->mapping = 0; + rxbi->len = 0; + } +} + +static void +jme_free_rx_resources(struct jme_adapter *jme) +{ + int i; + struct jme_ring *rxring = &(jme->rxring[0]); + + if (rxring->alloc) { + for (i = 0 ; i < jme->rx_ring_size ; ++i) + jme_free_rx_buf(jme, i); + + dma_free_coherent(&(jme->pdev->dev), + RX_RING_ALLOC_SIZE(jme->rx_ring_size), + rxring->alloc, + rxring->dmaalloc); + rxring->alloc = NULL; + rxring->desc = NULL; + rxring->dmaalloc = 0; + rxring->dma = 0; + } + rxring->next_to_use = 0; + atomic_set(&rxring->next_to_clean, 0); +} + +static int +jme_setup_rx_resources(struct jme_adapter *jme) +{ + int i; + struct jme_ring *rxring = &(jme->rxring[0]); + + rxring->alloc = dma_alloc_coherent(&(jme->pdev->dev), + RX_RING_ALLOC_SIZE(jme->rx_ring_size), + &(rxring->dmaalloc), + GFP_ATOMIC); + if (!rxring->alloc) { + rxring->desc = NULL; + rxring->dmaalloc = 0; + rxring->dma = 0; + return -ENOMEM; + } + + /* + * 16 Bytes align + */ + rxring->desc = (void *)ALIGN((unsigned long)(rxring->alloc), + RING_DESC_ALIGN); + rxring->dma = ALIGN(rxring->dmaalloc, RING_DESC_ALIGN); + rxring->next_to_use = 0; + atomic_set(&rxring->next_to_clean, 0); + + /* + * Initiallize Receive Descriptors + */ + for (i = 0 ; i < jme->rx_ring_size ; ++i) { + if (unlikely(jme_make_new_rx_buf(jme, i))) { + jme_free_rx_resources(jme); + return -ENOMEM; + } + + jme_set_clean_rxdesc(jme, i); + } + + return 0; +} + +static inline void +jme_enable_rx_engine(struct jme_adapter *jme) +{ + /* + * Select Queue 0 + */ + jwrite32(jme, JME_RXCS, jme->reg_rxcs | + RXCS_QUEUESEL_Q0); + wmb(); + + /* + * Setup RX DMA Bass Address + */ + jwrite32(jme, JME_RXDBA_LO, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL); + jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32); + jwrite32(jme, JME_RXNDA, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL); + + /* + * Setup RX Descriptor Count + */ + jwrite32(jme, JME_RXQDC, jme->rx_ring_size); + + /* + * Setup Unicast Filter + */ + jme_set_multi(jme->dev); + + /* + * Enable RX Engine + */ + wmb(); + jwrite32(jme, JME_RXCS, jme->reg_rxcs | + RXCS_QUEUESEL_Q0 | + RXCS_ENABLE | + RXCS_QST); +} + +static inline void +jme_restart_rx_engine(struct jme_adapter *jme) +{ + /* + * Start RX Engine + */ + jwrite32(jme, JME_RXCS, jme->reg_rxcs | + RXCS_QUEUESEL_Q0 | + RXCS_ENABLE | + RXCS_QST); +} + +static inline void +jme_disable_rx_engine(struct jme_adapter *jme) +{ + int i; + u32 val; + + /* + * Disable RX Engine + */ + jwrite32(jme, JME_RXCS, jme->reg_rxcs); + wmb(); + + val = jread32(jme, JME_RXCS); + for (i = JME_RX_DISABLE_TIMEOUT ; (val & RXCS_ENABLE) && i > 0 ; --i) { + mdelay(1); + val = jread32(jme, JME_RXCS); + rmb(); + } + + if (!i) + jeprintk(jme->pdev, "Disable RX engine timeout.\n"); + +} + +static int +jme_rxsum_ok(struct jme_adapter *jme, u16 flags) +{ + if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4))) + return false; + + if (unlikely(!(flags & RXWBFLAG_MF) && + (flags & RXWBFLAG_TCPON) && !(flags & RXWBFLAG_TCPCS))) { + msg_rx_err(jme, "TCP Checksum error.\n"); + goto out_sumerr; + } + + if (unlikely(!(flags & RXWBFLAG_MF) && + (flags & RXWBFLAG_UDPON) && !(flags & RXWBFLAG_UDPCS))) { + msg_rx_err(jme, "UDP Checksum error.\n"); + goto out_sumerr; + } + + if (unlikely((flags & RXWBFLAG_IPV4) && !(flags & RXWBFLAG_IPCS))) { + msg_rx_err(jme, "IPv4 Checksum error.\n"); + goto out_sumerr; + } + + return true; + +out_sumerr: + return false; +} + +static void +jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) +{ + struct jme_ring *rxring = &(jme->rxring[0]); + struct rxdesc *rxdesc = rxring->desc; + struct jme_buffer_info *rxbi = rxring->bufinf; + struct sk_buff *skb; + int framesize; + + rxdesc += idx; + rxbi += idx; + + skb = rxbi->skb; + pci_dma_sync_single_for_cpu(jme->pdev, + rxbi->mapping, + rxbi->len, + PCI_DMA_FROMDEVICE); + + if (unlikely(jme_make_new_rx_buf(jme, idx))) { + pci_dma_sync_single_for_device(jme->pdev, + rxbi->mapping, + rxbi->len, + PCI_DMA_FROMDEVICE); + + ++(NET_STAT(jme).rx_dropped); + } else { + framesize = le16_to_cpu(rxdesc->descwb.framesize) + - RX_PREPAD_SIZE; + + skb_reserve(skb, RX_PREPAD_SIZE); + skb_put(skb, framesize); + skb->protocol = eth_type_trans(skb, jme->dev); + + if (jme_rxsum_ok(jme, rxdesc->descwb.flags)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + + if (rxdesc->descwb.flags & RXWBFLAG_TAGON) { + if (jme->vlgrp) { + jme->jme_vlan_rx(skb, jme->vlgrp, + le32_to_cpu(rxdesc->descwb.vlan)); + NET_STAT(jme).rx_bytes += 4; + } + } else { + jme->jme_rx(skb); + } + + if ((le16_to_cpu(rxdesc->descwb.flags) & RXWBFLAG_DEST) == + RXWBFLAG_DEST_MUL) + ++(NET_STAT(jme).multicast); + + jme->dev->last_rx = jiffies; + NET_STAT(jme).rx_bytes += framesize; + ++(NET_STAT(jme).rx_packets); + } + + jme_set_clean_rxdesc(jme, idx); + +} + +static int +jme_process_receive(struct jme_adapter *jme, int limit) +{ + struct jme_ring *rxring = &(jme->rxring[0]); + struct rxdesc *rxdesc = rxring->desc; + int i, j, ccnt, desccnt, mask = jme->rx_ring_mask; + + if (unlikely(!atomic_dec_and_test(&jme->rx_cleaning))) + goto out_inc; + + if (unlikely(atomic_read(&jme->link_changing) != 1)) + goto out_inc; + + if (unlikely(!netif_carrier_ok(jme->dev))) + goto out_inc; + + i = atomic_read(&rxring->next_to_clean); + while (limit-- > 0) { + rxdesc = rxring->desc; + rxdesc += i; + + if ((rxdesc->descwb.flags & RXWBFLAG_OWN) || + !(rxdesc->descwb.desccnt & RXWBDCNT_WBCPL)) + goto out; + + desccnt = rxdesc->descwb.desccnt & RXWBDCNT_DCNT; + + if (unlikely(desccnt > 1 || + rxdesc->descwb.errstat & RXWBERR_ALLERR)) { + + if (rxdesc->descwb.errstat & RXWBERR_CRCERR) + ++(NET_STAT(jme).rx_crc_errors); + else if (rxdesc->descwb.errstat & RXWBERR_OVERUN) + ++(NET_STAT(jme).rx_fifo_errors); + else + ++(NET_STAT(jme).rx_errors); + + if (desccnt > 1) + limit -= desccnt - 1; + + for (j = i, ccnt = desccnt ; ccnt-- ; ) { + jme_set_clean_rxdesc(jme, j); + j = (j + 1) & (mask); + } + + } else { + jme_alloc_and_feed_skb(jme, i); + } + + i = (i + desccnt) & (mask); + } + +out: + atomic_set(&rxring->next_to_clean, i); + +out_inc: + atomic_inc(&jme->rx_cleaning); + + return limit > 0 ? limit : 0; + +} + +static void +jme_attempt_pcc(struct dynpcc_info *dpi, int atmp) +{ + if (likely(atmp == dpi->cur)) { + dpi->cnt = 0; + return; + } + + if (dpi->attempt == atmp) { + ++(dpi->cnt); + } else { + dpi->attempt = atmp; + dpi->cnt = 0; + } + +} + +static void +jme_dynamic_pcc(struct jme_adapter *jme) +{ + register struct dynpcc_info *dpi = &(jme->dpi); + + if ((NET_STAT(jme).rx_bytes - dpi->last_bytes) > PCC_P3_THRESHOLD) + jme_attempt_pcc(dpi, PCC_P3); + else if ((NET_STAT(jme).rx_packets - dpi->last_pkts) > PCC_P2_THRESHOLD + || dpi->intr_cnt > PCC_INTR_THRESHOLD) + jme_attempt_pcc(dpi, PCC_P2); + else + jme_attempt_pcc(dpi, PCC_P1); + + if (unlikely(dpi->attempt != dpi->cur && dpi->cnt > 5)) { + if (dpi->attempt < dpi->cur) + tasklet_schedule(&jme->rxclean_task); + jme_set_rx_pcc(jme, dpi->attempt); + dpi->cur = dpi->attempt; + dpi->cnt = 0; + } +} + +static void +jme_start_pcc_timer(struct jme_adapter *jme) +{ + struct dynpcc_info *dpi = &(jme->dpi); + dpi->last_bytes = NET_STAT(jme).rx_bytes; + dpi->last_pkts = NET_STAT(jme).rx_packets; + dpi->intr_cnt = 0; + jwrite32(jme, JME_TMCSR, + TMCSR_EN | ((0xFFFFFF - PCC_INTERVAL_US) & TMCSR_CNT)); +} + +static inline void +jme_stop_pcc_timer(struct jme_adapter *jme) +{ + jwrite32(jme, JME_TMCSR, 0); +} + +static void +jme_shutdown_nic(struct jme_adapter *jme) +{ + u32 phylink; + + phylink = jme_linkstat_from_phy(jme); + + if (!(phylink & PHY_LINK_UP)) { + /* + * Disable all interrupt before issue timer + */ + jme_stop_irq(jme); + jwrite32(jme, JME_TIMER2, TMCSR_EN | 0xFFFFFE); + } +} + +static void +jme_pcc_tasklet(unsigned long arg) +{ + struct jme_adapter *jme = (struct jme_adapter *)arg; + struct net_device *netdev = jme->dev; + + if (unlikely(test_bit(JME_FLAG_SHUTDOWN, &jme->flags))) { + jme_shutdown_nic(jme); + return; + } + + if (unlikely(!netif_carrier_ok(netdev) || + (atomic_read(&jme->link_changing) != 1) + )) { + jme_stop_pcc_timer(jme); + return; + } + + if (!(test_bit(JME_FLAG_POLL, &jme->flags))) + jme_dynamic_pcc(jme); + + jme_start_pcc_timer(jme); +} + +static inline void +jme_polling_mode(struct jme_adapter *jme) +{ + jme_set_rx_pcc(jme, PCC_OFF); +} + +static inline void +jme_interrupt_mode(struct jme_adapter *jme) +{ + jme_set_rx_pcc(jme, PCC_P1); +} + +static inline int +jme_pseudo_hotplug_enabled(struct jme_adapter *jme) +{ + u32 apmc; + apmc = jread32(jme, JME_APMC); + return apmc & JME_APMC_PSEUDO_HP_EN; +} + +static void +jme_start_shutdown_timer(struct jme_adapter *jme) +{ + u32 apmc; + + apmc = jread32(jme, JME_APMC) | JME_APMC_PCIE_SD_EN; + apmc &= ~JME_APMC_EPIEN_CTRL; + if (!no_extplug) { + jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_EN); + wmb(); + } + jwrite32f(jme, JME_APMC, apmc); + + jwrite32f(jme, JME_TIMER2, 0); + set_bit(JME_FLAG_SHUTDOWN, &jme->flags); + jwrite32(jme, JME_TMCSR, + TMCSR_EN | ((0xFFFFFF - APMC_PHP_SHUTDOWN_DELAY) & TMCSR_CNT)); +} + +static void +jme_stop_shutdown_timer(struct jme_adapter *jme) +{ + u32 apmc; + + jwrite32f(jme, JME_TMCSR, 0); + jwrite32f(jme, JME_TIMER2, 0); + clear_bit(JME_FLAG_SHUTDOWN, &jme->flags); + + apmc = jread32(jme, JME_APMC); + apmc &= ~(JME_APMC_PCIE_SD_EN | JME_APMC_EPIEN_CTRL); + jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_DIS); + wmb(); + jwrite32f(jme, JME_APMC, apmc); +} + +static void +jme_link_change_tasklet(unsigned long arg) +{ + struct jme_adapter *jme = (struct jme_adapter *)arg; + struct net_device *netdev = jme->dev; + int rc; + + while (!atomic_dec_and_test(&jme->link_changing)) { + atomic_inc(&jme->link_changing); + msg_intr(jme, "Get link change lock failed.\n"); + while (atomic_read(&jme->link_changing) != 1) + msg_intr(jme, "Waiting link change lock.\n"); + } + + if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu) + goto out; + + jme->old_mtu = netdev->mtu; + netif_stop_queue(netdev); + if (jme_pseudo_hotplug_enabled(jme)) + jme_stop_shutdown_timer(jme); + + jme_stop_pcc_timer(jme); + tasklet_disable(&jme->txclean_task); + tasklet_disable(&jme->rxclean_task); + tasklet_disable(&jme->rxempty_task); + + if (netif_carrier_ok(netdev)) { + jme_reset_ghc_speed(jme); + jme_disable_rx_engine(jme); + jme_disable_tx_engine(jme); + jme_reset_mac_processor(jme); + jme_free_rx_resources(jme); + jme_free_tx_resources(jme); + + if (test_bit(JME_FLAG_POLL, &jme->flags)) + jme_polling_mode(jme); + + netif_carrier_off(netdev); + } + + jme_check_link(netdev, 0); + if (netif_carrier_ok(netdev)) { + rc = jme_setup_rx_resources(jme); + if (rc) { + jeprintk(jme->pdev, "Allocating resources for RX error" + ", Device STOPPED!\n"); + goto out_enable_tasklet; + } + + rc = jme_setup_tx_resources(jme); + if (rc) { + jeprintk(jme->pdev, "Allocating resources for TX error" + ", Device STOPPED!\n"); + goto err_out_free_rx_resources; + } + + jme_enable_rx_engine(jme); + jme_enable_tx_engine(jme); + + netif_start_queue(netdev); + + if (test_bit(JME_FLAG_POLL, &jme->flags)) + jme_interrupt_mode(jme); + + jme_start_pcc_timer(jme); + } else if (jme_pseudo_hotplug_enabled(jme)) { + jme_start_shutdown_timer(jme); + } + + goto out_enable_tasklet; + +err_out_free_rx_resources: + jme_free_rx_resources(jme); +out_enable_tasklet: + tasklet_enable(&jme->txclean_task); + tasklet_hi_enable(&jme->rxclean_task); + tasklet_hi_enable(&jme->rxempty_task); +out: + atomic_inc(&jme->link_changing); +} + +static void +jme_rx_clean_tasklet(unsigned long arg) +{ + struct jme_adapter *jme = (struct jme_adapter *)arg; + struct dynpcc_info *dpi = &(jme->dpi); + + jme_process_receive(jme, jme->rx_ring_size); + ++(dpi->intr_cnt); + +} + +static int +jme_poll(JME_NAPI_HOLDER(holder), JME_NAPI_WEIGHT(budget)) +{ + struct jme_adapter *jme = jme_napi_priv(holder); + struct net_device *netdev = jme->dev; + int rest; + + rest = jme_process_receive(jme, JME_NAPI_WEIGHT_VAL(budget)); + + while (atomic_read(&jme->rx_empty) > 0) { + atomic_dec(&jme->rx_empty); + ++(NET_STAT(jme).rx_dropped); + jme_restart_rx_engine(jme); + } + atomic_inc(&jme->rx_empty); + + if (rest) { + JME_RX_COMPLETE(netdev, holder); + jme_interrupt_mode(jme); + } + + JME_NAPI_WEIGHT_SET(budget, rest); + return JME_NAPI_WEIGHT_VAL(budget) - rest; +} + +static void +jme_rx_empty_tasklet(unsigned long arg) +{ + struct jme_adapter *jme = (struct jme_adapter *)arg; + + if (unlikely(atomic_read(&jme->link_changing) != 1)) + return; + + if (unlikely(!netif_carrier_ok(jme->dev))) + return; + + msg_rx_status(jme, "RX Queue Full!\n"); + + jme_rx_clean_tasklet(arg); + + while (atomic_read(&jme->rx_empty) > 0) { + atomic_dec(&jme->rx_empty); + ++(NET_STAT(jme).rx_dropped); + jme_restart_rx_engine(jme); + } + atomic_inc(&jme->rx_empty); +} + +static void +jme_wake_queue_if_stopped(struct jme_adapter *jme) +{ + struct jme_ring *txring = jme->txring; + + smp_wmb(); + if (unlikely(netif_queue_stopped(jme->dev) && + atomic_read(&txring->nr_free) >= (jme->tx_wake_threshold))) { + msg_tx_done(jme, "TX Queue Waked.\n"); + netif_wake_queue(jme->dev); + } + +} + +static void +jme_tx_clean_tasklet(unsigned long arg) +{ + struct jme_adapter *jme = (struct jme_adapter *)arg; + struct jme_ring *txring = &(jme->txring[0]); + struct txdesc *txdesc = txring->desc; + struct jme_buffer_info *txbi = txring->bufinf, *ctxbi, *ttxbi; + int i, j, cnt = 0, max, err, mask; + + tx_dbg(jme, "Into txclean.\n"); + + if (unlikely(!atomic_dec_and_test(&jme->tx_cleaning))) + goto out; + + if (unlikely(atomic_read(&jme->link_changing) != 1)) + goto out; + + if (unlikely(!netif_carrier_ok(jme->dev))) + goto out; + + max = jme->tx_ring_size - atomic_read(&txring->nr_free); + mask = jme->tx_ring_mask; + + for (i = atomic_read(&txring->next_to_clean) ; cnt < max ; ) { + + ctxbi = txbi + i; + + if (likely(ctxbi->skb && + !(txdesc[i].descwb.flags & TXWBFLAG_OWN))) { + + tx_dbg(jme, "txclean: %d+%d@%lu\n", + i, ctxbi->nr_desc, jiffies); + + err = txdesc[i].descwb.flags & TXWBFLAG_ALLERR; + + for (j = 1 ; j < ctxbi->nr_desc ; ++j) { + ttxbi = txbi + ((i + j) & (mask)); + txdesc[(i + j) & (mask)].dw[0] = 0; + + pci_unmap_page(jme->pdev, + ttxbi->mapping, + ttxbi->len, + PCI_DMA_TODEVICE); + + ttxbi->mapping = 0; + ttxbi->len = 0; + } + + dev_kfree_skb(ctxbi->skb); + + cnt += ctxbi->nr_desc; + + if (unlikely(err)) { + ++(NET_STAT(jme).tx_carrier_errors); + } else { + ++(NET_STAT(jme).tx_packets); + NET_STAT(jme).tx_bytes += ctxbi->len; + } + + ctxbi->skb = NULL; + ctxbi->len = 0; + ctxbi->start_xmit = 0; + + } else { + break; + } + + i = (i + ctxbi->nr_desc) & mask; + + ctxbi->nr_desc = 0; + } + + tx_dbg(jme, "txclean: done %d@%lu.\n", i, jiffies); + atomic_set(&txring->next_to_clean, i); + atomic_add(cnt, &txring->nr_free); + + jme_wake_queue_if_stopped(jme); + +out: + atomic_inc(&jme->tx_cleaning); +} + +static void +jme_intr_msi(struct jme_adapter *jme, u32 intrstat) +{ + /* + * Disable interrupt + */ + jwrite32f(jme, JME_IENC, INTR_ENABLE); + + if (intrstat & (INTR_LINKCH | INTR_SWINTR)) { + /* + * Link change event is critical + * all other events are ignored + */ + jwrite32(jme, JME_IEVE, intrstat); + tasklet_schedule(&jme->linkch_task); + goto out_reenable; + } + + if (intrstat & INTR_TMINTR) { + jwrite32(jme, JME_IEVE, INTR_TMINTR); + tasklet_schedule(&jme->pcc_task); + } + + if (intrstat & (INTR_PCCTXTO | INTR_PCCTX)) { + jwrite32(jme, JME_IEVE, INTR_PCCTXTO | INTR_PCCTX | INTR_TX0); + tasklet_schedule(&jme->txclean_task); + } + + if ((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) { + jwrite32(jme, JME_IEVE, (intrstat & (INTR_PCCRX0TO | + INTR_PCCRX0 | + INTR_RX0EMP)) | + INTR_RX0); + } + + if (test_bit(JME_FLAG_POLL, &jme->flags)) { + if (intrstat & INTR_RX0EMP) + atomic_inc(&jme->rx_empty); + + if ((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) { + if (likely(JME_RX_SCHEDULE_PREP(jme))) { + jme_polling_mode(jme); + JME_RX_SCHEDULE(jme); + } + } + } else { + if (intrstat & INTR_RX0EMP) { + atomic_inc(&jme->rx_empty); + tasklet_hi_schedule(&jme->rxempty_task); + } else if (intrstat & (INTR_PCCRX0TO | INTR_PCCRX0)) { + tasklet_hi_schedule(&jme->rxclean_task); + } + } + +out_reenable: + /* + * Re-enable interrupt + */ + jwrite32f(jme, JME_IENS, INTR_ENABLE); +} + +static irqreturn_t +jme_intr(int irq, void *dev_id) +{ + struct net_device *netdev = dev_id; + struct jme_adapter *jme = netdev_priv(netdev); + u32 intrstat; + + intrstat = jread32(jme, JME_IEVE); + + /* + * Check if it's really an interrupt for us + */ + if (unlikely((intrstat & INTR_ENABLE) == 0)) + return IRQ_NONE; + + /* + * Check if the device still exist + */ + if (unlikely(intrstat == ~((typeof(intrstat))0))) + return IRQ_NONE; + + jme_intr_msi(jme, intrstat); + + return IRQ_HANDLED; +} + +static irqreturn_t +jme_msi(int irq, void *dev_id) +{ + struct net_device *netdev = dev_id; + struct jme_adapter *jme = netdev_priv(netdev); + u32 intrstat; + + pci_dma_sync_single_for_cpu(jme->pdev, + jme->shadow_dma, + sizeof(u32) * SHADOW_REG_NR, + PCI_DMA_FROMDEVICE); + intrstat = jme->shadow_regs[SHADOW_IEVE]; + jme->shadow_regs[SHADOW_IEVE] = 0; + + jme_intr_msi(jme, intrstat); + + return IRQ_HANDLED; +} + +static void +jme_reset_link(struct jme_adapter *jme) +{ + jwrite32(jme, JME_TMCSR, TMCSR_SWIT); +} + +static void +jme_restart_an(struct jme_adapter *jme) +{ + u32 bmcr; + + spin_lock_bh(&jme->phy_lock); + bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR); + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr); + spin_unlock_bh(&jme->phy_lock); +} + +static int +jme_request_irq(struct jme_adapter *jme) +{ + int rc; + struct net_device *netdev = jme->dev; + irq_handler_t handler = jme_intr; + int irq_flags = IRQF_SHARED; + + if (!pci_enable_msi(jme->pdev)) { + set_bit(JME_FLAG_MSI, &jme->flags); + handler = jme_msi; + irq_flags = 0; + } + + rc = request_irq(jme->pdev->irq, handler, irq_flags, netdev->name, + netdev); + if (rc) { + jeprintk(jme->pdev, + "Unable to request %s interrupt (return: %d)\n", + test_bit(JME_FLAG_MSI, &jme->flags) ? "MSI" : "INTx", + rc); + + if (test_bit(JME_FLAG_MSI, &jme->flags)) { + pci_disable_msi(jme->pdev); + clear_bit(JME_FLAG_MSI, &jme->flags); + } + } else { + netdev->irq = jme->pdev->irq; + } + + return rc; +} + +static void +jme_free_irq(struct jme_adapter *jme) +{ + free_irq(jme->pdev->irq, jme->dev); + if (test_bit(JME_FLAG_MSI, &jme->flags)) { + pci_disable_msi(jme->pdev); + clear_bit(JME_FLAG_MSI, &jme->flags); + jme->dev->irq = jme->pdev->irq; + } +} + +static int +jme_open(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int rc; + + jme_clear_pm(jme); + JME_NAPI_ENABLE(jme); + + tasklet_enable(&jme->txclean_task); + tasklet_hi_enable(&jme->rxclean_task); + tasklet_hi_enable(&jme->rxempty_task); + + rc = jme_request_irq(jme); + if (rc) + goto err_out; + + jme_enable_shadow(jme); + jme_start_irq(jme); + + if (test_bit(JME_FLAG_SSET, &jme->flags)) + jme_set_settings(netdev, &jme->old_ecmd); + else + jme_reset_phy_processor(jme); + + jme_reset_link(jme); + + return 0; + +err_out: + netif_stop_queue(netdev); + netif_carrier_off(netdev); + return rc; +} + +#ifdef CONFIG_PM +static void +jme_set_100m_half(struct jme_adapter *jme) +{ + u32 bmcr, tmp; + + bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR); + tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | + BMCR_SPEED1000 | BMCR_FULLDPLX); + tmp |= BMCR_SPEED100; + + if (bmcr != tmp) + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, tmp); + + if (jme->fpgaver) + jwrite32(jme, JME_GHC, GHC_SPEED_100M | GHC_LINK_POLL); + else + jwrite32(jme, JME_GHC, GHC_SPEED_100M); +} + +#define JME_WAIT_LINK_TIME 2000 /* 2000ms */ +static void +jme_wait_link(struct jme_adapter *jme) +{ + u32 phylink, to = JME_WAIT_LINK_TIME; + + mdelay(1000); + phylink = jme_linkstat_from_phy(jme); + while (!(phylink & PHY_LINK_UP) && (to -= 10) > 0) { + mdelay(10); + phylink = jme_linkstat_from_phy(jme); + } +} +#endif + +static inline void +jme_phy_off(struct jme_adapter *jme) +{ + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, BMCR_PDOWN); +} + +static int +jme_close(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + + netif_stop_queue(netdev); + netif_carrier_off(netdev); + + jme_stop_irq(jme); + jme_disable_shadow(jme); + jme_free_irq(jme); + + JME_NAPI_DISABLE(jme); + + tasklet_kill(&jme->linkch_task); + tasklet_kill(&jme->txclean_task); + tasklet_kill(&jme->rxclean_task); + tasklet_kill(&jme->rxempty_task); + + jme_reset_ghc_speed(jme); + jme_disable_rx_engine(jme); + jme_disable_tx_engine(jme); + jme_reset_mac_processor(jme); + jme_free_rx_resources(jme); + jme_free_tx_resources(jme); + jme->phylink = 0; + jme_phy_off(jme); + + return 0; +} + +static int +jme_alloc_txdesc(struct jme_adapter *jme, + struct sk_buff *skb) +{ + struct jme_ring *txring = jme->txring; + int idx, nr_alloc, mask = jme->tx_ring_mask; + + idx = txring->next_to_use; + nr_alloc = skb_shinfo(skb)->nr_frags + 2; + + if (unlikely(atomic_read(&txring->nr_free) < nr_alloc)) + return -1; + + atomic_sub(nr_alloc, &txring->nr_free); + + txring->next_to_use = (txring->next_to_use + nr_alloc) & mask; + + return idx; +} + +static void +jme_fill_tx_map(struct pci_dev *pdev, + struct txdesc *txdesc, + struct jme_buffer_info *txbi, + struct page *page, + u32 page_offset, + u32 len, + u8 hidma) +{ + dma_addr_t dmaaddr; + + dmaaddr = pci_map_page(pdev, + page, + page_offset, + len, + PCI_DMA_TODEVICE); + + pci_dma_sync_single_for_device(pdev, + dmaaddr, + len, + PCI_DMA_TODEVICE); + + txdesc->dw[0] = 0; + txdesc->dw[1] = 0; + txdesc->desc2.flags = TXFLAG_OWN; + txdesc->desc2.flags |= (hidma) ? TXFLAG_64BIT : 0; + txdesc->desc2.datalen = cpu_to_le16(len); + txdesc->desc2.bufaddrh = cpu_to_le32((__u64)dmaaddr >> 32); + txdesc->desc2.bufaddrl = cpu_to_le32( + (__u64)dmaaddr & 0xFFFFFFFFUL); + + txbi->mapping = dmaaddr; + txbi->len = len; +} + +static void +jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx) +{ + struct jme_ring *txring = jme->txring; + struct txdesc *txdesc = txring->desc, *ctxdesc; + struct jme_buffer_info *txbi = txring->bufinf, *ctxbi; + u8 hidma = jme->dev->features & NETIF_F_HIGHDMA; + int i, nr_frags = skb_shinfo(skb)->nr_frags; + int mask = jme->tx_ring_mask; + struct skb_frag_struct *frag; + u32 len; + + for (i = 0 ; i < nr_frags ; ++i) { + frag = &skb_shinfo(skb)->frags[i]; + ctxdesc = txdesc + ((idx + i + 2) & (mask)); + ctxbi = txbi + ((idx + i + 2) & (mask)); + + jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, frag->page, + frag->page_offset, frag->size, hidma); + } + + len = skb_is_nonlinear(skb) ? skb_headlen(skb) : skb->len; + ctxdesc = txdesc + ((idx + 1) & (mask)); + ctxbi = txbi + ((idx + 1) & (mask)); + jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, virt_to_page(skb->data), + offset_in_page(skb->data), len, hidma); + +} + +static int +jme_expand_header(struct jme_adapter *jme, struct sk_buff *skb) +{ + if (unlikely(skb_shinfo(skb)->gso_size && + skb_header_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) { + dev_kfree_skb(skb); + return -1; + } + + return 0; +} + +static int +jme_tx_tso(struct sk_buff *skb, + u16 *mss, u8 *flags) +{ + *mss = skb_shinfo(skb)->gso_size << TXDESC_MSS_SHIFT; + if (*mss) { + *flags |= TXFLAG_LSEN; + + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *iph = ip_hdr(skb); + + iph->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, + 0); + } else { + struct ipv6hdr *ip6h = ipv6_hdr(skb); + + tcp_hdr(skb)->check = ~csum_ipv6_magic(&ip6h->saddr, + &ip6h->daddr, 0, + IPPROTO_TCP, + 0); + } + + return 0; + } + + return 1; +} + +static void +jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags) +{ + if (skb->ip_summed == CHECKSUM_PARTIAL) { + u8 ip_proto; + + switch (skb->protocol) { + case htons(ETH_P_IP): + ip_proto = ip_hdr(skb)->protocol; + break; + case htons(ETH_P_IPV6): + ip_proto = ipv6_hdr(skb)->nexthdr; + break; + default: + ip_proto = 0; + break; + } + + switch (ip_proto) { + case IPPROTO_TCP: + *flags |= TXFLAG_TCPCS; + break; + case IPPROTO_UDP: + *flags |= TXFLAG_UDPCS; + break; + default: + msg_tx_err(jme, "Error upper layer protocol.\n"); + break; + } + } +} + +static inline void +jme_tx_vlan(struct sk_buff *skb, u16 *vlan, u8 *flags) +{ + if (vlan_tx_tag_present(skb)) { + *flags |= TXFLAG_TAGON; + *vlan = vlan_tx_tag_get(skb); + } +} + +static int +jme_fill_first_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) +{ + struct jme_ring *txring = jme->txring; + struct txdesc *txdesc; + struct jme_buffer_info *txbi; + u8 flags; + + txdesc = (struct txdesc *)txring->desc + idx; + txbi = txring->bufinf + idx; + + txdesc->dw[0] = 0; + txdesc->dw[1] = 0; + txdesc->dw[2] = 0; + txdesc->dw[3] = 0; + txdesc->desc1.pktsize = cpu_to_le16(skb->len); + /* + * Set OWN bit at final. + * When kernel transmit faster than NIC. + * And NIC trying to send this descriptor before we tell + * it to start sending this TX queue. + * Other fields are already filled correctly. + */ + wmb(); + flags = TXFLAG_OWN | TXFLAG_INT; + /* + * Set checksum flags while not tso + */ + if (jme_tx_tso(skb, &txdesc->desc1.mss, &flags)) + jme_tx_csum(jme, skb, &flags); + jme_tx_vlan(skb, &txdesc->desc1.vlan, &flags); + txdesc->desc1.flags = flags; + /* + * Set tx buffer info after telling NIC to send + * For better tx_clean timing + */ + wmb(); + txbi->nr_desc = skb_shinfo(skb)->nr_frags + 2; + txbi->skb = skb; + txbi->len = skb->len; + txbi->start_xmit = jiffies; + if (!txbi->start_xmit) + txbi->start_xmit = (0UL-1); + + return 0; +} + +static void +jme_stop_queue_if_full(struct jme_adapter *jme) +{ + struct jme_ring *txring = jme->txring; + struct jme_buffer_info *txbi = txring->bufinf; + int idx = atomic_read(&txring->next_to_clean); + + txbi += idx; + + smp_wmb(); + if (unlikely(atomic_read(&txring->nr_free) < (MAX_SKB_FRAGS+2))) { + netif_stop_queue(jme->dev); + msg_tx_queued(jme, "TX Queue Paused.\n"); + smp_wmb(); + if (atomic_read(&txring->nr_free) + >= (jme->tx_wake_threshold)) { + netif_wake_queue(jme->dev); + msg_tx_queued(jme, "TX Queue Fast Waked.\n"); + } + } + + if (unlikely(txbi->start_xmit && + (jiffies - txbi->start_xmit) >= TX_TIMEOUT && + txbi->skb)) { + netif_stop_queue(jme->dev); + msg_tx_queued(jme, "TX Queue Stopped %d@%lu.\n", idx, jiffies); + } +} + +/* + * This function is already protected by netif_tx_lock() + */ + +static int +jme_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int idx; + + if (unlikely(jme_expand_header(jme, skb))) { + ++(NET_STAT(jme).tx_dropped); + return NETDEV_TX_OK; + } + + idx = jme_alloc_txdesc(jme, skb); + + if (unlikely(idx < 0)) { + netif_stop_queue(netdev); + msg_tx_err(jme, "BUG! Tx ring full when queue awake!\n"); + + return NETDEV_TX_BUSY; + } + + jme_map_tx_skb(jme, skb, idx); + jme_fill_first_tx_desc(jme, skb, idx); + + jwrite32(jme, JME_TXCS, jme->reg_txcs | + TXCS_SELECT_QUEUE0 | + TXCS_QUEUE0S | + TXCS_ENABLE); + netdev->trans_start = jiffies; + + tx_dbg(jme, "xmit: %d+%d@%lu\n", idx, + skb_shinfo(skb)->nr_frags + 2, + jiffies); + jme_stop_queue_if_full(jme); + + return NETDEV_TX_OK; +} + +static int +jme_set_macaddr(struct net_device *netdev, void *p) +{ + struct jme_adapter *jme = netdev_priv(netdev); + struct sockaddr *addr = p; + u32 val; + + if (netif_running(netdev)) + return -EBUSY; + + spin_lock_bh(&jme->macaddr_lock); + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + + val = (addr->sa_data[3] & 0xff) << 24 | + (addr->sa_data[2] & 0xff) << 16 | + (addr->sa_data[1] & 0xff) << 8 | + (addr->sa_data[0] & 0xff); + jwrite32(jme, JME_RXUMA_LO, val); + val = (addr->sa_data[5] & 0xff) << 8 | + (addr->sa_data[4] & 0xff); + jwrite32(jme, JME_RXUMA_HI, val); + spin_unlock_bh(&jme->macaddr_lock); + + return 0; +} + +static void +jme_set_multi(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + u32 mc_hash[2] = {}; + int i; + + spin_lock_bh(&jme->rxmcs_lock); + + jme->reg_rxmcs |= RXMCS_BRDFRAME | RXMCS_UNIFRAME; + + if (netdev->flags & IFF_PROMISC) { + jme->reg_rxmcs |= RXMCS_ALLFRAME; + } else if (netdev->flags & IFF_ALLMULTI) { + jme->reg_rxmcs |= RXMCS_ALLMULFRAME; + } else if (netdev->flags & IFF_MULTICAST) { + struct dev_mc_list *mclist; + int bit_nr; + + jme->reg_rxmcs |= RXMCS_MULFRAME | RXMCS_MULFILTERED; + for (i = 0, mclist = netdev->mc_list; + mclist && i < netdev->mc_count; + ++i, mclist = mclist->next) { + + bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3F; + mc_hash[bit_nr >> 5] |= 1 << (bit_nr & 0x1F); + } + + jwrite32(jme, JME_RXMCHT_LO, mc_hash[0]); + jwrite32(jme, JME_RXMCHT_HI, mc_hash[1]); + } + + wmb(); + jwrite32(jme, JME_RXMCS, jme->reg_rxmcs); + + spin_unlock_bh(&jme->rxmcs_lock); +} + +static int +jme_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct jme_adapter *jme = netdev_priv(netdev); + + if (new_mtu == jme->old_mtu) + return 0; + + if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) || + ((new_mtu) < IPV6_MIN_MTU)) + return -EINVAL; + + if (new_mtu > 4000) { + jme->reg_rxcs &= ~RXCS_FIFOTHNP; + jme->reg_rxcs |= RXCS_FIFOTHNP_64QW; + jme_restart_rx_engine(jme); + } else { + jme->reg_rxcs &= ~RXCS_FIFOTHNP; + jme->reg_rxcs |= RXCS_FIFOTHNP_128QW; + jme_restart_rx_engine(jme); + } + + if (new_mtu > 1900) { + netdev->features &= ~(NETIF_F_HW_CSUM | + NETIF_F_TSO | + NETIF_F_TSO6); + } else { + if (test_bit(JME_FLAG_TXCSUM, &jme->flags)) + netdev->features |= NETIF_F_HW_CSUM; + if (test_bit(JME_FLAG_TSO, &jme->flags)) + netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; + } + + netdev->mtu = new_mtu; + jme_reset_link(jme); + + return 0; +} + +static void +jme_tx_timeout(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + + jme->phylink = 0; + jme_reset_phy_processor(jme); + if (test_bit(JME_FLAG_SSET, &jme->flags)) + jme_set_settings(netdev, &jme->old_ecmd); + + /* + * Force to Reset the link again + */ + jme_reset_link(jme); +} + +static void +jme_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) +{ + struct jme_adapter *jme = netdev_priv(netdev); + + jme->vlgrp = grp; +} + +static void +jme_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + struct jme_adapter *jme = netdev_priv(netdev); + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(jme->pdev)); +} + +static int +jme_get_regs_len(struct net_device *netdev) +{ + return JME_REG_LEN; +} + +static void +mmapio_memcpy(struct jme_adapter *jme, u32 *p, u32 reg, int len) +{ + int i; + + for (i = 0 ; i < len ; i += 4) + p[i >> 2] = jread32(jme, reg + i); +} + +static void +mdio_memcpy(struct jme_adapter *jme, u32 *p, int reg_nr) +{ + int i; + u16 *p16 = (u16 *)p; + + for (i = 0 ; i < reg_nr ; ++i) + p16[i] = jme_mdio_read(jme->dev, jme->mii_if.phy_id, i); +} + +static void +jme_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) +{ + struct jme_adapter *jme = netdev_priv(netdev); + u32 *p32 = (u32 *)p; + + memset(p, 0xFF, JME_REG_LEN); + + regs->version = 1; + mmapio_memcpy(jme, p32, JME_MAC, JME_MAC_LEN); + + p32 += 0x100 >> 2; + mmapio_memcpy(jme, p32, JME_PHY, JME_PHY_LEN); + + p32 += 0x100 >> 2; + mmapio_memcpy(jme, p32, JME_MISC, JME_MISC_LEN); + + p32 += 0x100 >> 2; + mmapio_memcpy(jme, p32, JME_RSS, JME_RSS_LEN); + + p32 += 0x100 >> 2; + mdio_memcpy(jme, p32, JME_PHY_REG_NR); +} + +static int +jme_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd) +{ + struct jme_adapter *jme = netdev_priv(netdev); + + ecmd->tx_coalesce_usecs = PCC_TX_TO; + ecmd->tx_max_coalesced_frames = PCC_TX_CNT; + + if (test_bit(JME_FLAG_POLL, &jme->flags)) { + ecmd->use_adaptive_rx_coalesce = false; + ecmd->rx_coalesce_usecs = 0; + ecmd->rx_max_coalesced_frames = 0; + return 0; + } + + ecmd->use_adaptive_rx_coalesce = true; + + switch (jme->dpi.cur) { + case PCC_P1: + ecmd->rx_coalesce_usecs = PCC_P1_TO; + ecmd->rx_max_coalesced_frames = PCC_P1_CNT; + break; + case PCC_P2: + ecmd->rx_coalesce_usecs = PCC_P2_TO; + ecmd->rx_max_coalesced_frames = PCC_P2_CNT; + break; + case PCC_P3: + ecmd->rx_coalesce_usecs = PCC_P3_TO; + ecmd->rx_max_coalesced_frames = PCC_P3_CNT; + break; + default: + break; + } + + return 0; +} + +static int +jme_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd) +{ + struct jme_adapter *jme = netdev_priv(netdev); + struct dynpcc_info *dpi = &(jme->dpi); + + if (netif_running(netdev)) + return -EBUSY; + + if (ecmd->use_adaptive_rx_coalesce + && test_bit(JME_FLAG_POLL, &jme->flags)) { + clear_bit(JME_FLAG_POLL, &jme->flags); + jme->jme_rx = netif_rx; + jme->jme_vlan_rx = vlan_hwaccel_rx; + dpi->cur = PCC_P1; + dpi->attempt = PCC_P1; + dpi->cnt = 0; + jme_set_rx_pcc(jme, PCC_P1); + jme_interrupt_mode(jme); + } else if (!(ecmd->use_adaptive_rx_coalesce) + && !(test_bit(JME_FLAG_POLL, &jme->flags))) { + set_bit(JME_FLAG_POLL, &jme->flags); + jme->jme_rx = netif_receive_skb; + jme->jme_vlan_rx = vlan_hwaccel_receive_skb; + jme_interrupt_mode(jme); + } + + return 0; +} + +static void +jme_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *ecmd) +{ + struct jme_adapter *jme = netdev_priv(netdev); + u32 val; + + ecmd->tx_pause = (jme->reg_txpfc & TXPFC_PF_EN) != 0; + ecmd->rx_pause = (jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0; + + spin_lock_bh(&jme->phy_lock); + val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE); + spin_unlock_bh(&jme->phy_lock); + + ecmd->autoneg = + (val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0; +} + +static int +jme_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *ecmd) +{ + struct jme_adapter *jme = netdev_priv(netdev); + u32 val; + + if (((jme->reg_txpfc & TXPFC_PF_EN) != 0) ^ + (ecmd->tx_pause != 0)) { + + if (ecmd->tx_pause) + jme->reg_txpfc |= TXPFC_PF_EN; + else + jme->reg_txpfc &= ~TXPFC_PF_EN; + + jwrite32(jme, JME_TXPFC, jme->reg_txpfc); + } + + spin_lock_bh(&jme->rxmcs_lock); + if (((jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0) ^ + (ecmd->rx_pause != 0)) { + + if (ecmd->rx_pause) + jme->reg_rxmcs |= RXMCS_FLOWCTRL; + else + jme->reg_rxmcs &= ~RXMCS_FLOWCTRL; + + jwrite32(jme, JME_RXMCS, jme->reg_rxmcs); + } + spin_unlock_bh(&jme->rxmcs_lock); + + spin_lock_bh(&jme->phy_lock); + val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE); + if (((val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0) ^ + (ecmd->autoneg != 0)) { + + if (ecmd->autoneg) + val |= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + else + val &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + + jme_mdio_write(jme->dev, jme->mii_if.phy_id, + MII_ADVERTISE, val); + } + spin_unlock_bh(&jme->phy_lock); + + return 0; +} + +static void +jme_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct jme_adapter *jme = netdev_priv(netdev); + + wol->supported = WAKE_MAGIC | WAKE_PHY; + + wol->wolopts = 0; + + if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN)) + wol->wolopts |= WAKE_PHY; + + if (jme->reg_pmcs & PMCS_MFEN) + wol->wolopts |= WAKE_MAGIC; + +} + +static int +jme_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct jme_adapter *jme = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_MAGICSECURE | + WAKE_UCAST | + WAKE_MCAST | + WAKE_BCAST | + WAKE_ARP)) + return -EOPNOTSUPP; + + jme->reg_pmcs = 0; + + if (wol->wolopts & WAKE_PHY) + jme->reg_pmcs |= PMCS_LFEN | PMCS_LREN; + + if (wol->wolopts & WAKE_MAGIC) + jme->reg_pmcs |= PMCS_MFEN; + + jwrite32(jme, JME_PMCS, jme->reg_pmcs); + + return 0; +} + +static int +jme_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int rc; + + spin_lock_bh(&jme->phy_lock); + rc = mii_ethtool_gset(&(jme->mii_if), ecmd); + spin_unlock_bh(&jme->phy_lock); + return rc; +} + +static int +jme_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int rc, fdc = 0; + + if (ecmd->speed == SPEED_1000 && ecmd->autoneg != AUTONEG_ENABLE) + return -EINVAL; + + if (jme->mii_if.force_media && + ecmd->autoneg != AUTONEG_ENABLE && + (jme->mii_if.full_duplex != ecmd->duplex)) + fdc = 1; + + spin_lock_bh(&jme->phy_lock); + rc = mii_ethtool_sset(&(jme->mii_if), ecmd); + spin_unlock_bh(&jme->phy_lock); + + if (!rc && fdc) + jme_reset_link(jme); + + if (!rc) { + set_bit(JME_FLAG_SSET, &jme->flags); + jme->old_ecmd = *ecmd; + } + + return rc; +} + +static u32 +jme_get_link(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + return jread32(jme, JME_PHY_LINK) & PHY_LINK_UP; +} + +static u32 +jme_get_msglevel(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + return jme->msg_enable; +} + +static void +jme_set_msglevel(struct net_device *netdev, u32 value) +{ + struct jme_adapter *jme = netdev_priv(netdev); + jme->msg_enable = value; +} + +static u32 +jme_get_rx_csum(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + return jme->reg_rxmcs & RXMCS_CHECKSUM; +} + +static int +jme_set_rx_csum(struct net_device *netdev, u32 on) +{ + struct jme_adapter *jme = netdev_priv(netdev); + + spin_lock_bh(&jme->rxmcs_lock); + if (on) + jme->reg_rxmcs |= RXMCS_CHECKSUM; + else + jme->reg_rxmcs &= ~RXMCS_CHECKSUM; + jwrite32(jme, JME_RXMCS, jme->reg_rxmcs); + spin_unlock_bh(&jme->rxmcs_lock); + + return 0; +} + +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_HW_CSUM; + } else { + clear_bit(JME_FLAG_TXCSUM, &jme->flags); + netdev->features &= ~NETIF_F_HW_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); + jme_restart_an(jme); + return 0; +} + +static u8 +jme_smb_read(struct jme_adapter *jme, unsigned int addr) +{ + u32 val; + int to; + + val = jread32(jme, JME_SMBCSR); + to = JME_SMB_BUSY_TIMEOUT; + while ((val & SMBCSR_BUSY) && --to) { + msleep(1); + val = jread32(jme, JME_SMBCSR); + } + if (!to) { + msg_hw(jme, "SMB Bus Busy.\n"); + return 0xFF; + } + + jwrite32(jme, JME_SMBINTF, + ((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) | + SMBINTF_HWRWN_READ | + SMBINTF_HWCMD); + + val = jread32(jme, JME_SMBINTF); + to = JME_SMB_BUSY_TIMEOUT; + while ((val & SMBINTF_HWCMD) && --to) { + msleep(1); + val = jread32(jme, JME_SMBINTF); + } + if (!to) { + msg_hw(jme, "SMB Bus Busy.\n"); + return 0xFF; + } + + return (val & SMBINTF_HWDATR) >> SMBINTF_HWDATR_SHIFT; +} + +static void +jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data) +{ + u32 val; + int to; + + val = jread32(jme, JME_SMBCSR); + to = JME_SMB_BUSY_TIMEOUT; + while ((val & SMBCSR_BUSY) && --to) { + msleep(1); + val = jread32(jme, JME_SMBCSR); + } + if (!to) { + msg_hw(jme, "SMB Bus Busy.\n"); + return; + } + + jwrite32(jme, JME_SMBINTF, + ((data << SMBINTF_HWDATW_SHIFT) & SMBINTF_HWDATW) | + ((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) | + SMBINTF_HWRWN_WRITE | + SMBINTF_HWCMD); + + val = jread32(jme, JME_SMBINTF); + to = JME_SMB_BUSY_TIMEOUT; + while ((val & SMBINTF_HWCMD) && --to) { + msleep(1); + val = jread32(jme, JME_SMBINTF); + } + if (!to) { + msg_hw(jme, "SMB Bus Busy.\n"); + return; + } + + mdelay(2); +} + +static int +jme_get_eeprom_len(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + u32 val; + val = jread32(jme, JME_SMBCSR); + return (val & SMBCSR_EEPROMD) ? JME_SMB_LEN : 0; +} + +static int +jme_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int i, offset = eeprom->offset, len = eeprom->len; + + /* + * ethtool will check the boundary for us + */ + eeprom->magic = JME_EEPROM_MAGIC; + for (i = 0 ; i < len ; ++i) + data[i] = jme_smb_read(jme, i + offset); + + return 0; +} + +static int +jme_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int i, offset = eeprom->offset, len = eeprom->len; + + if (eeprom->magic != JME_EEPROM_MAGIC) + return -EINVAL; + + /* + * ethtool will check the boundary for us + */ + for (i = 0 ; i < len ; ++i) + jme_smb_write(jme, i + offset, data[i]); + + return 0; +} + +static const struct ethtool_ops jme_ethtool_ops = { + .get_drvinfo = jme_get_drvinfo, + .get_regs_len = jme_get_regs_len, + .get_regs = jme_get_regs, + .get_coalesce = jme_get_coalesce, + .set_coalesce = jme_set_coalesce, + .get_pauseparam = jme_get_pauseparam, + .set_pauseparam = jme_set_pauseparam, + .get_wol = jme_get_wol, + .set_wol = jme_set_wol, + .get_settings = jme_get_settings, + .set_settings = jme_set_settings, + .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, + .set_eeprom = jme_set_eeprom, +}; + +static int +jme_pci_dma64(struct pci_dev *pdev) +{ + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) + if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) + return 1; + + if (!pci_set_dma_mask(pdev, DMA_40BIT_MASK)) + if (!pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK)) + return 1; + + if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) + if (!pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) + return 0; + + return -1; +} + +static inline void +jme_phy_init(struct jme_adapter *jme) +{ + u16 reg26; + + reg26 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 26); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, 26, reg26 | 0x1000); +} + +static inline void +jme_check_hw_ver(struct jme_adapter *jme) +{ + u32 chipmode; + + chipmode = jread32(jme, JME_CHIPMODE); + + jme->fpgaver = (chipmode & CM_FPGAVER_MASK) >> CM_FPGAVER_SHIFT; + jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT; +} + +static int __devinit +jme_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int rc = 0, using_dac, i; + struct net_device *netdev; + struct jme_adapter *jme; + u16 bmcr, bmsr; + u32 apmc; + + /* + * set up PCI device basics + */ + rc = pci_enable_device(pdev); + if (rc) { + jeprintk(pdev, "Cannot enable PCI device.\n"); + goto err_out; + } + + using_dac = jme_pci_dma64(pdev); + if (using_dac < 0) { + jeprintk(pdev, "Cannot set PCI DMA Mask.\n"); + rc = -EIO; + goto err_out_disable_pdev; + } + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + jeprintk(pdev, "No PCI resource region found.\n"); + rc = -ENOMEM; + goto err_out_disable_pdev; + } + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) { + jeprintk(pdev, "Cannot obtain PCI resource region.\n"); + goto err_out_disable_pdev; + } + + pci_set_master(pdev); + + /* + * alloc and init net device + */ + netdev = alloc_etherdev(sizeof(*jme)); + if (!netdev) { + jeprintk(pdev, "Cannot allocate netdev structure.\n"); + rc = -ENOMEM; + goto err_out_release_regions; + } + netdev->open = jme_open; + netdev->stop = jme_close; + netdev->hard_start_xmit = jme_start_xmit; + netdev->set_mac_address = jme_set_macaddr; + netdev->set_multicast_list = jme_set_multi; + netdev->change_mtu = jme_change_mtu; + netdev->ethtool_ops = &jme_ethtool_ops; + netdev->tx_timeout = jme_tx_timeout; + netdev->watchdog_timeo = TX_TIMEOUT; + netdev->vlan_rx_register = jme_vlan_rx_register; + NETDEV_GET_STATS(netdev, &jme_get_stats); + netdev->features = NETIF_F_HW_CSUM | + NETIF_F_SG | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX; + if (using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + SET_NETDEV_DEV(netdev, &pdev->dev); + pci_set_drvdata(pdev, netdev); + + /* + * init adapter info + */ + jme = netdev_priv(netdev); + jme->pdev = pdev; + jme->dev = netdev; + jme->jme_rx = netif_rx; + jme->jme_vlan_rx = vlan_hwaccel_rx; + jme->old_mtu = netdev->mtu = 1500; + jme->phylink = 0; + jme->tx_ring_size = 1 << 10; + jme->tx_ring_mask = jme->tx_ring_size - 1; + jme->tx_wake_threshold = 1 << 9; + jme->rx_ring_size = 1 << 9; + jme->rx_ring_mask = jme->rx_ring_size - 1; + jme->msg_enable = JME_DEF_MSG_ENABLE; + jme->regs = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!(jme->regs)) { + jeprintk(pdev, "Mapping PCI resource region error.\n"); + rc = -ENOMEM; + goto err_out_free_netdev; + } + jme->shadow_regs = pci_alloc_consistent(pdev, + sizeof(u32) * SHADOW_REG_NR, + &(jme->shadow_dma)); + if (!(jme->shadow_regs)) { + jeprintk(pdev, "Allocating shadow register mapping error.\n"); + rc = -ENOMEM; + goto err_out_unmap; + } + + if (no_pseudohp) { + apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN; + jwrite32(jme, JME_APMC, apmc); + } else if (force_pseudohp) { + apmc = jread32(jme, JME_APMC) | JME_APMC_PSEUDO_HP_EN; + jwrite32(jme, JME_APMC, apmc); + } + + NETIF_NAPI_SET(netdev, &jme->napi, jme_poll, jme->rx_ring_size >> 2) + + spin_lock_init(&jme->phy_lock); + spin_lock_init(&jme->macaddr_lock); + spin_lock_init(&jme->rxmcs_lock); + + atomic_set(&jme->link_changing, 1); + atomic_set(&jme->rx_cleaning, 1); + atomic_set(&jme->tx_cleaning, 1); + atomic_set(&jme->rx_empty, 1); + + tasklet_init(&jme->pcc_task, + &jme_pcc_tasklet, + (unsigned long) jme); + tasklet_init(&jme->linkch_task, + &jme_link_change_tasklet, + (unsigned long) jme); + tasklet_init(&jme->txclean_task, + &jme_tx_clean_tasklet, + (unsigned long) jme); + tasklet_init(&jme->rxclean_task, + &jme_rx_clean_tasklet, + (unsigned long) jme); + tasklet_init(&jme->rxempty_task, + &jme_rx_empty_tasklet, + (unsigned long) jme); + tasklet_disable_nosync(&jme->txclean_task); + tasklet_disable_nosync(&jme->rxclean_task); + tasklet_disable_nosync(&jme->rxempty_task); + jme->dpi.cur = PCC_P1; + + jme->reg_ghc = 0; + jme->reg_rxcs = RXCS_DEFAULT; + jme->reg_rxmcs = RXMCS_DEFAULT; + jme->reg_txpfc = 0; + jme->reg_pmcs = PMCS_MFEN; + set_bit(JME_FLAG_TXCSUM, &jme->flags); + set_bit(JME_FLAG_TSO, &jme->flags); + + /* + * Get Max Read Req Size from PCI Config Space + */ + pci_read_config_byte(pdev, PCI_DCSR_MRRS, &jme->mrrs); + jme->mrrs &= PCI_DCSR_MRRS_MASK; + switch (jme->mrrs) { + case MRRS_128B: + jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_128B; + break; + case MRRS_256B: + jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_256B; + break; + default: + jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_512B; + break; + }; + + /* + * Must check before reset_mac_processor + */ + jme_check_hw_ver(jme); + jme->mii_if.dev = netdev; + if (jme->fpgaver) { + jme->mii_if.phy_id = 0; + for (i = 1 ; i < 32 ; ++i) { + bmcr = jme_mdio_read(netdev, i, MII_BMCR); + bmsr = jme_mdio_read(netdev, i, MII_BMSR); + if (bmcr != 0xFFFFU && (bmcr != 0 || bmsr != 0)) { + jme->mii_if.phy_id = i; + break; + } + } + + if (!jme->mii_if.phy_id) { + rc = -EIO; + jeprintk(pdev, "Can not find phy_id.\n"); + goto err_out_free_shadow; + } + + jme->reg_ghc |= GHC_LINK_POLL; + } else { + jme->mii_if.phy_id = 1; + } + if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) + jme->mii_if.supports_gmii = true; + else + jme->mii_if.supports_gmii = false; + jme->mii_if.mdio_read = jme_mdio_read; + jme->mii_if.mdio_write = jme_mdio_write; + + jme_clear_pm(jme); + jme_set_phyfifoa(jme); + pci_read_config_byte(pdev, PCI_REVISION_ID, &jme->rev); + if (!jme->fpgaver) + jme_phy_init(jme); + jme_phy_off(jme); + + /* + * Reset MAC processor and reload EEPROM for MAC Address + */ + jme_reset_mac_processor(jme); + rc = jme_reload_eeprom(jme); + if (rc) { + jeprintk(pdev, + "Reload eeprom for reading MAC Address error.\n"); + goto err_out_free_shadow; + } + jme_load_macaddr(netdev); + + /* + * Tell stack that we are not ready to work until open() + */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + /* + * Register netdev + */ + rc = register_netdev(netdev); + if (rc) { + jeprintk(pdev, "Cannot register net device.\n"); + goto err_out_free_shadow; + } + + msg_probe(jme, + "JMC250 gigabit%s ver:%x rev:%x " + "macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + (jme->fpgaver != 0) ? " (FPGA)" : "", + (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev, + jme->rev, + netdev->dev_addr[0], + netdev->dev_addr[1], + netdev->dev_addr[2], + netdev->dev_addr[3], + netdev->dev_addr[4], + netdev->dev_addr[5]); + + return 0; + +err_out_free_shadow: + pci_free_consistent(pdev, + sizeof(u32) * SHADOW_REG_NR, + jme->shadow_regs, + jme->shadow_dma); +err_out_unmap: + iounmap(jme->regs); +err_out_free_netdev: + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); +err_out_release_regions: + pci_release_regions(pdev); +err_out_disable_pdev: + pci_disable_device(pdev); +err_out: + return rc; +} + +static void __devexit +jme_remove_one(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct jme_adapter *jme = netdev_priv(netdev); + + unregister_netdev(netdev); + pci_free_consistent(pdev, + sizeof(u32) * SHADOW_REG_NR, + jme->shadow_regs, + jme->shadow_dma); + iounmap(jme->regs); + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); + pci_release_regions(pdev); + pci_disable_device(pdev); + +} + +#ifdef CONFIG_PM +static int +jme_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct jme_adapter *jme = netdev_priv(netdev); + + atomic_dec(&jme->link_changing); + + netif_device_detach(netdev); + netif_stop_queue(netdev); + jme_stop_irq(jme); + + tasklet_disable(&jme->txclean_task); + tasklet_disable(&jme->rxclean_task); + tasklet_disable(&jme->rxempty_task); + + jme_disable_shadow(jme); + + if (netif_carrier_ok(netdev)) { + if (test_bit(JME_FLAG_POLL, &jme->flags)) + jme_polling_mode(jme); + + jme_stop_pcc_timer(jme); + jme_reset_ghc_speed(jme); + jme_disable_rx_engine(jme); + jme_disable_tx_engine(jme); + jme_reset_mac_processor(jme); + jme_free_rx_resources(jme); + jme_free_tx_resources(jme); + netif_carrier_off(netdev); + jme->phylink = 0; + } + + tasklet_enable(&jme->txclean_task); + tasklet_hi_enable(&jme->rxclean_task); + tasklet_hi_enable(&jme->rxempty_task); + + pci_save_state(pdev); + if (jme->reg_pmcs) { + jme_set_100m_half(jme); + + if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN)) + jme_wait_link(jme); + + jwrite32(jme, JME_PMCS, jme->reg_pmcs); + + pci_enable_wake(pdev, PCI_D3cold, true); + } else { + jme_phy_off(jme); + } + pci_set_power_state(pdev, PCI_D3cold); + + return 0; +} + +static int +jme_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct jme_adapter *jme = netdev_priv(netdev); + + jme_clear_pm(jme); + pci_restore_state(pdev); + + if (test_bit(JME_FLAG_SSET, &jme->flags)) + jme_set_settings(netdev, &jme->old_ecmd); + else + jme_reset_phy_processor(jme); + + jme_enable_shadow(jme); + jme_start_irq(jme); + netif_device_attach(netdev); + + atomic_inc(&jme->link_changing); + + jme_reset_link(jme); + + return 0; +} +#endif + +static struct pci_device_id jme_pci_tbl[] = { + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC250) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC260) }, + { } +}; + +static struct pci_driver jme_driver = { + .name = DRV_NAME, + .id_table = jme_pci_tbl, + .probe = jme_init_one, + .remove = __devexit_p(jme_remove_one), +#ifdef CONFIG_PM + .suspend = jme_suspend, + .resume = jme_resume, +#endif /* CONFIG_PM */ +}; + +static int __init +jme_init_module(void) +{ + printk(KERN_INFO PFX "JMicron JMC250 gigabit ethernet " + "driver version %s\n", DRV_VERSION); + return pci_register_driver(&jme_driver); +} + +static void __exit +jme_cleanup_module(void) +{ + pci_unregister_driver(&jme_driver); +} + +module_init(jme_init_module); +module_exit(jme_cleanup_module); + +MODULE_AUTHOR("Guo-Fu Tseng <cooldavid@cooldavid.org>"); +MODULE_DESCRIPTION("JMicron JMC2x0 PCI Express Ethernet driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_DEVICE_TABLE(pci, jme_pci_tbl); + diff --git a/drivers/net/jme.h b/drivers/net/jme.h new file mode 100644 index 00000000000..f863aee6648 --- /dev/null +++ b/drivers/net/jme.h @@ -0,0 +1,1229 @@ +/* + * JMicron JMC2x0 series PCIe Ethernet Linux Device Driver + * + * Copyright 2008 JMicron Technology Corporation + * http://www.jmicron.com/ + * + * Author: Guo-Fu Tseng <cooldavid@cooldavid.org> + * + * 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. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __JME_H_INCLUDED__ +#define __JME_H_INCLUDEE__ + +#define DRV_NAME "jme" +#define DRV_VERSION "1.0.3" +#define PFX DRV_NAME ": " + +#define PCI_DEVICE_ID_JMICRON_JMC250 0x0250 +#define PCI_DEVICE_ID_JMICRON_JMC260 0x0260 + +/* + * Message related definitions + */ +#define JME_DEF_MSG_ENABLE \ + (NETIF_MSG_PROBE | \ + NETIF_MSG_LINK | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR | \ + NETIF_MSG_HW) + +#define jeprintk(pdev, fmt, args...) \ + printk(KERN_ERR PFX fmt, ## args) + +#ifdef TX_DEBUG +#define tx_dbg(priv, fmt, args...) \ + printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ## args) +#else +#define tx_dbg(priv, fmt, args...) +#endif + +#define jme_msg(msglvl, type, priv, fmt, args...) \ + if (netif_msg_##type(priv)) \ + printk(msglvl "%s: " fmt, (priv)->dev->name, ## args) + +#define msg_probe(priv, fmt, args...) \ + jme_msg(KERN_INFO, probe, priv, fmt, ## args) + +#define msg_link(priv, fmt, args...) \ + jme_msg(KERN_INFO, link, priv, fmt, ## args) + +#define msg_intr(priv, fmt, args...) \ + jme_msg(KERN_INFO, intr, priv, fmt, ## args) + +#define msg_rx_err(priv, fmt, args...) \ + jme_msg(KERN_ERR, rx_err, priv, fmt, ## args) + +#define msg_rx_status(priv, fmt, args...) \ + jme_msg(KERN_INFO, rx_status, priv, fmt, ## args) + +#define msg_tx_err(priv, fmt, args...) \ + jme_msg(KERN_ERR, tx_err, priv, fmt, ## args) + +#define msg_tx_done(priv, fmt, args...) \ + jme_msg(KERN_INFO, tx_done, priv, fmt, ## args) + +#define msg_tx_queued(priv, fmt, args...) \ + jme_msg(KERN_INFO, tx_queued, priv, fmt, ## args) + +#define msg_hw(priv, fmt, args...) \ + jme_msg(KERN_ERR, hw, priv, fmt, ## args) + +/* + * Extra PCI Configuration space interface + */ +#define PCI_DCSR_MRRS 0x59 +#define PCI_DCSR_MRRS_MASK 0x70 + +enum pci_dcsr_mrrs_vals { + MRRS_128B = 0x00, + MRRS_256B = 0x10, + MRRS_512B = 0x20, + MRRS_1024B = 0x30, + MRRS_2048B = 0x40, + MRRS_4096B = 0x50, +}; + +#define PCI_SPI 0xB0 + +enum pci_spi_bits { + SPI_EN = 0x10, + SPI_MISO = 0x08, + SPI_MOSI = 0x04, + SPI_SCLK = 0x02, + SPI_CS = 0x01, +}; + +struct jme_spi_op { + void __user *uwbuf; + void __user *urbuf; + __u8 wn; /* Number of write actions */ + __u8 rn; /* Number of read actions */ + __u8 bitn; /* Number of bits per action */ + __u8 spd; /* The maxim acceptable speed of controller, in MHz.*/ + __u8 mode; /* CPOL, CPHA, and Duplex mode of SPI */ + + /* Internal use only */ + u8 *kwbuf; + u8 *krbuf; + u8 sr; + u16 halfclk; /* Half of clock cycle calculated from spd, in ns */ +}; + +enum jme_spi_op_bits { + SPI_MODE_CPHA = 0x01, + SPI_MODE_CPOL = 0x02, + SPI_MODE_DUP = 0x80, +}; + +#define HALF_US 500 /* 500 ns */ +#define JMESPIIOCTL SIOCDEVPRIVATE + +/* + * Dynamic(adaptive)/Static PCC values + */ +enum dynamic_pcc_values { + PCC_OFF = 0, + PCC_P1 = 1, + PCC_P2 = 2, + PCC_P3 = 3, + + PCC_OFF_TO = 0, + PCC_P1_TO = 1, + PCC_P2_TO = 64, + PCC_P3_TO = 128, + + PCC_OFF_CNT = 0, + PCC_P1_CNT = 1, + PCC_P2_CNT = 16, + PCC_P3_CNT = 32, +}; +struct dynpcc_info { + unsigned long last_bytes; + unsigned long last_pkts; + unsigned long intr_cnt; + unsigned char cur; + unsigned char attempt; + unsigned char cnt; +}; +#define PCC_INTERVAL_US 100000 +#define PCC_INTERVAL (HZ / (1000000 / PCC_INTERVAL_US)) +#define PCC_P3_THRESHOLD (2 * 1024 * 1024) +#define PCC_P2_THRESHOLD 800 +#define PCC_INTR_THRESHOLD 800 +#define PCC_TX_TO 1000 +#define PCC_TX_CNT 8 + +/* + * TX/RX Descriptors + * + * TX/RX Ring DESC Count Must be multiple of 16 and <= 1024 + */ +#define RING_DESC_ALIGN 16 /* Descriptor alignment */ +#define TX_DESC_SIZE 16 +#define TX_RING_NR 8 +#define TX_RING_ALLOC_SIZE(s) ((s * TX_DESC_SIZE) + RING_DESC_ALIGN) + +struct txdesc { + union { + __u8 all[16]; + __le32 dw[4]; + struct { + /* DW0 */ + __le16 vlan; + __u8 rsv1; + __u8 flags; + + /* DW1 */ + __le16 datalen; + __le16 mss; + + /* DW2 */ + __le16 pktsize; + __le16 rsv2; + + /* DW3 */ + __le32 bufaddr; + } desc1; + struct { + /* DW0 */ + __le16 rsv1; + __u8 rsv2; + __u8 flags; + + /* DW1 */ + __le16 datalen; + __le16 rsv3; + + /* DW2 */ + __le32 bufaddrh; + + /* DW3 */ + __le32 bufaddrl; + } desc2; + struct { + /* DW0 */ + __u8 ehdrsz; + __u8 rsv1; + __u8 rsv2; + __u8 flags; + + /* DW1 */ + __le16 trycnt; + __le16 segcnt; + + /* DW2 */ + __le16 pktsz; + __le16 rsv3; + + /* DW3 */ + __le32 bufaddrl; + } descwb; + }; +}; + +enum jme_txdesc_flags_bits { + TXFLAG_OWN = 0x80, + TXFLAG_INT = 0x40, + TXFLAG_64BIT = 0x20, + TXFLAG_TCPCS = 0x10, + TXFLAG_UDPCS = 0x08, + TXFLAG_IPCS = 0x04, + TXFLAG_LSEN = 0x02, + TXFLAG_TAGON = 0x01, +}; + +#define TXDESC_MSS_SHIFT 2 +enum jme_rxdescwb_flags_bits { + TXWBFLAG_OWN = 0x80, + TXWBFLAG_INT = 0x40, + TXWBFLAG_TMOUT = 0x20, + TXWBFLAG_TRYOUT = 0x10, + TXWBFLAG_COL = 0x08, + + TXWBFLAG_ALLERR = TXWBFLAG_TMOUT | + TXWBFLAG_TRYOUT | + TXWBFLAG_COL, +}; + +#define RX_DESC_SIZE 16 +#define RX_RING_NR 4 +#define RX_RING_ALLOC_SIZE(s) ((s * RX_DESC_SIZE) + RING_DESC_ALIGN) +#define RX_BUF_DMA_ALIGN 8 +#define RX_PREPAD_SIZE 10 +#define ETH_CRC_LEN 2 +#define RX_VLANHDR_LEN 2 +#define RX_EXTRA_LEN (RX_PREPAD_SIZE + \ + ETH_HLEN + \ + ETH_CRC_LEN + \ + RX_VLANHDR_LEN + \ + RX_BUF_DMA_ALIGN) + +struct rxdesc { + union { + __u8 all[16]; + __le32 dw[4]; + struct { + /* DW0 */ + __le16 rsv2; + __u8 rsv1; + __u8 flags; + + /* DW1 */ + __le16 datalen; + __le16 wbcpl; + + /* DW2 */ + __le32 bufaddrh; + + /* DW3 */ + __le32 bufaddrl; + } desc1; + struct { + /* DW0 */ + __le16 vlan; + __le16 flags; + + /* DW1 */ + __le16 framesize; + __u8 errstat; + __u8 desccnt; + + /* DW2 */ + __le32 rsshash; + + /* DW3 */ + __u8 hashfun; + __u8 hashtype; + __le16 resrv; + } descwb; + }; +}; + +enum jme_rxdesc_flags_bits { + RXFLAG_OWN = 0x80, + RXFLAG_INT = 0x40, + RXFLAG_64BIT = 0x20, +}; + +enum jme_rxwbdesc_flags_bits { + RXWBFLAG_OWN = 0x8000, + RXWBFLAG_INT = 0x4000, + RXWBFLAG_MF = 0x2000, + RXWBFLAG_64BIT = 0x2000, + RXWBFLAG_TCPON = 0x1000, + RXWBFLAG_UDPON = 0x0800, + RXWBFLAG_IPCS = 0x0400, + RXWBFLAG_TCPCS = 0x0200, + RXWBFLAG_UDPCS = 0x0100, + RXWBFLAG_TAGON = 0x0080, + RXWBFLAG_IPV4 = 0x0040, + RXWBFLAG_IPV6 = 0x0020, + RXWBFLAG_PAUSE = 0x0010, + RXWBFLAG_MAGIC = 0x0008, + RXWBFLAG_WAKEUP = 0x0004, + RXWBFLAG_DEST = 0x0003, + RXWBFLAG_DEST_UNI = 0x0001, + RXWBFLAG_DEST_MUL = 0x0002, + RXWBFLAG_DEST_BRO = 0x0003, +}; + +enum jme_rxwbdesc_desccnt_mask { + RXWBDCNT_WBCPL = 0x80, + RXWBDCNT_DCNT = 0x7F, +}; + +enum jme_rxwbdesc_errstat_bits { + RXWBERR_LIMIT = 0x80, + RXWBERR_MIIER = 0x40, + RXWBERR_NIBON = 0x20, + RXWBERR_COLON = 0x10, + RXWBERR_ABORT = 0x08, + RXWBERR_SHORT = 0x04, + RXWBERR_OVERUN = 0x02, + RXWBERR_CRCERR = 0x01, + RXWBERR_ALLERR = 0xFF, +}; + +/* + * Buffer information corresponding to ring descriptors. + */ +struct jme_buffer_info { + struct sk_buff *skb; + dma_addr_t mapping; + int len; + int nr_desc; + unsigned long start_xmit; +}; + +/* + * The structure holding buffer information and ring descriptors all together. + */ +#define MAX_RING_DESC_NR 1024 +struct jme_ring { + void *alloc; /* pointer to allocated memory */ + void *desc; /* pointer to ring memory */ + dma_addr_t dmaalloc; /* phys address of ring alloc */ + dma_addr_t dma; /* phys address for ring dma */ + + /* Buffer information corresponding to each descriptor */ + struct jme_buffer_info bufinf[MAX_RING_DESC_NR]; + + int next_to_use; + atomic_t next_to_clean; + atomic_t nr_free; +}; + +#define NET_STAT(priv) (priv->dev->stats) +#define NETDEV_GET_STATS(netdev, fun_ptr) +#define DECLARE_NET_DEVICE_STATS + +#define DECLARE_NAPI_STRUCT struct napi_struct napi; +#define NETIF_NAPI_SET(dev, napis, pollfn, q) \ + netif_napi_add(dev, napis, pollfn, q); +#define JME_NAPI_HOLDER(holder) struct napi_struct *holder +#define JME_NAPI_WEIGHT(w) int w +#define JME_NAPI_WEIGHT_VAL(w) w +#define JME_NAPI_WEIGHT_SET(w, r) +#define JME_RX_COMPLETE(dev, napis) netif_rx_complete(dev, napis) +#define JME_NAPI_ENABLE(priv) napi_enable(&priv->napi); +#define JME_NAPI_DISABLE(priv) \ + if (!napi_disable_pending(&priv->napi)) \ + napi_disable(&priv->napi); +#define JME_RX_SCHEDULE_PREP(priv) \ + netif_rx_schedule_prep(priv->dev, &priv->napi) +#define JME_RX_SCHEDULE(priv) \ + __netif_rx_schedule(priv->dev, &priv->napi); + +/* + * Jmac Adapter Private data + */ +#define SHADOW_REG_NR 8 +struct jme_adapter { + struct pci_dev *pdev; + struct net_device *dev; + void __iomem *regs; + dma_addr_t shadow_dma; + u32 *shadow_regs; + struct mii_if_info mii_if; + struct jme_ring rxring[RX_RING_NR]; + struct jme_ring txring[TX_RING_NR]; + spinlock_t phy_lock; + spinlock_t macaddr_lock; + spinlock_t rxmcs_lock; + struct tasklet_struct rxempty_task; + struct tasklet_struct rxclean_task; + struct tasklet_struct txclean_task; + struct tasklet_struct linkch_task; + struct tasklet_struct pcc_task; + unsigned long flags; + u32 reg_txcs; + u32 reg_txpfc; + u32 reg_rxcs; + u32 reg_rxmcs; + u32 reg_ghc; + u32 reg_pmcs; + u32 phylink; + u32 tx_ring_size; + u32 tx_ring_mask; + u32 tx_wake_threshold; + u32 rx_ring_size; + u32 rx_ring_mask; + u8 mrrs; + unsigned int fpgaver; + unsigned int chiprev; + u8 rev; + u32 msg_enable; + struct ethtool_cmd old_ecmd; + unsigned int old_mtu; + struct vlan_group *vlgrp; + struct dynpcc_info dpi; + atomic_t intr_sem; + atomic_t link_changing; + atomic_t tx_cleaning; + atomic_t rx_cleaning; + atomic_t rx_empty; + int (*jme_rx)(struct sk_buff *skb); + int (*jme_vlan_rx)(struct sk_buff *skb, + struct vlan_group *grp, + unsigned short vlan_tag); + DECLARE_NAPI_STRUCT + DECLARE_NET_DEVICE_STATS +}; + +enum shadow_reg_val { + SHADOW_IEVE = 0, +}; + +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, +}; + +#define TX_TIMEOUT (5 * HZ) +#define JME_REG_LEN 0x500 +#define MAX_ETHERNET_JUMBO_PACKET_SIZE 9216 + +static inline struct jme_adapter* +jme_napi_priv(struct napi_struct *napi) +{ + struct jme_adapter *jme; + jme = container_of(napi, struct jme_adapter, napi); + return jme; +} + +/* + * MMaped I/O Resters + */ +enum jme_iomap_offsets { + JME_MAC = 0x0000, + JME_PHY = 0x0400, + JME_MISC = 0x0800, + JME_RSS = 0x0C00, +}; + +enum jme_iomap_lens { + JME_MAC_LEN = 0x80, + JME_PHY_LEN = 0x58, + JME_MISC_LEN = 0x98, + JME_RSS_LEN = 0xFF, +}; + +enum jme_iomap_regs { + JME_TXCS = JME_MAC | 0x00, /* Transmit Control and Status */ + JME_TXDBA_LO = JME_MAC | 0x04, /* Transmit Queue Desc Base Addr */ + JME_TXDBA_HI = JME_MAC | 0x08, /* Transmit Queue Desc Base Addr */ + JME_TXQDC = JME_MAC | 0x0C, /* Transmit Queue Desc Count */ + JME_TXNDA = JME_MAC | 0x10, /* Transmit Queue Next Desc Addr */ + JME_TXMCS = JME_MAC | 0x14, /* Transmit MAC Control Status */ + JME_TXPFC = JME_MAC | 0x18, /* Transmit Pause Frame Control */ + JME_TXTRHD = JME_MAC | 0x1C, /* Transmit Timer/Retry@Half-Dup */ + + JME_RXCS = JME_MAC | 0x20, /* Receive Control and Status */ + JME_RXDBA_LO = JME_MAC | 0x24, /* Receive Queue Desc Base Addr */ + JME_RXDBA_HI = JME_MAC | 0x28, /* Receive Queue Desc Base Addr */ + JME_RXQDC = JME_MAC | 0x2C, /* Receive Queue Desc Count */ + JME_RXNDA = JME_MAC | 0x30, /* Receive Queue Next Desc Addr */ + JME_RXMCS = JME_MAC | 0x34, /* Receive MAC Control Status */ + JME_RXUMA_LO = JME_MAC | 0x38, /* Receive Unicast MAC Address */ + JME_RXUMA_HI = JME_MAC | 0x3C, /* Receive Unicast MAC Address */ + JME_RXMCHT_LO = JME_MAC | 0x40, /* Recv Multicast Addr HashTable */ + JME_RXMCHT_HI = JME_MAC | 0x44, /* Recv Multicast Addr HashTable */ + JME_WFODP = JME_MAC | 0x48, /* Wakeup Frame Output Data Port */ + JME_WFOI = JME_MAC | 0x4C, /* Wakeup Frame Output Interface */ + + JME_SMI = JME_MAC | 0x50, /* Station Management Interface */ + JME_GHC = JME_MAC | 0x54, /* Global Host Control */ + JME_PMCS = JME_MAC | 0x60, /* Power Management Control/Stat */ + + + JME_PHY_CS = JME_PHY | 0x28, /* PHY Ctrl and Status Register */ + JME_PHY_LINK = JME_PHY | 0x30, /* PHY Link Status Register */ + JME_SMBCSR = JME_PHY | 0x40, /* SMB Control and Status */ + JME_SMBINTF = JME_PHY | 0x44, /* SMB Interface */ + + + JME_TMCSR = JME_MISC | 0x00, /* Timer Control/Status Register */ + JME_GPREG0 = JME_MISC | 0x08, /* General purpose REG-0 */ + JME_GPREG1 = JME_MISC | 0x0C, /* General purpose REG-1 */ + JME_IEVE = JME_MISC | 0x20, /* Interrupt Event Status */ + JME_IREQ = JME_MISC | 0x24, /* Intr Req Status(For Debug) */ + JME_IENS = JME_MISC | 0x28, /* Intr Enable - Setting Port */ + JME_IENC = JME_MISC | 0x2C, /* Interrupt Enable - Clear Port */ + JME_PCCRX0 = JME_MISC | 0x30, /* PCC Control for RX Queue 0 */ + JME_PCCTX = JME_MISC | 0x40, /* PCC Control for TX Queues */ + JME_CHIPMODE = JME_MISC | 0x44, /* Identify FPGA Version */ + JME_SHBA_HI = JME_MISC | 0x48, /* Shadow Register Base HI */ + JME_SHBA_LO = JME_MISC | 0x4C, /* Shadow Register Base LO */ + JME_TIMER1 = JME_MISC | 0x70, /* Timer1 */ + JME_TIMER2 = JME_MISC | 0x74, /* Timer2 */ + JME_APMC = JME_MISC | 0x7C, /* Aggressive Power Mode Control */ + JME_PCCSRX0 = JME_MISC | 0x80, /* PCC Status of RX0 */ +}; + +/* + * TX Control/Status Bits + */ +enum jme_txcs_bits { + TXCS_QUEUE7S = 0x00008000, + TXCS_QUEUE6S = 0x00004000, + TXCS_QUEUE5S = 0x00002000, + TXCS_QUEUE4S = 0x00001000, + TXCS_QUEUE3S = 0x00000800, + TXCS_QUEUE2S = 0x00000400, + TXCS_QUEUE1S = 0x00000200, + TXCS_QUEUE0S = 0x00000100, + TXCS_FIFOTH = 0x000000C0, + TXCS_DMASIZE = 0x00000030, + TXCS_BURST = 0x00000004, + TXCS_ENABLE = 0x00000001, +}; + +enum jme_txcs_value { + TXCS_FIFOTH_16QW = 0x000000C0, + TXCS_FIFOTH_12QW = 0x00000080, + TXCS_FIFOTH_8QW = 0x00000040, + TXCS_FIFOTH_4QW = 0x00000000, + + TXCS_DMASIZE_64B = 0x00000000, + TXCS_DMASIZE_128B = 0x00000010, + TXCS_DMASIZE_256B = 0x00000020, + TXCS_DMASIZE_512B = 0x00000030, + + TXCS_SELECT_QUEUE0 = 0x00000000, + TXCS_SELECT_QUEUE1 = 0x00010000, + TXCS_SELECT_QUEUE2 = 0x00020000, + TXCS_SELECT_QUEUE3 = 0x00030000, + TXCS_SELECT_QUEUE4 = 0x00040000, + TXCS_SELECT_QUEUE5 = 0x00050000, + TXCS_SELECT_QUEUE6 = 0x00060000, + TXCS_SELECT_QUEUE7 = 0x00070000, + + TXCS_DEFAULT = TXCS_FIFOTH_4QW | + TXCS_BURST, +}; + +#define JME_TX_DISABLE_TIMEOUT 10 /* 10 msec */ + +/* + * TX MAC Control/Status Bits + */ +enum jme_txmcs_bit_masks { + TXMCS_IFG2 = 0xC0000000, + TXMCS_IFG1 = 0x30000000, + TXMCS_TTHOLD = 0x00000300, + TXMCS_FBURST = 0x00000080, + TXMCS_CARRIEREXT = 0x00000040, + TXMCS_DEFER = 0x00000020, + TXMCS_BACKOFF = 0x00000010, + TXMCS_CARRIERSENSE = 0x00000008, + TXMCS_COLLISION = 0x00000004, + TXMCS_CRC = 0x00000002, + TXMCS_PADDING = 0x00000001, +}; + +enum jme_txmcs_values { + TXMCS_IFG2_6_4 = 0x00000000, + TXMCS_IFG2_8_5 = 0x40000000, + TXMCS_IFG2_10_6 = 0x80000000, + TXMCS_IFG2_12_7 = 0xC0000000, + + TXMCS_IFG1_8_4 = 0x00000000, + TXMCS_IFG1_12_6 = 0x10000000, + TXMCS_IFG1_16_8 = 0x20000000, + TXMCS_IFG1_20_10 = 0x30000000, + + TXMCS_TTHOLD_1_8 = 0x00000000, + TXMCS_TTHOLD_1_4 = 0x00000100, + TXMCS_TTHOLD_1_2 = 0x00000200, + TXMCS_TTHOLD_FULL = 0x00000300, + + TXMCS_DEFAULT = TXMCS_IFG2_8_5 | + TXMCS_IFG1_16_8 | + TXMCS_TTHOLD_FULL | + TXMCS_DEFER | + TXMCS_CRC | + TXMCS_PADDING, +}; + +enum jme_txpfc_bits_masks { + TXPFC_VLAN_TAG = 0xFFFF0000, + TXPFC_VLAN_EN = 0x00008000, + TXPFC_PF_EN = 0x00000001, +}; + +enum jme_txtrhd_bits_masks { + TXTRHD_TXPEN = 0x80000000, + TXTRHD_TXP = 0x7FFFFF00, + TXTRHD_TXREN = 0x00000080, + TXTRHD_TXRL = 0x0000007F, +}; + +enum jme_txtrhd_shifts { + TXTRHD_TXP_SHIFT = 8, + TXTRHD_TXRL_SHIFT = 0, +}; + +/* + * RX Control/Status Bits + */ +enum jme_rxcs_bit_masks { + /* FIFO full threshold for transmitting Tx Pause Packet */ + RXCS_FIFOTHTP = 0x30000000, + /* FIFO threshold for processing next packet */ + RXCS_FIFOTHNP = 0x0C000000, + RXCS_DMAREQSZ = 0x03000000, /* DMA Request Size */ + RXCS_QUEUESEL = 0x00030000, /* Queue selection */ + RXCS_RETRYGAP = 0x0000F000, /* RX Desc full retry gap */ + RXCS_RETRYCNT = 0x00000F00, /* RX Desc full retry counter */ + RXCS_WAKEUP = 0x00000040, /* Enable receive wakeup packet */ + RXCS_MAGIC = 0x00000020, /* Enable receive magic packet */ + RXCS_SHORT = 0x00000010, /* Enable receive short packet */ + RXCS_ABORT = 0x00000008, /* Enable receive errorr packet */ + RXCS_QST = 0x00000004, /* Receive queue start */ + RXCS_SUSPEND = 0x00000002, + RXCS_ENABLE = 0x00000001, +}; + +enum jme_rxcs_values { + RXCS_FIFOTHTP_16T = 0x00000000, + RXCS_FIFOTHTP_32T = 0x10000000, + RXCS_FIFOTHTP_64T = 0x20000000, + RXCS_FIFOTHTP_128T = 0x30000000, + + RXCS_FIFOTHNP_16QW = 0x00000000, + RXCS_FIFOTHNP_32QW = 0x04000000, + RXCS_FIFOTHNP_64QW = 0x08000000, + RXCS_FIFOTHNP_128QW = 0x0C000000, + + RXCS_DMAREQSZ_16B = 0x00000000, + RXCS_DMAREQSZ_32B = 0x01000000, + RXCS_DMAREQSZ_64B = 0x02000000, + RXCS_DMAREQSZ_128B = 0x03000000, + + RXCS_QUEUESEL_Q0 = 0x00000000, + RXCS_QUEUESEL_Q1 = 0x00010000, + RXCS_QUEUESEL_Q2 = 0x00020000, + RXCS_QUEUESEL_Q3 = 0x00030000, + + RXCS_RETRYGAP_256ns = 0x00000000, + RXCS_RETRYGAP_512ns = 0x00001000, + RXCS_RETRYGAP_1024ns = 0x00002000, + RXCS_RETRYGAP_2048ns = 0x00003000, + RXCS_RETRYGAP_4096ns = 0x00004000, + RXCS_RETRYGAP_8192ns = 0x00005000, + RXCS_RETRYGAP_16384ns = 0x00006000, + RXCS_RETRYGAP_32768ns = 0x00007000, + + RXCS_RETRYCNT_0 = 0x00000000, + RXCS_RETRYCNT_4 = 0x00000100, + RXCS_RETRYCNT_8 = 0x00000200, + RXCS_RETRYCNT_12 = 0x00000300, + RXCS_RETRYCNT_16 = 0x00000400, + RXCS_RETRYCNT_20 = 0x00000500, + RXCS_RETRYCNT_24 = 0x00000600, + RXCS_RETRYCNT_28 = 0x00000700, + RXCS_RETRYCNT_32 = 0x00000800, + RXCS_RETRYCNT_36 = 0x00000900, + RXCS_RETRYCNT_40 = 0x00000A00, + RXCS_RETRYCNT_44 = 0x00000B00, + RXCS_RETRYCNT_48 = 0x00000C00, + RXCS_RETRYCNT_52 = 0x00000D00, + RXCS_RETRYCNT_56 = 0x00000E00, + RXCS_RETRYCNT_60 = 0x00000F00, + + RXCS_DEFAULT = RXCS_FIFOTHTP_128T | + RXCS_FIFOTHNP_128QW | + RXCS_DMAREQSZ_128B | + RXCS_RETRYGAP_256ns | + RXCS_RETRYCNT_32, +}; + +#define JME_RX_DISABLE_TIMEOUT 10 /* 10 msec */ + +/* + * RX MAC Control/Status Bits + */ +enum jme_rxmcs_bits { + RXMCS_ALLFRAME = 0x00000800, + RXMCS_BRDFRAME = 0x00000400, + RXMCS_MULFRAME = 0x00000200, + RXMCS_UNIFRAME = 0x00000100, + RXMCS_ALLMULFRAME = 0x00000080, + RXMCS_MULFILTERED = 0x00000040, + RXMCS_RXCOLLDEC = 0x00000020, + RXMCS_FLOWCTRL = 0x00000008, + RXMCS_VTAGRM = 0x00000004, + RXMCS_PREPAD = 0x00000002, + RXMCS_CHECKSUM = 0x00000001, + + RXMCS_DEFAULT = RXMCS_VTAGRM | + RXMCS_PREPAD | + RXMCS_FLOWCTRL | + RXMCS_CHECKSUM, +}; + +/* + * Wakeup Frame setup interface registers + */ +#define WAKEUP_FRAME_NR 8 +#define WAKEUP_FRAME_MASK_DWNR 4 + +enum jme_wfoi_bit_masks { + WFOI_MASK_SEL = 0x00000070, + WFOI_CRC_SEL = 0x00000008, + WFOI_FRAME_SEL = 0x00000007, +}; + +enum jme_wfoi_shifts { + WFOI_MASK_SHIFT = 4, +}; + +/* + * SMI Related definitions + */ +enum jme_smi_bit_mask { + SMI_DATA_MASK = 0xFFFF0000, + SMI_REG_ADDR_MASK = 0x0000F800, + SMI_PHY_ADDR_MASK = 0x000007C0, + SMI_OP_WRITE = 0x00000020, + /* Set to 1, after req done it'll be cleared to 0 */ + SMI_OP_REQ = 0x00000010, + SMI_OP_MDIO = 0x00000008, /* Software assess In/Out */ + SMI_OP_MDOE = 0x00000004, /* Software Output Enable */ + SMI_OP_MDC = 0x00000002, /* Software CLK Control */ + SMI_OP_MDEN = 0x00000001, /* Software access Enable */ +}; + +enum jme_smi_bit_shift { + SMI_DATA_SHIFT = 16, + SMI_REG_ADDR_SHIFT = 11, + SMI_PHY_ADDR_SHIFT = 6, +}; + +static inline u32 smi_reg_addr(int x) +{ + return (x << SMI_REG_ADDR_SHIFT) & SMI_REG_ADDR_MASK; +} + +static inline u32 smi_phy_addr(int x) +{ + return (x << SMI_PHY_ADDR_SHIFT) & SMI_PHY_ADDR_MASK; +} + +#define JME_PHY_TIMEOUT 100 /* 100 msec */ +#define JME_PHY_REG_NR 32 + +/* + * Global Host Control + */ +enum jme_ghc_bit_mask { + GHC_SWRST = 0x40000000, + GHC_DPX = 0x00000040, + GHC_SPEED = 0x00000030, + GHC_LINK_POLL = 0x00000001, +}; + +enum jme_ghc_speed_val { + GHC_SPEED_10M = 0x00000010, + GHC_SPEED_100M = 0x00000020, + GHC_SPEED_1000M = 0x00000030, +}; + +/* + * Power management control and status register + */ +enum jme_pmcs_bit_masks { + PMCS_WF7DET = 0x80000000, + PMCS_WF6DET = 0x40000000, + PMCS_WF5DET = 0x20000000, + PMCS_WF4DET = 0x10000000, + PMCS_WF3DET = 0x08000000, + PMCS_WF2DET = 0x04000000, + PMCS_WF1DET = 0x02000000, + PMCS_WF0DET = 0x01000000, + PMCS_LFDET = 0x00040000, + PMCS_LRDET = 0x00020000, + PMCS_MFDET = 0x00010000, + PMCS_WF7EN = 0x00008000, + PMCS_WF6EN = 0x00004000, + PMCS_WF5EN = 0x00002000, + PMCS_WF4EN = 0x00001000, + PMCS_WF3EN = 0x00000800, + PMCS_WF2EN = 0x00000400, + PMCS_WF1EN = 0x00000200, + PMCS_WF0EN = 0x00000100, + PMCS_LFEN = 0x00000004, + PMCS_LREN = 0x00000002, + PMCS_MFEN = 0x00000001, +}; + +/* + * Giga PHY Status Registers + */ +enum jme_phy_link_bit_mask { + PHY_LINK_SPEED_MASK = 0x0000C000, + PHY_LINK_DUPLEX = 0x00002000, + PHY_LINK_SPEEDDPU_RESOLVED = 0x00000800, + PHY_LINK_UP = 0x00000400, + PHY_LINK_AUTONEG_COMPLETE = 0x00000200, + PHY_LINK_MDI_STAT = 0x00000040, +}; + +enum jme_phy_link_speed_val { + PHY_LINK_SPEED_10M = 0x00000000, + PHY_LINK_SPEED_100M = 0x00004000, + PHY_LINK_SPEED_1000M = 0x00008000, +}; + +#define JME_SPDRSV_TIMEOUT 500 /* 500 us */ + +/* + * SMB Control and Status + */ +enum jme_smbcsr_bit_mask { + SMBCSR_CNACK = 0x00020000, + SMBCSR_RELOAD = 0x00010000, + SMBCSR_EEPROMD = 0x00000020, + SMBCSR_INITDONE = 0x00000010, + SMBCSR_BUSY = 0x0000000F, +}; + +enum jme_smbintf_bit_mask { + SMBINTF_HWDATR = 0xFF000000, + SMBINTF_HWDATW = 0x00FF0000, + SMBINTF_HWADDR = 0x0000FF00, + SMBINTF_HWRWN = 0x00000020, + SMBINTF_HWCMD = 0x00000010, + SMBINTF_FASTM = 0x00000008, + SMBINTF_GPIOSCL = 0x00000004, + SMBINTF_GPIOSDA = 0x00000002, + SMBINTF_GPIOEN = 0x00000001, +}; + +enum jme_smbintf_vals { + SMBINTF_HWRWN_READ = 0x00000020, + SMBINTF_HWRWN_WRITE = 0x00000000, +}; + +enum jme_smbintf_shifts { + SMBINTF_HWDATR_SHIFT = 24, + SMBINTF_HWDATW_SHIFT = 16, + SMBINTF_HWADDR_SHIFT = 8, +}; + +#define JME_EEPROM_RELOAD_TIMEOUT 2000 /* 2000 msec */ +#define JME_SMB_BUSY_TIMEOUT 20 /* 20 msec */ +#define JME_SMB_LEN 256 +#define JME_EEPROM_MAGIC 0x250 + +/* + * Timer Control/Status Register + */ +enum jme_tmcsr_bit_masks { + TMCSR_SWIT = 0x80000000, + TMCSR_EN = 0x01000000, + TMCSR_CNT = 0x00FFFFFF, +}; + +/* + * General Purpose REG-0 + */ +enum jme_gpreg0_masks { + GPREG0_DISSH = 0xFF000000, + GPREG0_PCIRLMT = 0x00300000, + GPREG0_PCCNOMUTCLR = 0x00040000, + GPREG0_LNKINTPOLL = 0x00001000, + GPREG0_PCCTMR = 0x00000300, + GPREG0_PHYADDR = 0x0000001F, +}; + +enum jme_gpreg0_vals { + GPREG0_DISSH_DW7 = 0x80000000, + GPREG0_DISSH_DW6 = 0x40000000, + GPREG0_DISSH_DW5 = 0x20000000, + GPREG0_DISSH_DW4 = 0x10000000, + GPREG0_DISSH_DW3 = 0x08000000, + GPREG0_DISSH_DW2 = 0x04000000, + GPREG0_DISSH_DW1 = 0x02000000, + GPREG0_DISSH_DW0 = 0x01000000, + GPREG0_DISSH_ALL = 0xFF000000, + + GPREG0_PCIRLMT_8 = 0x00000000, + GPREG0_PCIRLMT_6 = 0x00100000, + GPREG0_PCIRLMT_5 = 0x00200000, + GPREG0_PCIRLMT_4 = 0x00300000, + + GPREG0_PCCTMR_16ns = 0x00000000, + GPREG0_PCCTMR_256ns = 0x00000100, + GPREG0_PCCTMR_1us = 0x00000200, + GPREG0_PCCTMR_1ms = 0x00000300, + + GPREG0_PHYADDR_1 = 0x00000001, + + GPREG0_DEFAULT = GPREG0_PCIRLMT_4 | + GPREG0_PCCTMR_1us | + GPREG0_PHYADDR_1, +}; + +/* + * General Purpose REG-1 + * Note: All theses bits defined here are for + * Chip mode revision 0x11 only + */ +enum jme_gpreg1_masks { + GPREG1_INTRDELAYUNIT = 0x00000018, + GPREG1_INTRDELAYENABLE = 0x00000007, +}; + +enum jme_gpreg1_vals { + GPREG1_RSSPATCH = 0x00000040, + GPREG1_HALFMODEPATCH = 0x00000020, + + GPREG1_INTDLYUNIT_16NS = 0x00000000, + GPREG1_INTDLYUNIT_256NS = 0x00000008, + GPREG1_INTDLYUNIT_1US = 0x00000010, + GPREG1_INTDLYUNIT_16US = 0x00000018, + + GPREG1_INTDLYEN_1U = 0x00000001, + GPREG1_INTDLYEN_2U = 0x00000002, + GPREG1_INTDLYEN_3U = 0x00000003, + GPREG1_INTDLYEN_4U = 0x00000004, + GPREG1_INTDLYEN_5U = 0x00000005, + GPREG1_INTDLYEN_6U = 0x00000006, + GPREG1_INTDLYEN_7U = 0x00000007, + + GPREG1_DEFAULT = 0x00000000, +}; + +/* + * Interrupt Status Bits + */ +enum jme_interrupt_bits { + INTR_SWINTR = 0x80000000, + INTR_TMINTR = 0x40000000, + INTR_LINKCH = 0x20000000, + INTR_PAUSERCV = 0x10000000, + INTR_MAGICRCV = 0x08000000, + INTR_WAKERCV = 0x04000000, + INTR_PCCRX0TO = 0x02000000, + INTR_PCCRX1TO = 0x01000000, + INTR_PCCRX2TO = 0x00800000, + INTR_PCCRX3TO = 0x00400000, + INTR_PCCTXTO = 0x00200000, + INTR_PCCRX0 = 0x00100000, + INTR_PCCRX1 = 0x00080000, + INTR_PCCRX2 = 0x00040000, + INTR_PCCRX3 = 0x00020000, + INTR_PCCTX = 0x00010000, + INTR_RX3EMP = 0x00008000, + INTR_RX2EMP = 0x00004000, + INTR_RX1EMP = 0x00002000, + INTR_RX0EMP = 0x00001000, + INTR_RX3 = 0x00000800, + INTR_RX2 = 0x00000400, + INTR_RX1 = 0x00000200, + INTR_RX0 = 0x00000100, + INTR_TX7 = 0x00000080, + INTR_TX6 = 0x00000040, + INTR_TX5 = 0x00000020, + INTR_TX4 = 0x00000010, + INTR_TX3 = 0x00000008, + INTR_TX2 = 0x00000004, + INTR_TX1 = 0x00000002, + INTR_TX0 = 0x00000001, +}; + +static const u32 INTR_ENABLE = INTR_SWINTR | + INTR_TMINTR | + INTR_LINKCH | + INTR_PCCRX0TO | + INTR_PCCRX0 | + INTR_PCCTXTO | + INTR_PCCTX | + INTR_RX0EMP; + +/* + * PCC Control Registers + */ +enum jme_pccrx_masks { + PCCRXTO_MASK = 0xFFFF0000, + PCCRX_MASK = 0x0000FF00, +}; + +enum jme_pcctx_masks { + PCCTXTO_MASK = 0xFFFF0000, + PCCTX_MASK = 0x0000FF00, + PCCTX_QS_MASK = 0x000000FF, +}; + +enum jme_pccrx_shifts { + PCCRXTO_SHIFT = 16, + PCCRX_SHIFT = 8, +}; + +enum jme_pcctx_shifts { + PCCTXTO_SHIFT = 16, + PCCTX_SHIFT = 8, +}; + +enum jme_pcctx_bits { + PCCTXQ0_EN = 0x00000001, + PCCTXQ1_EN = 0x00000002, + PCCTXQ2_EN = 0x00000004, + PCCTXQ3_EN = 0x00000008, + PCCTXQ4_EN = 0x00000010, + PCCTXQ5_EN = 0x00000020, + PCCTXQ6_EN = 0x00000040, + PCCTXQ7_EN = 0x00000080, +}; + +/* + * Chip Mode Register + */ +enum jme_chipmode_bit_masks { + CM_FPGAVER_MASK = 0xFFFF0000, + CM_CHIPREV_MASK = 0x0000FF00, + CM_CHIPMODE_MASK = 0x0000000F, +}; + +enum jme_chipmode_shifts { + CM_FPGAVER_SHIFT = 16, + CM_CHIPREV_SHIFT = 8, +}; + +/* + * Shadow base address register bits + */ +enum jme_shadow_base_address_bits { + SHBA_POSTEN = 0x1, +}; + +/* + * Aggressive Power Mode Control + */ +enum jme_apmc_bits { + JME_APMC_PCIE_SD_EN = 0x40000000, + JME_APMC_PSEUDO_HP_EN = 0x20000000, + JME_APMC_EPIEN = 0x04000000, + JME_APMC_EPIEN_CTRL = 0x03000000, +}; + +enum jme_apmc_values { + JME_APMC_EPIEN_CTRL_EN = 0x02000000, + JME_APMC_EPIEN_CTRL_DIS = 0x01000000, +}; + +#define APMC_PHP_SHUTDOWN_DELAY (10 * 1000 * 1000) + +#ifdef REG_DEBUG +static char *MAC_REG_NAME[] = { + "JME_TXCS", "JME_TXDBA_LO", "JME_TXDBA_HI", "JME_TXQDC", + "JME_TXNDA", "JME_TXMCS", "JME_TXPFC", "JME_TXTRHD", + "JME_RXCS", "JME_RXDBA_LO", "JME_RXDBA_HI", "JME_RXQDC", + "JME_RXNDA", "JME_RXMCS", "JME_RXUMA_LO", "JME_RXUMA_HI", + "JME_RXMCHT_LO", "JME_RXMCHT_HI", "JME_WFODP", "JME_WFOI", + "JME_SMI", "JME_GHC", "UNKNOWN", "UNKNOWN", + "JME_PMCS"}; + +static char *PE_REG_NAME[] = { + "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", + "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", + "UNKNOWN", "UNKNOWN", "JME_PHY_CS", "UNKNOWN", + "JME_PHY_LINK", "UNKNOWN", "UNKNOWN", "UNKNOWN", + "JME_SMBCSR", "JME_SMBINTF"}; + +static char *MISC_REG_NAME[] = { + "JME_TMCSR", "JME_GPIO", "JME_GPREG0", "JME_GPREG1", + "JME_IEVE", "JME_IREQ", "JME_IENS", "JME_IENC", + "JME_PCCRX0", "JME_PCCRX1", "JME_PCCRX2", "JME_PCCRX3", + "JME_PCCTX0", "JME_CHIPMODE", "JME_SHBA_HI", "JME_SHBA_LO", + "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", + "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", + "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", + "JME_TIMER1", "JME_TIMER2", "UNKNOWN", "JME_APMC", + "JME_PCCSRX0"}; + +static inline void reg_dbg(const struct jme_adapter *jme, + const char *msg, u32 val, u32 reg) +{ + const char *regname; + switch (reg & 0xF00) { + case 0x000: + regname = MAC_REG_NAME[(reg & 0xFF) >> 2]; + break; + case 0x400: + regname = PE_REG_NAME[(reg & 0xFF) >> 2]; + break; + case 0x800: + regname = MISC_REG_NAME[(reg & 0xFF) >> 2]; + break; + default: + regname = PE_REG_NAME[0]; + } + printk(KERN_DEBUG "%s: %-20s %08x@%s\n", jme->dev->name, + msg, val, regname); +} +#else +static inline void reg_dbg(const struct jme_adapter *jme, + const char *msg, u32 val, u32 reg) {} +#endif + +/* + * Read/Write MMaped I/O Registers + */ +static inline u32 jread32(struct jme_adapter *jme, u32 reg) +{ + return readl(jme->regs + reg); +} + +static inline void jwrite32(struct jme_adapter *jme, u32 reg, u32 val) +{ + reg_dbg(jme, "REG WRITE", val, reg); + writel(val, jme->regs + reg); + reg_dbg(jme, "VAL AFTER WRITE", readl(jme->regs + reg), reg); +} + +static inline void jwrite32f(struct jme_adapter *jme, u32 reg, u32 val) +{ + /* + * Read after write should cause flush + */ + reg_dbg(jme, "REG WRITE FLUSH", val, reg); + writel(val, jme->regs + reg); + readl(jme->regs + reg); + reg_dbg(jme, "VAL AFTER WRITE", readl(jme->regs + reg), reg); +} + +/* + * PHY Regs + */ +enum jme_phy_reg17_bit_masks { + PREG17_SPEED = 0xC000, + PREG17_DUPLEX = 0x2000, + PREG17_SPDRSV = 0x0800, + PREG17_LNKUP = 0x0400, + PREG17_MDI = 0x0040, +}; + +enum jme_phy_reg17_vals { + PREG17_SPEED_10M = 0x0000, + PREG17_SPEED_100M = 0x4000, + PREG17_SPEED_1000M = 0x8000, +}; + +#define BMSR_ANCOMP 0x0020 + +/* + * Workaround + */ +static inline int is_buggy250(unsigned short device, unsigned int chiprev) +{ + return device == PCI_DEVICE_ID_JMICRON_JMC250 && chiprev == 0x11; +} + +/* + * Function prototypes + */ +static int jme_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd); +static void jme_set_multi(struct net_device *netdev); + +#endif diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 00d59ab2f8a..f80dcc11fe2 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -530,9 +530,9 @@ static irqreturn_t __ei_interrupt(int irq, void *dev_id) #ifdef CONFIG_NET_POLL_CONTROLLER static void __ei_poll(struct net_device *dev) { - disable_irq_lockdep(dev->irq); + disable_irq(dev->irq); __ei_interrupt(dev->irq, dev); - enable_irq_lockdep(dev->irq); + enable_irq(dev->irq); } #endif diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 84c77f1f9a5..01f7a31bac7 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -195,8 +195,8 @@ static int macb_mii_probe(struct net_device *dev) /* find the first phy */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { - if (bp->mii_bus.phy_map[phy_addr]) { - phydev = bp->mii_bus.phy_map[phy_addr]; + if (bp->mii_bus->phy_map[phy_addr]) { + phydev = bp->mii_bus->phy_map[phy_addr]; break; } } @@ -244,30 +244,36 @@ static int macb_mii_init(struct macb *bp) /* Enable managment port */ macb_writel(bp, NCR, MACB_BIT(MPE)); - bp->mii_bus.name = "MACB_mii_bus"; - bp->mii_bus.read = &macb_mdio_read; - bp->mii_bus.write = &macb_mdio_write; - bp->mii_bus.reset = &macb_mdio_reset; - snprintf(bp->mii_bus.id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); - bp->mii_bus.priv = bp; - bp->mii_bus.dev = &bp->dev->dev; + bp->mii_bus = mdiobus_alloc(); + if (bp->mii_bus == NULL) { + err = -ENOMEM; + goto err_out; + } + + bp->mii_bus->name = "MACB_mii_bus"; + bp->mii_bus->read = &macb_mdio_read; + bp->mii_bus->write = &macb_mdio_write; + bp->mii_bus->reset = &macb_mdio_reset; + snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); + bp->mii_bus->priv = bp; + bp->mii_bus->parent = &bp->dev->dev; pdata = bp->pdev->dev.platform_data; if (pdata) - bp->mii_bus.phy_mask = pdata->phy_mask; + bp->mii_bus->phy_mask = pdata->phy_mask; - bp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); - if (!bp->mii_bus.irq) { + bp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (!bp->mii_bus->irq) { err = -ENOMEM; - goto err_out; + goto err_out_free_mdiobus; } for (i = 0; i < PHY_MAX_ADDR; i++) - bp->mii_bus.irq[i] = PHY_POLL; + bp->mii_bus->irq[i] = PHY_POLL; - platform_set_drvdata(bp->dev, &bp->mii_bus); + platform_set_drvdata(bp->dev, bp->mii_bus); - if (mdiobus_register(&bp->mii_bus)) + if (mdiobus_register(bp->mii_bus)) goto err_out_free_mdio_irq; if (macb_mii_probe(bp->dev) != 0) { @@ -277,9 +283,11 @@ static int macb_mii_init(struct macb *bp) return 0; err_out_unregister_bus: - mdiobus_unregister(&bp->mii_bus); + mdiobus_unregister(bp->mii_bus); err_out_free_mdio_irq: - kfree(bp->mii_bus.irq); + kfree(bp->mii_bus->irq); +err_out_free_mdiobus: + mdiobus_free(bp->mii_bus); err_out: return err; } @@ -1261,8 +1269,9 @@ static int __exit macb_remove(struct platform_device *pdev) bp = netdev_priv(dev); if (bp->phy_dev) phy_disconnect(bp->phy_dev); - mdiobus_unregister(&bp->mii_bus); - kfree(bp->mii_bus.irq); + mdiobus_unregister(bp->mii_bus); + kfree(bp->mii_bus->irq); + mdiobus_free(bp->mii_bus); unregister_netdev(dev); free_irq(dev->irq, dev); iounmap(bp->regs); diff --git a/drivers/net/macb.h b/drivers/net/macb.h index 57b85acf0d1..d3212f6db70 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -384,7 +384,7 @@ struct macb { unsigned int rx_pending, tx_pending; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; struct phy_device *phy_dev; unsigned int link; unsigned int speed; diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 51ad3765e07..85587a6667b 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -9,7 +9,7 @@ * 2 of the License, or (at your option) any later version. * * Copyright (C) 1996 Paul Mackerras. - * Copyright (C) 1998 Alan Cox <alan@redhat.com> + * Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk> * * Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver * diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 0a97c26df6a..a1e22ed1f6e 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -41,7 +41,7 @@ #endif #if MFE_DEBUG>=1 -#define DPRINTK(str,args...) printk(KERN_DEBUG "meth: %s: " str, __FUNCTION__ , ## args) +#define DPRINTK(str,args...) printk(KERN_DEBUG "meth: %s: " str, __func__ , ## args) #define MFE_RX_DEBUG 2 #else #define DPRINTK(str,args...) diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index 6d343efb271..4e7a5faf035 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -203,7 +203,7 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id) out_badirq: printk(KERN_INFO "%s: %s(): irq %d for unknown device\n", - dev->name, __FUNCTION__, irq); + dev->name, __func__, irq); return ret; } diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c index 096bca54bcf..b411b79d72a 100644 --- a/drivers/net/mlx4/alloc.c +++ b/drivers/net/mlx4/alloc.c @@ -33,6 +33,7 @@ #include <linux/errno.h> #include <linux/slab.h> +#include <linux/mm.h> #include <linux/bitmap.h> #include <linux/dma-mapping.h> #include <linux/vmalloc.h> diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 62071d9c4a5..d1dd5b48dbd 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -67,11 +67,10 @@ struct mlx4_mpt_entry { #define MLX4_MPT_FLAG_PHYSICAL (1 << 9) #define MLX4_MPT_FLAG_REGION (1 << 8) -#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 26) +#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 27) +#define MLX4_MPT_PD_FLAG_RAE (1 << 28) #define MLX4_MPT_PD_FLAG_EN_INV (3 << 24) -#define MLX4_MTT_FLAG_PRESENT 1 - #define MLX4_MPT_STATUS_SW 0xF0 #define MLX4_MPT_STATUS_HW 0x00 @@ -348,7 +347,10 @@ int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) if (mr->mtt.order >= 0 && mr->mtt.page_shift == 0) { /* fast register MR in free state */ mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_FREE); - mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG); + mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG | + MLX4_MPT_PD_FLAG_RAE); + mpt_entry->mtt_sz = cpu_to_be32((1 << mr->mtt.order) * + MLX4_MTT_ENTRY_PER_SEG); } else { mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS); } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 0a18b9e96da..a9c8c08044b 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -38,6 +38,7 @@ #include <linux/init.h> #include <linux/dma-mapping.h> #include <linux/in.h> +#include <linux/ip.h> #include <linux/tcp.h> #include <linux/udp.h> #include <linux/etherdevice.h> @@ -48,30 +49,28 @@ #include <linux/kernel.h> #include <linux/spinlock.h> #include <linux/workqueue.h> -#include <linux/mii.h> +#include <linux/phy.h> #include <linux/mv643xx_eth.h> #include <asm/io.h> #include <asm/types.h> #include <asm/system.h> static char mv643xx_eth_driver_name[] = "mv643xx_eth"; -static char mv643xx_eth_driver_version[] = "1.3"; +static char mv643xx_eth_driver_version[] = "1.4"; -#define MV643XX_ETH_CHECKSUM_OFFLOAD_TX -#define MV643XX_ETH_NAPI -#define MV643XX_ETH_TX_FAST_REFILL - -#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX -#define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1) -#else -#define MAX_DESCS_PER_SKB 1 -#endif /* * Registers shared between all ports. */ #define PHY_ADDR 0x0000 #define SMI_REG 0x0004 +#define SMI_BUSY 0x10000000 +#define SMI_READ_VALID 0x08000000 +#define SMI_OPCODE_READ 0x04000000 +#define SMI_OPCODE_WRITE 0x00000000 +#define ERR_INT_CAUSE 0x0080 +#define ERR_INT_SMI_DONE 0x00000010 +#define ERR_INT_MASK 0x0084 #define WINDOW_BASE(w) (0x0200 + ((w) << 3)) #define WINDOW_SIZE(w) (0x0204 + ((w) << 3)) #define WINDOW_REMAP_HIGH(w) (0x0280 + ((w) << 2)) @@ -104,16 +103,12 @@ static char mv643xx_eth_driver_version[] = "1.3"; #define TX_BW_MTU(p) (0x0458 + ((p) << 10)) #define TX_BW_BURST(p) (0x045c + ((p) << 10)) #define INT_CAUSE(p) (0x0460 + ((p) << 10)) -#define INT_TX_END_0 0x00080000 #define INT_TX_END 0x07f80000 -#define INT_RX 0x0007fbfc +#define INT_RX 0x000003fc #define INT_EXT 0x00000002 #define INT_CAUSE_EXT(p) (0x0464 + ((p) << 10)) -#define INT_EXT_LINK 0x00100000 -#define INT_EXT_PHY 0x00010000 -#define INT_EXT_TX_ERROR_0 0x00000100 -#define INT_EXT_TX_0 0x00000001 -#define INT_EXT_TX 0x0000ffff +#define INT_EXT_LINK_PHY 0x00110000 +#define INT_EXT_TX 0x000000ff #define INT_MASK(p) (0x0468 + ((p) << 10)) #define INT_MASK_EXT(p) (0x046c + ((p) << 10)) #define TX_FIFO_URGENT_THRESHOLD(p) (0x0474 + ((p) << 10)) @@ -171,8 +166,8 @@ static char mv643xx_eth_driver_version[] = "1.3"; #define FORCE_LINK_PASS (1 << 1) #define SERIAL_PORT_ENABLE (1 << 0) -#define DEFAULT_RX_QUEUE_SIZE 400 -#define DEFAULT_TX_QUEUE_SIZE 800 +#define DEFAULT_RX_QUEUE_SIZE 128 +#define DEFAULT_TX_QUEUE_SIZE 256 /* @@ -249,9 +244,23 @@ struct mv643xx_eth_shared_private { void __iomem *base; /* - * Protects access to SMI_REG, which is shared between ports. + * Points at the right SMI instance to use. + */ + struct mv643xx_eth_shared_private *smi; + + /* + * Provides access to local SMI interface. + */ + struct mii_bus *smi_bus; + + /* + * If we have access to the error interrupt pin (which is + * somewhat misnamed as it not only reflects internal errors + * but also reflects SMI completion), use that to wait for + * SMI access completion instead of polling the SMI busy bit. */ - spinlock_t phy_lock; + int err_interrupt; + wait_queue_head_t smi_busy_wait; /* * Per-port MBUS window access register value. @@ -263,9 +272,13 @@ struct mv643xx_eth_shared_private { */ unsigned int t_clk; int extended_rx_coal_limit; - int tx_bw_control_moved; + int tx_bw_control; }; +#define TX_BW_CONTROL_ABSENT 0 +#define TX_BW_CONTROL_OLD_LAYOUT 1 +#define TX_BW_CONTROL_NEW_LAYOUT 2 + /* per-port *****************************************************************/ struct mib_counters { @@ -314,8 +327,6 @@ struct rx_queue { dma_addr_t rx_desc_dma; int rx_desc_area_size; struct sk_buff **rx_skb; - - struct timer_list rx_oom; }; struct tx_queue { @@ -330,7 +341,12 @@ struct tx_queue { struct tx_desc *tx_desc_area; dma_addr_t tx_desc_dma; int tx_desc_area_size; - struct sk_buff **tx_skb; + + struct sk_buff_head tx_skb; + + unsigned long tx_packets; + unsigned long tx_bytes; + unsigned long tx_dropped; }; struct mv643xx_eth_private { @@ -339,14 +355,24 @@ struct mv643xx_eth_private { struct net_device *dev; - struct mv643xx_eth_shared_private *shared_smi; - int phy_addr; - - spinlock_t lock; + struct phy_device *phy; + struct timer_list mib_counters_timer; + spinlock_t mib_counters_lock; struct mib_counters mib_counters; + struct work_struct tx_timeout_task; - struct mii_if_info mii; + + struct napi_struct napi; + u8 work_link; + u8 work_tx; + u8 work_tx_end; + u8 work_rx; + u8 work_rx_refill; + u8 work_rx_oom; + + int skb_size; + struct sk_buff_head rx_recycle; /* * RX state. @@ -354,9 +380,8 @@ struct mv643xx_eth_private { int default_rx_ring_size; unsigned long rx_desc_sram_addr; int rx_desc_sram_size; - u8 rxq_mask; - int rxq_primary; - struct napi_struct napi; + int rxq_count; + struct timer_list rx_oom; struct rx_queue rxq[8]; /* @@ -365,12 +390,8 @@ struct mv643xx_eth_private { int default_tx_ring_size; unsigned long tx_desc_sram_addr; int tx_desc_sram_size; - u8 txq_mask; - int txq_primary; + int txq_count; struct tx_queue txq[8]; -#ifdef MV643XX_ETH_TX_FAST_REFILL - int tx_clean_threshold; -#endif }; @@ -440,94 +461,21 @@ static void txq_disable(struct tx_queue *txq) udelay(10); } -static void __txq_maybe_wake(struct tx_queue *txq) +static void txq_maybe_wake(struct tx_queue *txq) { struct mv643xx_eth_private *mp = txq_to_mp(txq); + struct netdev_queue *nq = netdev_get_tx_queue(mp->dev, txq->index); - /* - * netif_{stop,wake}_queue() flow control only applies to - * the primary queue. - */ - BUG_ON(txq->index != mp->txq_primary); - - if (txq->tx_ring_size - txq->tx_desc_count >= MAX_DESCS_PER_SKB) - netif_wake_queue(mp->dev); -} - - -/* rx ***********************************************************************/ -static void txq_reclaim(struct tx_queue *txq, int force); - -static void rxq_refill(struct rx_queue *rxq) -{ - struct mv643xx_eth_private *mp = rxq_to_mp(rxq); - unsigned long flags; - - spin_lock_irqsave(&mp->lock, flags); - - while (rxq->rx_desc_count < rxq->rx_ring_size) { - int skb_size; - struct sk_buff *skb; - int unaligned; - int rx; - - /* - * Reserve 2+14 bytes for an ethernet header (the - * hardware automatically prepends 2 bytes of dummy - * data to each received packet), 16 bytes for up to - * four VLAN tags, and 4 bytes for the trailing FCS - * -- 36 bytes total. - */ - skb_size = mp->dev->mtu + 36; - - /* - * Make sure that the skb size is a multiple of 8 - * bytes, as the lower three bits of the receive - * descriptor's buffer size field are ignored by - * the hardware. - */ - skb_size = (skb_size + 7) & ~7; - - skb = dev_alloc_skb(skb_size + dma_get_cache_alignment() - 1); - if (skb == NULL) - break; - - unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1); - if (unaligned) - skb_reserve(skb, dma_get_cache_alignment() - unaligned); - - rxq->rx_desc_count++; - rx = rxq->rx_used_desc; - rxq->rx_used_desc = (rx + 1) % rxq->rx_ring_size; - - rxq->rx_desc_area[rx].buf_ptr = dma_map_single(NULL, skb->data, - skb_size, DMA_FROM_DEVICE); - rxq->rx_desc_area[rx].buf_size = skb_size; - rxq->rx_skb[rx] = skb; - wmb(); - rxq->rx_desc_area[rx].cmd_sts = BUFFER_OWNED_BY_DMA | - RX_ENABLE_INTERRUPT; - wmb(); - - /* - * The hardware automatically prepends 2 bytes of - * dummy data to each received packet, so that the - * IP header ends up 16-byte aligned. - */ - skb_reserve(skb, 2); + if (netif_tx_queue_stopped(nq)) { + __netif_tx_lock(nq, smp_processor_id()); + if (txq->tx_ring_size - txq->tx_desc_count >= MAX_SKB_FRAGS + 1) + netif_tx_wake_queue(nq); + __netif_tx_unlock(nq); } - - if (rxq->rx_desc_count != rxq->rx_ring_size) - mod_timer(&rxq->rx_oom, jiffies + (HZ / 10)); - - spin_unlock_irqrestore(&mp->lock, flags); } -static inline void rxq_refill_timer_wrapper(unsigned long data) -{ - rxq_refill((struct rx_queue *)data); -} +/* rx napi ******************************************************************/ static int rxq_process(struct rx_queue *rxq, int budget) { struct mv643xx_eth_private *mp = rxq_to_mp(rxq); @@ -539,31 +487,31 @@ static int rxq_process(struct rx_queue *rxq, int budget) struct rx_desc *rx_desc; unsigned int cmd_sts; struct sk_buff *skb; - unsigned long flags; - - spin_lock_irqsave(&mp->lock, flags); + u16 byte_cnt; rx_desc = &rxq->rx_desc_area[rxq->rx_curr_desc]; cmd_sts = rx_desc->cmd_sts; - if (cmd_sts & BUFFER_OWNED_BY_DMA) { - spin_unlock_irqrestore(&mp->lock, flags); + if (cmd_sts & BUFFER_OWNED_BY_DMA) break; - } rmb(); skb = rxq->rx_skb[rxq->rx_curr_desc]; rxq->rx_skb[rxq->rx_curr_desc] = NULL; - rxq->rx_curr_desc = (rxq->rx_curr_desc + 1) % rxq->rx_ring_size; - - spin_unlock_irqrestore(&mp->lock, flags); + rxq->rx_curr_desc++; + if (rxq->rx_curr_desc == rxq->rx_ring_size) + rxq->rx_curr_desc = 0; - dma_unmap_single(NULL, rx_desc->buf_ptr + 2, + dma_unmap_single(NULL, rx_desc->buf_ptr, rx_desc->buf_size, DMA_FROM_DEVICE); rxq->rx_desc_count--; rx++; + mp->work_rx_refill |= 1 << rxq->index; + + byte_cnt = rx_desc->byte_cnt; + /* * Update statistics. * @@ -573,7 +521,7 @@ static int rxq_process(struct rx_queue *rxq, int budget) * byte CRC at the end of the packet (which we do count). */ stats->rx_packets++; - stats->rx_bytes += rx_desc->byte_cnt - 2; + stats->rx_bytes += byte_cnt - 2; /* * In case we received a packet without first / last bits @@ -596,72 +544,84 @@ static int rxq_process(struct rx_queue *rxq, int budget) if (cmd_sts & ERROR_SUMMARY) stats->rx_errors++; - dev_kfree_skb_irq(skb); + dev_kfree_skb(skb); } else { /* * The -4 is for the CRC in the trailer of the * received packet */ - skb_put(skb, rx_desc->byte_cnt - 2 - 4); + skb_put(skb, byte_cnt - 2 - 4); - if (cmd_sts & LAYER_4_CHECKSUM_OK) { + if (cmd_sts & LAYER_4_CHECKSUM_OK) skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->csum = htons( - (cmd_sts & 0x0007fff8) >> 3); - } skb->protocol = eth_type_trans(skb, mp->dev); -#ifdef MV643XX_ETH_NAPI netif_receive_skb(skb); -#else - netif_rx(skb); -#endif } mp->dev->last_rx = jiffies; } - rxq_refill(rxq); + if (rx < budget) + mp->work_rx &= ~(1 << rxq->index); return rx; } -#ifdef MV643XX_ETH_NAPI -static int mv643xx_eth_poll(struct napi_struct *napi, int budget) +static int rxq_refill(struct rx_queue *rxq, int budget) { - struct mv643xx_eth_private *mp; - int rx; - int i; + struct mv643xx_eth_private *mp = rxq_to_mp(rxq); + int refilled; - mp = container_of(napi, struct mv643xx_eth_private, napi); + refilled = 0; + while (refilled < budget && rxq->rx_desc_count < rxq->rx_ring_size) { + struct sk_buff *skb; + int unaligned; + int rx; + + skb = __skb_dequeue(&mp->rx_recycle); + if (skb == NULL) + skb = dev_alloc_skb(mp->skb_size + + dma_get_cache_alignment() - 1); -#ifdef MV643XX_ETH_TX_FAST_REFILL - if (++mp->tx_clean_threshold > 5) { - mp->tx_clean_threshold = 0; - for (i = 0; i < 8; i++) - if (mp->txq_mask & (1 << i)) - txq_reclaim(mp->txq + i, 0); - - if (netif_carrier_ok(mp->dev)) { - spin_lock_irq(&mp->lock); - __txq_maybe_wake(mp->txq + mp->txq_primary); - spin_unlock_irq(&mp->lock); + if (skb == NULL) { + mp->work_rx_oom |= 1 << rxq->index; + goto oom; } - } -#endif - rx = 0; - for (i = 7; rx < budget && i >= 0; i--) - if (mp->rxq_mask & (1 << i)) - rx += rxq_process(mp->rxq + i, budget - rx); + unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1); + if (unaligned) + skb_reserve(skb, dma_get_cache_alignment() - unaligned); - if (rx < budget) { - netif_rx_complete(mp->dev, napi); - wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); + refilled++; + rxq->rx_desc_count++; + + rx = rxq->rx_used_desc++; + if (rxq->rx_used_desc == rxq->rx_ring_size) + rxq->rx_used_desc = 0; + + rxq->rx_desc_area[rx].buf_ptr = dma_map_single(NULL, skb->data, + mp->skb_size, DMA_FROM_DEVICE); + rxq->rx_desc_area[rx].buf_size = mp->skb_size; + rxq->rx_skb[rx] = skb; + wmb(); + rxq->rx_desc_area[rx].cmd_sts = BUFFER_OWNED_BY_DMA | + RX_ENABLE_INTERRUPT; + wmb(); + + /* + * The hardware automatically prepends 2 bytes of + * dummy data to each received packet, so that the + * IP header ends up 16-byte aligned. + */ + skb_reserve(skb, 2); } - return rx; + if (refilled < budget) + mp->work_rx_refill &= ~(1 << rxq->index); + +oom: + return refilled; } -#endif /* tx ***********************************************************************/ @@ -684,8 +644,9 @@ static int txq_alloc_desc_index(struct tx_queue *txq) BUG_ON(txq->tx_desc_count >= txq->tx_ring_size); - tx_desc_curr = txq->tx_curr_desc; - txq->tx_curr_desc = (tx_desc_curr + 1) % txq->tx_ring_size; + tx_desc_curr = txq->tx_curr_desc++; + if (txq->tx_curr_desc == txq->tx_ring_size) + txq->tx_curr_desc = 0; BUG_ON(txq->tx_curr_desc == txq->tx_used_desc); @@ -714,10 +675,8 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) desc->cmd_sts = BUFFER_OWNED_BY_DMA | ZERO_PADDING | TX_LAST_DESC | TX_ENABLE_INTERRUPT; - txq->tx_skb[tx_index] = skb; } else { desc->cmd_sts = BUFFER_OWNED_BY_DMA; - txq->tx_skb[tx_index] = NULL; } desc->l4i_chk = 0; @@ -734,144 +693,228 @@ static inline __be16 sum16_as_be(__sum16 sum) return (__force __be16)sum; } -static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) +static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) { struct mv643xx_eth_private *mp = txq_to_mp(txq); int nr_frags = skb_shinfo(skb)->nr_frags; int tx_index; struct tx_desc *desc; u32 cmd_sts; + u16 l4i_chk; int length; cmd_sts = TX_FIRST_DESC | GEN_CRC | BUFFER_OWNED_BY_DMA; - - tx_index = txq_alloc_desc_index(txq); - desc = &txq->tx_desc_area[tx_index]; - - if (nr_frags) { - txq_submit_frag_skb(txq, skb); - - length = skb_headlen(skb); - txq->tx_skb[tx_index] = NULL; - } else { - cmd_sts |= ZERO_PADDING | TX_LAST_DESC | TX_ENABLE_INTERRUPT; - length = skb->len; - txq->tx_skb[tx_index] = skb; - } - - desc->byte_cnt = length; - desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); + l4i_chk = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) { - int mac_hdr_len; + int tag_bytes; BUG_ON(skb->protocol != htons(ETH_P_IP) && skb->protocol != htons(ETH_P_8021Q)); - cmd_sts |= GEN_TCP_UDP_CHECKSUM | - GEN_IP_V4_CHECKSUM | - ip_hdr(skb)->ihl << TX_IHL_SHIFT; + tag_bytes = (void *)ip_hdr(skb) - (void *)skb->data - ETH_HLEN; + if (unlikely(tag_bytes & ~12)) { + if (skb_checksum_help(skb) == 0) + goto no_csum; + kfree_skb(skb); + return 1; + } - mac_hdr_len = (void *)ip_hdr(skb) - (void *)skb->data; - switch (mac_hdr_len - ETH_HLEN) { - case 0: - break; - case 4: - cmd_sts |= MAC_HDR_EXTRA_4_BYTES; - break; - case 8: - cmd_sts |= MAC_HDR_EXTRA_8_BYTES; - break; - case 12: + if (tag_bytes & 4) cmd_sts |= MAC_HDR_EXTRA_4_BYTES; + if (tag_bytes & 8) cmd_sts |= MAC_HDR_EXTRA_8_BYTES; - break; - default: - if (net_ratelimit()) - dev_printk(KERN_ERR, &txq_to_mp(txq)->dev->dev, - "mac header length is %d?!\n", mac_hdr_len); - break; - } + + cmd_sts |= GEN_TCP_UDP_CHECKSUM | + GEN_IP_V4_CHECKSUM | + ip_hdr(skb)->ihl << TX_IHL_SHIFT; switch (ip_hdr(skb)->protocol) { case IPPROTO_UDP: cmd_sts |= UDP_FRAME; - desc->l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check)); + l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check)); break; case IPPROTO_TCP: - desc->l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check)); + l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check)); break; default: BUG(); } } else { +no_csum: /* Errata BTS #50, IHL must be 5 if no HW checksum */ cmd_sts |= 5 << TX_IHL_SHIFT; - desc->l4i_chk = 0; } + tx_index = txq_alloc_desc_index(txq); + desc = &txq->tx_desc_area[tx_index]; + + if (nr_frags) { + txq_submit_frag_skb(txq, skb); + length = skb_headlen(skb); + } else { + cmd_sts |= ZERO_PADDING | TX_LAST_DESC | TX_ENABLE_INTERRUPT; + length = skb->len; + } + + desc->l4i_chk = l4i_chk; + desc->byte_cnt = length; + desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); + + __skb_queue_tail(&txq->tx_skb, skb); + /* ensure all other descriptors are written before first cmd_sts */ wmb(); desc->cmd_sts = cmd_sts; - /* clear TX_END interrupt status */ - wrl(mp, INT_CAUSE(mp->port_num), ~(INT_TX_END_0 << txq->index)); - rdl(mp, INT_CAUSE(mp->port_num)); + /* clear TX_END status */ + mp->work_tx_end &= ~(1 << txq->index); /* ensure all descriptors are written before poking hardware */ wmb(); txq_enable(txq); txq->tx_desc_count += nr_frags + 1; + + return 0; } static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; + int queue; struct tx_queue *txq; - unsigned long flags; + struct netdev_queue *nq; + + queue = skb_get_queue_mapping(skb); + txq = mp->txq + queue; + nq = netdev_get_tx_queue(dev, queue); if (has_tiny_unaligned_frags(skb) && __skb_linearize(skb)) { - stats->tx_dropped++; + txq->tx_dropped++; dev_printk(KERN_DEBUG, &dev->dev, "failed to linearize skb with tiny " "unaligned fragment\n"); return NETDEV_TX_BUSY; } - spin_lock_irqsave(&mp->lock, flags); - - txq = mp->txq + mp->txq_primary; - - if (txq->tx_ring_size - txq->tx_desc_count < MAX_DESCS_PER_SKB) { - spin_unlock_irqrestore(&mp->lock, flags); - if (txq->index == mp->txq_primary && net_ratelimit()) - dev_printk(KERN_ERR, &dev->dev, - "primary tx queue full?!\n"); + if (txq->tx_ring_size - txq->tx_desc_count < MAX_SKB_FRAGS + 1) { + if (net_ratelimit()) + dev_printk(KERN_ERR, &dev->dev, "tx queue full?!\n"); kfree_skb(skb); return NETDEV_TX_OK; } - txq_submit_skb(txq, skb); - stats->tx_bytes += skb->len; - stats->tx_packets++; - dev->trans_start = jiffies; - - if (txq->index == mp->txq_primary) { + if (!txq_submit_skb(txq, skb)) { int entries_left; + txq->tx_bytes += skb->len; + txq->tx_packets++; + dev->trans_start = jiffies; + entries_left = txq->tx_ring_size - txq->tx_desc_count; - if (entries_left < MAX_DESCS_PER_SKB) - netif_stop_queue(dev); + if (entries_left < MAX_SKB_FRAGS + 1) + netif_tx_stop_queue(nq); } - spin_unlock_irqrestore(&mp->lock, flags); - return NETDEV_TX_OK; } +/* tx napi ******************************************************************/ +static void txq_kick(struct tx_queue *txq) +{ + struct mv643xx_eth_private *mp = txq_to_mp(txq); + struct netdev_queue *nq = netdev_get_tx_queue(mp->dev, txq->index); + u32 hw_desc_ptr; + u32 expected_ptr; + + __netif_tx_lock(nq, smp_processor_id()); + + if (rdl(mp, TXQ_COMMAND(mp->port_num)) & (1 << txq->index)) + goto out; + + hw_desc_ptr = rdl(mp, TXQ_CURRENT_DESC_PTR(mp->port_num, txq->index)); + expected_ptr = (u32)txq->tx_desc_dma + + txq->tx_curr_desc * sizeof(struct tx_desc); + + if (hw_desc_ptr != expected_ptr) + txq_enable(txq); + +out: + __netif_tx_unlock(nq); + + mp->work_tx_end &= ~(1 << txq->index); +} + +static int txq_reclaim(struct tx_queue *txq, int budget, int force) +{ + struct mv643xx_eth_private *mp = txq_to_mp(txq); + struct netdev_queue *nq = netdev_get_tx_queue(mp->dev, txq->index); + int reclaimed; + + __netif_tx_lock(nq, smp_processor_id()); + + reclaimed = 0; + while (reclaimed < budget && txq->tx_desc_count > 0) { + int tx_index; + struct tx_desc *desc; + u32 cmd_sts; + struct sk_buff *skb; + + tx_index = txq->tx_used_desc; + desc = &txq->tx_desc_area[tx_index]; + cmd_sts = desc->cmd_sts; + + if (cmd_sts & BUFFER_OWNED_BY_DMA) { + if (!force) + break; + desc->cmd_sts = cmd_sts & ~BUFFER_OWNED_BY_DMA; + } + + txq->tx_used_desc = tx_index + 1; + if (txq->tx_used_desc == txq->tx_ring_size) + txq->tx_used_desc = 0; + + reclaimed++; + txq->tx_desc_count--; + + skb = NULL; + if (cmd_sts & TX_LAST_DESC) + skb = __skb_dequeue(&txq->tx_skb); + + if (cmd_sts & ERROR_SUMMARY) { + dev_printk(KERN_INFO, &mp->dev->dev, "tx error\n"); + mp->dev->stats.tx_errors++; + } + + if (cmd_sts & TX_FIRST_DESC) { + dma_unmap_single(NULL, desc->buf_ptr, + desc->byte_cnt, DMA_TO_DEVICE); + } else { + dma_unmap_page(NULL, desc->buf_ptr, + desc->byte_cnt, DMA_TO_DEVICE); + } + + if (skb != NULL) { + if (skb_queue_len(&mp->rx_recycle) < + mp->default_rx_ring_size && + skb_recycle_check(skb, mp->skb_size)) + __skb_queue_head(&mp->rx_recycle, skb); + else + dev_kfree_skb(skb); + } + } + + __netif_tx_unlock(nq); + + if (reclaimed < budget) + mp->work_tx &= ~(1 << txq->index); + + return reclaimed; +} + + /* tx rate control **********************************************************/ /* * Set total maximum TX rate (shared by all TX queues for this port) @@ -895,14 +938,17 @@ static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst) if (bucket_size > 65535) bucket_size = 65535; - if (mp->shared->tx_bw_control_moved) { - wrl(mp, TX_BW_RATE_MOVED(mp->port_num), token_rate); - wrl(mp, TX_BW_MTU_MOVED(mp->port_num), mtu); - wrl(mp, TX_BW_BURST_MOVED(mp->port_num), bucket_size); - } else { + switch (mp->shared->tx_bw_control) { + case TX_BW_CONTROL_OLD_LAYOUT: wrl(mp, TX_BW_RATE(mp->port_num), token_rate); wrl(mp, TX_BW_MTU(mp->port_num), mtu); wrl(mp, TX_BW_BURST(mp->port_num), bucket_size); + break; + case TX_BW_CONTROL_NEW_LAYOUT: + wrl(mp, TX_BW_RATE_MOVED(mp->port_num), token_rate); + wrl(mp, TX_BW_MTU_MOVED(mp->port_num), mtu); + wrl(mp, TX_BW_BURST_MOVED(mp->port_num), bucket_size); + break; } } @@ -934,14 +980,21 @@ static void txq_set_fixed_prio_mode(struct tx_queue *txq) /* * Turn on fixed priority mode. */ - if (mp->shared->tx_bw_control_moved) - off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); - else + off = 0; + switch (mp->shared->tx_bw_control) { + case TX_BW_CONTROL_OLD_LAYOUT: off = TXQ_FIX_PRIO_CONF(mp->port_num); + break; + case TX_BW_CONTROL_NEW_LAYOUT: + off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); + break; + } - val = rdl(mp, off); - val |= 1 << txq->index; - wrl(mp, off, val); + if (off) { + val = rdl(mp, off); + val |= 1 << txq->index; + wrl(mp, off, val); + } } static void txq_set_wrr(struct tx_queue *txq, int weight) @@ -953,95 +1006,147 @@ static void txq_set_wrr(struct tx_queue *txq, int weight) /* * Turn off fixed priority mode. */ - if (mp->shared->tx_bw_control_moved) - off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); - else + off = 0; + switch (mp->shared->tx_bw_control) { + case TX_BW_CONTROL_OLD_LAYOUT: off = TXQ_FIX_PRIO_CONF(mp->port_num); + break; + case TX_BW_CONTROL_NEW_LAYOUT: + off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); + break; + } - val = rdl(mp, off); - val &= ~(1 << txq->index); - wrl(mp, off, val); + if (off) { + val = rdl(mp, off); + val &= ~(1 << txq->index); + wrl(mp, off, val); - /* - * Configure WRR weight for this queue. - */ - off = TXQ_BW_WRR_CONF(mp->port_num, txq->index); + /* + * Configure WRR weight for this queue. + */ + off = TXQ_BW_WRR_CONF(mp->port_num, txq->index); - val = rdl(mp, off); - val = (val & ~0xff) | (weight & 0xff); - wrl(mp, off, val); + val = rdl(mp, off); + val = (val & ~0xff) | (weight & 0xff); + wrl(mp, off, val); + } } /* mii management interface *************************************************/ -#define SMI_BUSY 0x10000000 -#define SMI_READ_VALID 0x08000000 -#define SMI_OPCODE_READ 0x04000000 -#define SMI_OPCODE_WRITE 0x00000000 +static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id) +{ + struct mv643xx_eth_shared_private *msp = dev_id; -static void smi_reg_read(struct mv643xx_eth_private *mp, unsigned int addr, - unsigned int reg, unsigned int *value) + if (readl(msp->base + ERR_INT_CAUSE) & ERR_INT_SMI_DONE) { + writel(~ERR_INT_SMI_DONE, msp->base + ERR_INT_CAUSE); + wake_up(&msp->smi_busy_wait); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int smi_is_done(struct mv643xx_eth_shared_private *msp) { - void __iomem *smi_reg = mp->shared_smi->base + SMI_REG; - unsigned long flags; - int i; + return !(readl(msp->base + SMI_REG) & SMI_BUSY); +} - /* the SMI register is a shared resource */ - spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); +static int smi_wait_ready(struct mv643xx_eth_shared_private *msp) +{ + if (msp->err_interrupt == NO_IRQ) { + int i; - /* wait for the SMI register to become available */ - for (i = 0; readl(smi_reg) & SMI_BUSY; i++) { - if (i == 1000) { - printk("%s: PHY busy timeout\n", mp->dev->name); - goto out; + for (i = 0; !smi_is_done(msp); i++) { + if (i == 10) + return -ETIMEDOUT; + msleep(10); } - udelay(10); + + return 0; + } + + if (!wait_event_timeout(msp->smi_busy_wait, smi_is_done(msp), + msecs_to_jiffies(100))) + return -ETIMEDOUT; + + return 0; +} + +static int smi_bus_read(struct mii_bus *bus, int addr, int reg) +{ + struct mv643xx_eth_shared_private *msp = bus->priv; + void __iomem *smi_reg = msp->base + SMI_REG; + int ret; + + if (smi_wait_ready(msp)) { + printk("mv643xx_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; } writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg); - /* now wait for the data to be valid */ - for (i = 0; !(readl(smi_reg) & SMI_READ_VALID); i++) { - if (i == 1000) { - printk("%s: PHY read timeout\n", mp->dev->name); - goto out; - } - udelay(10); + if (smi_wait_ready(msp)) { + printk("mv643xx_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; } - *value = readl(smi_reg) & 0xffff; -out: - spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); + ret = readl(smi_reg); + if (!(ret & SMI_READ_VALID)) { + printk("mv643xx_eth: SMI bus read not valid\n"); + return -ENODEV; + } + + return ret & 0xffff; } -static void smi_reg_write(struct mv643xx_eth_private *mp, - unsigned int addr, - unsigned int reg, unsigned int value) +static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val) { - void __iomem *smi_reg = mp->shared_smi->base + SMI_REG; - unsigned long flags; - int i; + struct mv643xx_eth_shared_private *msp = bus->priv; + void __iomem *smi_reg = msp->base + SMI_REG; - /* the SMI register is a shared resource */ - spin_lock_irqsave(&mp->shared_smi->phy_lock, flags); - - /* wait for the SMI register to become available */ - for (i = 0; readl(smi_reg) & SMI_BUSY; i++) { - if (i == 1000) { - printk("%s: PHY busy timeout\n", mp->dev->name); - goto out; - } - udelay(10); + if (smi_wait_ready(msp)) { + printk("mv643xx_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; } writel(SMI_OPCODE_WRITE | (reg << 21) | - (addr << 16) | (value & 0xffff), smi_reg); -out: - spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags); + (addr << 16) | (val & 0xffff), smi_reg); + + if (smi_wait_ready(msp)) { + printk("mv643xx_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; + } + + return 0; } -/* mib counters *************************************************************/ +/* statistics ***************************************************************/ +static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev) +{ + struct mv643xx_eth_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + unsigned long tx_packets = 0; + unsigned long tx_bytes = 0; + unsigned long tx_dropped = 0; + int i; + + for (i = 0; i < mp->txq_count; i++) { + struct tx_queue *txq = mp->txq + i; + + tx_packets += txq->tx_packets; + tx_bytes += txq->tx_bytes; + tx_dropped += txq->tx_dropped; + } + + stats->tx_packets = tx_packets; + stats->tx_bytes = tx_bytes; + stats->tx_dropped = tx_dropped; + + return stats; +} + static inline u32 mib_read(struct mv643xx_eth_private *mp, int offset) { return rdl(mp, MIB_COUNTERS(mp->port_num) + offset); @@ -1059,6 +1164,7 @@ static void mib_counters_update(struct mv643xx_eth_private *mp) { struct mib_counters *p = &mp->mib_counters; + spin_lock(&mp->mib_counters_lock); p->good_octets_received += mib_read(mp, 0x00); p->good_octets_received += (u64)mib_read(mp, 0x04) << 32; p->bad_octets_received += mib_read(mp, 0x08); @@ -1091,6 +1197,16 @@ static void mib_counters_update(struct mv643xx_eth_private *mp) p->bad_crc_event += mib_read(mp, 0x74); p->collision += mib_read(mp, 0x78); p->late_collision += mib_read(mp, 0x7c); + spin_unlock(&mp->mib_counters_lock); + + mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ); +} + +static void mib_counters_timer_wrapper(unsigned long _mp) +{ + struct mv643xx_eth_private *mp = (void *)_mp; + + mib_counters_update(mp); } @@ -1156,9 +1272,9 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd * struct mv643xx_eth_private *mp = netdev_priv(dev); int err; - spin_lock_irq(&mp->lock); - err = mii_ethtool_gset(&mp->mii, cmd); - spin_unlock_irq(&mp->lock); + err = phy_read_status(mp->phy); + if (err == 0) + err = phy_ethtool_gset(mp->phy, cmd); /* * The MAC does not support 1000baseT_Half. @@ -1206,18 +1322,13 @@ static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethto static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct mv643xx_eth_private *mp = netdev_priv(dev); - int err; /* * The MAC does not support 1000baseT_Half. */ cmd->advertising &= ~ADVERTISED_1000baseT_Half; - spin_lock_irq(&mp->lock); - err = mii_ethtool_sset(&mp->mii, cmd); - spin_unlock_irq(&mp->lock); - - return err; + return phy_ethtool_sset(mp->phy, cmd); } static int mv643xx_eth_set_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) @@ -1239,7 +1350,7 @@ static int mv643xx_eth_nway_reset(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); - return mii_nway_restart(&mp->mii); + return genphy_restart_aneg(mp->phy); } static int mv643xx_eth_nway_reset_phyless(struct net_device *dev) @@ -1249,14 +1360,7 @@ static int mv643xx_eth_nway_reset_phyless(struct net_device *dev) static u32 mv643xx_eth_get_link(struct net_device *dev) { - struct mv643xx_eth_private *mp = netdev_priv(dev); - - return mii_link_ok(&mp->mii); -} - -static u32 mv643xx_eth_get_link_phyless(struct net_device *dev) -{ - return 1; + return !!netif_carrier_ok(dev); } static void mv643xx_eth_get_strings(struct net_device *dev, @@ -1277,9 +1381,10 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, uint64_t *data) { - struct mv643xx_eth_private *mp = dev->priv; + struct mv643xx_eth_private *mp = netdev_priv(dev); int i; + mv643xx_eth_get_stats(dev); mib_counters_update(mp); for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) { @@ -1323,7 +1428,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = { .set_settings = mv643xx_eth_set_settings_phyless, .get_drvinfo = mv643xx_eth_get_drvinfo, .nway_reset = mv643xx_eth_nway_reset_phyless, - .get_link = mv643xx_eth_get_link_phyless, + .get_link = mv643xx_eth_get_link, .set_sg = ethtool_op_set_sg, .get_strings = mv643xx_eth_get_strings, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, @@ -1487,7 +1592,7 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index) size = rxq->rx_ring_size * sizeof(struct rx_desc); - if (index == mp->rxq_primary && size <= mp->rx_desc_sram_size) { + if (index == 0 && size <= mp->rx_desc_sram_size) { rxq->rx_desc_area = ioremap(mp->rx_desc_sram_addr, mp->rx_desc_sram_size); rxq->rx_desc_dma = mp->rx_desc_sram_addr; @@ -1515,20 +1620,21 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index) rx_desc = (struct rx_desc *)rxq->rx_desc_area; for (i = 0; i < rxq->rx_ring_size; i++) { - int nexti = (i + 1) % rxq->rx_ring_size; + int nexti; + + nexti = i + 1; + if (nexti == rxq->rx_ring_size) + nexti = 0; + rx_desc[i].next_desc_ptr = rxq->rx_desc_dma + nexti * sizeof(struct rx_desc); } - init_timer(&rxq->rx_oom); - rxq->rx_oom.data = (unsigned long)rxq; - rxq->rx_oom.function = rxq_refill_timer_wrapper; - return 0; out_free: - if (index == mp->rxq_primary && size <= mp->rx_desc_sram_size) + if (index == 0 && size <= mp->rx_desc_sram_size) iounmap(rxq->rx_desc_area); else dma_free_coherent(NULL, size, @@ -1546,8 +1652,6 @@ static void rxq_deinit(struct rx_queue *rxq) rxq_disable(rxq); - del_timer_sync(&rxq->rx_oom); - for (i = 0; i < rxq->rx_ring_size; i++) { if (rxq->rx_skb[i]) { dev_kfree_skb(rxq->rx_skb[i]); @@ -1561,7 +1665,7 @@ static void rxq_deinit(struct rx_queue *rxq) rxq->rx_desc_count); } - if (rxq->index == mp->rxq_primary && + if (rxq->index == 0 && rxq->rx_desc_area_size <= mp->rx_desc_sram_size) iounmap(rxq->rx_desc_area); else @@ -1588,7 +1692,7 @@ static int txq_init(struct mv643xx_eth_private *mp, int index) size = txq->tx_ring_size * sizeof(struct tx_desc); - if (index == mp->txq_primary && size <= mp->tx_desc_sram_size) { + if (index == 0 && size <= mp->tx_desc_sram_size) { txq->tx_desc_area = ioremap(mp->tx_desc_sram_addr, mp->tx_desc_sram_size); txq->tx_desc_dma = mp->tx_desc_sram_addr; @@ -1601,120 +1705,97 @@ static int txq_init(struct mv643xx_eth_private *mp, int index) if (txq->tx_desc_area == NULL) { dev_printk(KERN_ERR, &mp->dev->dev, "can't allocate tx ring (%d bytes)\n", size); - goto out; + return -ENOMEM; } memset(txq->tx_desc_area, 0, size); txq->tx_desc_area_size = size; - txq->tx_skb = kmalloc(txq->tx_ring_size * sizeof(*txq->tx_skb), - GFP_KERNEL); - if (txq->tx_skb == NULL) { - dev_printk(KERN_ERR, &mp->dev->dev, - "can't allocate tx skb ring\n"); - goto out_free; - } tx_desc = (struct tx_desc *)txq->tx_desc_area; for (i = 0; i < txq->tx_ring_size; i++) { struct tx_desc *txd = tx_desc + i; - int nexti = (i + 1) % txq->tx_ring_size; + int nexti; + + nexti = i + 1; + if (nexti == txq->tx_ring_size) + nexti = 0; txd->cmd_sts = 0; txd->next_desc_ptr = txq->tx_desc_dma + nexti * sizeof(struct tx_desc); } - return 0; - - -out_free: - if (index == mp->txq_primary && size <= mp->tx_desc_sram_size) - iounmap(txq->tx_desc_area); - else - dma_free_coherent(NULL, size, - txq->tx_desc_area, - txq->tx_desc_dma); + skb_queue_head_init(&txq->tx_skb); -out: - return -ENOMEM; + return 0; } -static void txq_reclaim(struct tx_queue *txq, int force) +static void txq_deinit(struct tx_queue *txq) { struct mv643xx_eth_private *mp = txq_to_mp(txq); - unsigned long flags; - - spin_lock_irqsave(&mp->lock, flags); - while (txq->tx_desc_count > 0) { - int tx_index; - struct tx_desc *desc; - u32 cmd_sts; - struct sk_buff *skb; - dma_addr_t addr; - int count; - tx_index = txq->tx_used_desc; - desc = &txq->tx_desc_area[tx_index]; - cmd_sts = desc->cmd_sts; + txq_disable(txq); + txq_reclaim(txq, txq->tx_ring_size, 1); - if (cmd_sts & BUFFER_OWNED_BY_DMA) { - if (!force) - break; - desc->cmd_sts = cmd_sts & ~BUFFER_OWNED_BY_DMA; - } + BUG_ON(txq->tx_used_desc != txq->tx_curr_desc); - txq->tx_used_desc = (tx_index + 1) % txq->tx_ring_size; - txq->tx_desc_count--; + if (txq->index == 0 && + txq->tx_desc_area_size <= mp->tx_desc_sram_size) + iounmap(txq->tx_desc_area); + else + dma_free_coherent(NULL, txq->tx_desc_area_size, + txq->tx_desc_area, txq->tx_desc_dma); +} - addr = desc->buf_ptr; - count = desc->byte_cnt; - skb = txq->tx_skb[tx_index]; - txq->tx_skb[tx_index] = NULL; - if (cmd_sts & ERROR_SUMMARY) { - dev_printk(KERN_INFO, &mp->dev->dev, "tx error\n"); - mp->dev->stats.tx_errors++; - } +/* netdev ops and related ***************************************************/ +static int mv643xx_eth_collect_events(struct mv643xx_eth_private *mp) +{ + u32 int_cause; + u32 int_cause_ext; - /* - * Drop mp->lock while we free the skb. - */ - spin_unlock_irqrestore(&mp->lock, flags); + int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & + (INT_TX_END | INT_RX | INT_EXT); + if (int_cause == 0) + return 0; - if (cmd_sts & TX_FIRST_DESC) - dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE); - else - dma_unmap_page(NULL, addr, count, DMA_TO_DEVICE); + int_cause_ext = 0; + if (int_cause & INT_EXT) + int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num)); - if (skb) - dev_kfree_skb_irq(skb); + int_cause &= INT_TX_END | INT_RX; + if (int_cause) { + wrl(mp, INT_CAUSE(mp->port_num), ~int_cause); + mp->work_tx_end |= ((int_cause & INT_TX_END) >> 19) & + ~(rdl(mp, TXQ_COMMAND(mp->port_num)) & 0xff); + mp->work_rx |= (int_cause & INT_RX) >> 2; + } - spin_lock_irqsave(&mp->lock, flags); + int_cause_ext &= INT_EXT_LINK_PHY | INT_EXT_TX; + if (int_cause_ext) { + wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext); + if (int_cause_ext & INT_EXT_LINK_PHY) + mp->work_link = 1; + mp->work_tx |= int_cause_ext & INT_EXT_TX; } - spin_unlock_irqrestore(&mp->lock, flags); + + return 1; } -static void txq_deinit(struct tx_queue *txq) +static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) { - struct mv643xx_eth_private *mp = txq_to_mp(txq); - - txq_disable(txq); - txq_reclaim(txq, 1); + struct net_device *dev = (struct net_device *)dev_id; + struct mv643xx_eth_private *mp = netdev_priv(dev); - BUG_ON(txq->tx_used_desc != txq->tx_curr_desc); + if (unlikely(!mv643xx_eth_collect_events(mp))) + return IRQ_NONE; - if (txq->index == mp->txq_primary && - txq->tx_desc_area_size <= mp->tx_desc_sram_size) - iounmap(txq->tx_desc_area); - else - dma_free_coherent(NULL, txq->tx_desc_area_size, - txq->tx_desc_area, txq->tx_desc_dma); + wrl(mp, INT_MASK(mp->port_num), 0); + napi_schedule(&mp->napi); - kfree(txq->tx_skb); + return IRQ_HANDLED; } - -/* netdev ops and related ***************************************************/ static void handle_link_event(struct mv643xx_eth_private *mp) { struct net_device *dev = mp->dev; @@ -1731,15 +1812,12 @@ static void handle_link_event(struct mv643xx_eth_private *mp) printk(KERN_INFO "%s: link down\n", dev->name); netif_carrier_off(dev); - netif_stop_queue(dev); - for (i = 0; i < 8; i++) { + for (i = 0; i < mp->txq_count; i++) { struct tx_queue *txq = mp->txq + i; - if (mp->txq_mask & (1 << i)) { - txq_reclaim(txq, 1); - txq_reset_hw_ptr(txq); - } + txq_reclaim(txq, txq->tx_ring_size, 1); + txq_reset_hw_ptr(txq); } } return; @@ -1767,119 +1845,93 @@ static void handle_link_event(struct mv643xx_eth_private *mp) speed, duplex ? "full" : "half", fc ? "en" : "dis"); - if (!netif_carrier_ok(dev)) { + if (!netif_carrier_ok(dev)) netif_carrier_on(dev); - netif_wake_queue(dev); - } } -static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) +static int mv643xx_eth_poll(struct napi_struct *napi, int budget) { - struct net_device *dev = (struct net_device *)dev_id; - struct mv643xx_eth_private *mp = netdev_priv(dev); - u32 int_cause; - u32 int_cause_ext; - - int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & - (INT_TX_END | INT_RX | INT_EXT); - if (int_cause == 0) - return IRQ_NONE; - - int_cause_ext = 0; - if (int_cause & INT_EXT) { - int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num)) - & (INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX); - wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext); - } + struct mv643xx_eth_private *mp; + int work_done; - if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) - handle_link_event(mp); + mp = container_of(napi, struct mv643xx_eth_private, napi); - /* - * RxBuffer or RxError set for any of the 8 queues? - */ -#ifdef MV643XX_ETH_NAPI - if (int_cause & INT_RX) { - wrl(mp, INT_CAUSE(mp->port_num), ~(int_cause & INT_RX)); - wrl(mp, INT_MASK(mp->port_num), 0x00000000); - rdl(mp, INT_MASK(mp->port_num)); + mp->work_rx_refill |= mp->work_rx_oom; + mp->work_rx_oom = 0; - netif_rx_schedule(dev, &mp->napi); - } -#else - if (int_cause & INT_RX) { - int i; + work_done = 0; + while (work_done < budget) { + u8 queue_mask; + int queue; + int work_tbd; - for (i = 7; i >= 0; i--) - if (mp->rxq_mask & (1 << i)) - rxq_process(mp->rxq + i, INT_MAX); - } -#endif - - /* - * TxBuffer or TxError set for any of the 8 queues? - */ - if (int_cause_ext & INT_EXT_TX) { - int i; + if (mp->work_link) { + mp->work_link = 0; + handle_link_event(mp); + continue; + } - for (i = 0; i < 8; i++) - if (mp->txq_mask & (1 << i)) - txq_reclaim(mp->txq + i, 0); + queue_mask = mp->work_tx | mp->work_tx_end | + mp->work_rx | mp->work_rx_refill; + if (!queue_mask) { + if (mv643xx_eth_collect_events(mp)) + continue; + break; + } - /* - * Enough space again in the primary TX queue for a - * full packet? - */ - if (netif_carrier_ok(dev)) { - spin_lock(&mp->lock); - __txq_maybe_wake(mp->txq + mp->txq_primary); - spin_unlock(&mp->lock); + queue = fls(queue_mask) - 1; + queue_mask = 1 << queue; + + work_tbd = budget - work_done; + if (work_tbd > 16) + work_tbd = 16; + + if (mp->work_tx_end & queue_mask) { + txq_kick(mp->txq + queue); + } else if (mp->work_tx & queue_mask) { + work_done += txq_reclaim(mp->txq + queue, work_tbd, 0); + txq_maybe_wake(mp->txq + queue); + } else if (mp->work_rx & queue_mask) { + work_done += rxq_process(mp->rxq + queue, work_tbd); + } else if (mp->work_rx_refill & queue_mask) { + work_done += rxq_refill(mp->rxq + queue, work_tbd); + } else { + BUG(); } } - /* - * Any TxEnd interrupts? - */ - if (int_cause & INT_TX_END) { - int i; - - wrl(mp, INT_CAUSE(mp->port_num), ~(int_cause & INT_TX_END)); - - spin_lock(&mp->lock); - for (i = 0; i < 8; i++) { - struct tx_queue *txq = mp->txq + i; - u32 hw_desc_ptr; - u32 expected_ptr; - - if ((int_cause & (INT_TX_END_0 << i)) == 0) - continue; + if (work_done < budget) { + if (mp->work_rx_oom) + mod_timer(&mp->rx_oom, jiffies + (HZ / 10)); + napi_complete(napi); + wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); + } - hw_desc_ptr = - rdl(mp, TXQ_CURRENT_DESC_PTR(mp->port_num, i)); - expected_ptr = (u32)txq->tx_desc_dma + - txq->tx_curr_desc * sizeof(struct tx_desc); + return work_done; +} - if (hw_desc_ptr != expected_ptr) - txq_enable(txq); - } - spin_unlock(&mp->lock); - } +static inline void oom_timer_wrapper(unsigned long data) +{ + struct mv643xx_eth_private *mp = (void *)data; - return IRQ_HANDLED; + napi_schedule(&mp->napi); } static void phy_reset(struct mv643xx_eth_private *mp) { - unsigned int data; + int data; + + data = phy_read(mp->phy, MII_BMCR); + if (data < 0) + return; - smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data); data |= BMCR_RESET; - smi_reg_write(mp, mp->phy_addr, MII_BMCR, data); + if (phy_write(mp->phy, MII_BMCR, data) < 0) + return; do { - udelay(1); - smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data); - } while (data & BMCR_RESET); + data = phy_read(mp->phy, MII_BMCR); + } while (data >= 0 && data & BMCR_RESET); } static void port_start(struct mv643xx_eth_private *mp) @@ -1890,7 +1942,7 @@ static void port_start(struct mv643xx_eth_private *mp) /* * Perform PHY reset, if there is a PHY. */ - if (mp->phy_addr != -1) { + if (mp->phy != NULL) { struct ethtool_cmd cmd; mv643xx_eth_get_settings(mp->dev, &cmd); @@ -1907,7 +1959,7 @@ static void port_start(struct mv643xx_eth_private *mp) wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); pscr |= DO_NOT_FORCE_LINK_FAIL; - if (mp->phy_addr == -1) + if (mp->phy == NULL) pscr |= FORCE_LINK_PASS; wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); @@ -1917,12 +1969,9 @@ static void port_start(struct mv643xx_eth_private *mp) * Configure TX path and queues. */ tx_set_rate(mp, 1000000000, 16777216); - for (i = 0; i < 8; i++) { + for (i = 0; i < mp->txq_count; i++) { struct tx_queue *txq = mp->txq + i; - if ((mp->txq_mask & (1 << i)) == 0) - continue; - txq_reset_hw_ptr(txq); txq_set_rate(txq, 1000000000, 16777216); txq_set_fixed_prio_mode(txq); @@ -1935,9 +1984,10 @@ static void port_start(struct mv643xx_eth_private *mp) /* * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast - * frames to RX queue #0. + * frames to RX queue #0, and include the pseudo-header when + * calculating receive checksums. */ - wrl(mp, PORT_CONFIG(mp->port_num), 0x00000000); + wrl(mp, PORT_CONFIG(mp->port_num), 0x02000000); /* * Treat BPDUs as normal multicasts, and disable partition mode. @@ -1947,14 +1997,11 @@ static void port_start(struct mv643xx_eth_private *mp) /* * Enable the receive queues. */ - for (i = 0; i < 8; i++) { + for (i = 0; i < mp->rxq_count; i++) { struct rx_queue *rxq = mp->rxq + i; int off = RXQ_CURRENT_DESC_PTR(mp->port_num, i); u32 addr; - if ((mp->rxq_mask & (1 << i)) == 0) - continue; - addr = (u32)rxq->rx_desc_dma; addr += rxq->rx_curr_desc * sizeof(struct rx_desc); wrl(mp, off, addr); @@ -1993,6 +2040,26 @@ static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay) wrl(mp, TX_FIFO_URGENT_THRESHOLD(mp->port_num), (coal & 0x3fff) << 4); } +static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp) +{ + int skb_size; + + /* + * Reserve 2+14 bytes for an ethernet header (the hardware + * automatically prepends 2 bytes of dummy data to each + * received packet), 16 bytes for up to four VLAN tags, and + * 4 bytes for the trailing FCS -- 36 bytes total. + */ + skb_size = mp->dev->mtu + 36; + + /* + * Make sure that the skb size is a multiple of 8 bytes, as + * the lower three bits of the receive descriptor's buffer + * size field are ignored by the hardware. + */ + mp->skb_size = (skb_size + 7) & ~7; +} + static int mv643xx_eth_open(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); @@ -2004,8 +2071,7 @@ static int mv643xx_eth_open(struct net_device *dev) rdl(mp, INT_CAUSE_EXT(mp->port_num)); err = request_irq(dev->irq, mv643xx_eth_irq, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, - dev->name, dev); + IRQF_SHARED, dev->name, dev); if (err) { dev_printk(KERN_ERR, &dev->dev, "can't assign irq\n"); return -EAGAIN; @@ -2013,58 +2079,53 @@ static int mv643xx_eth_open(struct net_device *dev) init_mac_tables(mp); - for (i = 0; i < 8; i++) { - if ((mp->rxq_mask & (1 << i)) == 0) - continue; + mv643xx_eth_recalc_skb_size(mp); + + napi_enable(&mp->napi); + skb_queue_head_init(&mp->rx_recycle); + + for (i = 0; i < mp->rxq_count; i++) { err = rxq_init(mp, i); if (err) { while (--i >= 0) - if (mp->rxq_mask & (1 << i)) - rxq_deinit(mp->rxq + i); + rxq_deinit(mp->rxq + i); goto out; } - rxq_refill(mp->rxq + i); + rxq_refill(mp->rxq + i, INT_MAX); } - for (i = 0; i < 8; i++) { - if ((mp->txq_mask & (1 << i)) == 0) - continue; + if (mp->work_rx_oom) { + mp->rx_oom.expires = jiffies + (HZ / 10); + add_timer(&mp->rx_oom); + } + for (i = 0; i < mp->txq_count; i++) { err = txq_init(mp, i); if (err) { while (--i >= 0) - if (mp->txq_mask & (1 << i)) - txq_deinit(mp->txq + i); + txq_deinit(mp->txq + i); goto out_free; } } -#ifdef MV643XX_ETH_NAPI - napi_enable(&mp->napi); -#endif - netif_carrier_off(dev); - netif_stop_queue(dev); port_start(mp); set_rx_coal(mp, 0); set_tx_coal(mp, 0); - wrl(mp, INT_MASK_EXT(mp->port_num), - INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX); - + wrl(mp, INT_MASK_EXT(mp->port_num), INT_EXT_LINK_PHY | INT_EXT_TX); wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); return 0; out_free: - for (i = 0; i < 8; i++) - if (mp->rxq_mask & (1 << i)) - rxq_deinit(mp->rxq + i); + for (i = 0; i < mp->rxq_count; i++) + rxq_deinit(mp->rxq + i); out: free_irq(dev->irq, dev); @@ -2076,12 +2137,10 @@ static void port_reset(struct mv643xx_eth_private *mp) unsigned int data; int i; - for (i = 0; i < 8; i++) { - if (mp->rxq_mask & (1 << i)) - rxq_disable(mp->rxq + i); - if (mp->txq_mask & (1 << i)) - txq_disable(mp->txq + i); - } + for (i = 0; i < mp->rxq_count; i++) + rxq_disable(mp->rxq + i); + for (i = 0; i < mp->txq_count; i++) + txq_disable(mp->txq + i); while (1) { u32 ps = rdl(mp, PORT_STATUS(mp->port_num)); @@ -2107,23 +2166,26 @@ static int mv643xx_eth_stop(struct net_device *dev) wrl(mp, INT_MASK(mp->port_num), 0x00000000); rdl(mp, INT_MASK(mp->port_num)); -#ifdef MV643XX_ETH_NAPI + del_timer_sync(&mp->mib_counters_timer); + napi_disable(&mp->napi); -#endif + + del_timer_sync(&mp->rx_oom); + netif_carrier_off(dev); - netif_stop_queue(dev); free_irq(dev->irq, dev); port_reset(mp); + mv643xx_eth_get_stats(dev); mib_counters_update(mp); - for (i = 0; i < 8; i++) { - if (mp->rxq_mask & (1 << i)) - rxq_deinit(mp->rxq + i); - if (mp->txq_mask & (1 << i)) - txq_deinit(mp->txq + i); - } + skb_queue_purge(&mp->rx_recycle); + + for (i = 0; i < mp->rxq_count; i++) + rxq_deinit(mp->rxq + i); + for (i = 0; i < mp->txq_count; i++) + txq_deinit(mp->txq + i); return 0; } @@ -2132,8 +2194,8 @@ static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct mv643xx_eth_private *mp = netdev_priv(dev); - if (mp->phy_addr != -1) - return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL); + if (mp->phy != NULL) + return phy_mii_ioctl(mp->phy, if_mii(ifr), cmd); return -EOPNOTSUPP; } @@ -2146,6 +2208,7 @@ static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; dev->mtu = new_mtu; + mv643xx_eth_recalc_skb_size(mp); tx_set_rate(mp, 1000000000, 16777216); if (!netif_running(dev)) @@ -2173,12 +2236,10 @@ static void tx_timeout_task(struct work_struct *ugly) mp = container_of(ugly, struct mv643xx_eth_private, tx_timeout_task); if (netif_running(mp->dev)) { - netif_stop_queue(mp->dev); - + netif_tx_stop_all_queues(mp->dev); port_reset(mp); port_start(mp); - - __txq_maybe_wake(mp->txq + mp->txq_primary); + netif_tx_wake_all_queues(mp->dev); } } @@ -2205,22 +2266,6 @@ static void mv643xx_eth_netpoll(struct net_device *dev) } #endif -static int mv643xx_eth_mdio_read(struct net_device *dev, int addr, int reg) -{ - struct mv643xx_eth_private *mp = netdev_priv(dev); - int val; - - smi_reg_read(mp, addr, reg, &val); - - return val; -} - -static void mv643xx_eth_mdio_write(struct net_device *dev, int addr, int reg, int val) -{ - struct mv643xx_eth_private *mp = netdev_priv(dev); - smi_reg_write(mp, addr, reg, val); -} - /* platform glue ************************************************************/ static void @@ -2272,14 +2317,20 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp) msp->extended_rx_coal_limit = 0; /* - * Check whether the TX rate control registers are in the - * old or the new place. + * Check whether the MAC supports TX rate control, and if + * yes, whether its associated registers are in the old or + * the new place. */ writel(1, msp->base + TX_BW_MTU_MOVED(0)); - if (readl(msp->base + TX_BW_MTU_MOVED(0)) & 1) - msp->tx_bw_control_moved = 1; - else - msp->tx_bw_control_moved = 0; + if (readl(msp->base + TX_BW_MTU_MOVED(0)) & 1) { + msp->tx_bw_control = TX_BW_CONTROL_NEW_LAYOUT; + } else { + writel(7, msp->base + TX_BW_RATE(0)); + if (readl(msp->base + TX_BW_RATE(0)) & 7) + msp->tx_bw_control = TX_BW_CONTROL_OLD_LAYOUT; + else + msp->tx_bw_control = TX_BW_CONTROL_ABSENT; + } } static int mv643xx_eth_shared_probe(struct platform_device *pdev) @@ -2309,7 +2360,45 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) if (msp->base == NULL) goto out_free; - spin_lock_init(&msp->phy_lock); + /* + * Set up and register SMI bus. + */ + if (pd == NULL || pd->shared_smi == NULL) { + msp->smi_bus = mdiobus_alloc(); + if (msp->smi_bus == NULL) + goto out_unmap; + + msp->smi_bus->priv = msp; + msp->smi_bus->name = "mv643xx_eth smi"; + msp->smi_bus->read = smi_bus_read; + msp->smi_bus->write = smi_bus_write, + snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id); + msp->smi_bus->parent = &pdev->dev; + msp->smi_bus->phy_mask = 0xffffffff; + if (mdiobus_register(msp->smi_bus) < 0) + goto out_free_mii_bus; + msp->smi = msp; + } else { + msp->smi = platform_get_drvdata(pd->shared_smi); + } + + msp->err_interrupt = NO_IRQ; + init_waitqueue_head(&msp->smi_busy_wait); + + /* + * Check whether the error interrupt is hooked up. + */ + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res != NULL) { + int err; + + err = request_irq(res->start, mv643xx_eth_err_irq, + IRQF_SHARED, "mv643xx_eth", msp); + if (!err) { + writel(ERR_INT_SMI_DONE, msp->base + ERR_INT_MASK); + msp->err_interrupt = res->start; + } + } /* * (Re-)program MBUS remapping windows if we are asked to. @@ -2327,6 +2416,10 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) return 0; +out_free_mii_bus: + mdiobus_free(msp->smi_bus); +out_unmap: + iounmap(msp->base); out_free: kfree(msp); out: @@ -2336,7 +2429,14 @@ out: static int mv643xx_eth_shared_remove(struct platform_device *pdev) { struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev); + struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; + if (pd == NULL || pd->shared_smi == NULL) { + mdiobus_free(msp->smi_bus); + mdiobus_unregister(msp->smi_bus); + } + if (msp->err_interrupt != NO_IRQ) + free_irq(msp->err_interrupt, msp); iounmap(msp->base); kfree(msp); @@ -2382,33 +2482,13 @@ static void set_params(struct mv643xx_eth_private *mp, else uc_addr_get(mp, dev->dev_addr); - if (pd->phy_addr == -1) { - mp->shared_smi = NULL; - mp->phy_addr = -1; - } else { - mp->shared_smi = mp->shared; - if (pd->shared_smi != NULL) - mp->shared_smi = platform_get_drvdata(pd->shared_smi); - - if (pd->force_phy_addr || pd->phy_addr) { - mp->phy_addr = pd->phy_addr & 0x3f; - phy_addr_set(mp, mp->phy_addr); - } else { - mp->phy_addr = phy_addr_get(mp); - } - } - mp->default_rx_ring_size = DEFAULT_RX_QUEUE_SIZE; if (pd->rx_queue_size) mp->default_rx_ring_size = pd->rx_queue_size; mp->rx_desc_sram_addr = pd->rx_sram_addr; mp->rx_desc_sram_size = pd->rx_sram_size; - if (pd->rx_queue_mask) - mp->rxq_mask = pd->rx_queue_mask; - else - mp->rxq_mask = 0x01; - mp->rxq_primary = fls(mp->rxq_mask) - 1; + mp->rxq_count = pd->rx_queue_count ? : 1; mp->default_tx_ring_size = DEFAULT_TX_QUEUE_SIZE; if (pd->tx_queue_size) @@ -2416,76 +2496,63 @@ static void set_params(struct mv643xx_eth_private *mp, mp->tx_desc_sram_addr = pd->tx_sram_addr; mp->tx_desc_sram_size = pd->tx_sram_size; - if (pd->tx_queue_mask) - mp->txq_mask = pd->tx_queue_mask; - else - mp->txq_mask = 0x01; - mp->txq_primary = fls(mp->txq_mask) - 1; + mp->txq_count = pd->tx_queue_count ? : 1; } -static int phy_detect(struct mv643xx_eth_private *mp) +static struct phy_device *phy_scan(struct mv643xx_eth_private *mp, + int phy_addr) { - unsigned int data; - unsigned int data2; + struct mii_bus *bus = mp->shared->smi->smi_bus; + struct phy_device *phydev; + int start; + int num; + int i; + + if (phy_addr == MV643XX_ETH_PHY_ADDR_DEFAULT) { + start = phy_addr_get(mp) & 0x1f; + num = 32; + } else { + start = phy_addr & 0x1f; + num = 1; + } - smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data); - smi_reg_write(mp, mp->phy_addr, MII_BMCR, data ^ BMCR_ANENABLE); + phydev = NULL; + for (i = 0; i < num; i++) { + int addr = (start + i) & 0x1f; - smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data2); - if (((data ^ data2) & BMCR_ANENABLE) == 0) - return -ENODEV; + if (bus->phy_map[addr] == NULL) + mdiobus_scan(bus, addr); - smi_reg_write(mp, mp->phy_addr, MII_BMCR, data); + if (phydev == NULL) { + phydev = bus->phy_map[addr]; + if (phydev != NULL) + phy_addr_set(mp, addr); + } + } - return 0; + return phydev; } -static int phy_init(struct mv643xx_eth_private *mp, - struct mv643xx_eth_platform_data *pd) +static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex) { - struct ethtool_cmd cmd; - int err; + struct phy_device *phy = mp->phy; - err = phy_detect(mp); - if (err) { - dev_printk(KERN_INFO, &mp->dev->dev, - "no PHY detected at addr %d\n", mp->phy_addr); - return err; - } phy_reset(mp); - mp->mii.phy_id = mp->phy_addr; - mp->mii.phy_id_mask = 0x3f; - mp->mii.reg_num_mask = 0x1f; - mp->mii.dev = mp->dev; - mp->mii.mdio_read = mv643xx_eth_mdio_read; - mp->mii.mdio_write = mv643xx_eth_mdio_write; - - mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii); - - memset(&cmd, 0, sizeof(cmd)); - - cmd.port = PORT_MII; - cmd.transceiver = XCVR_INTERNAL; - cmd.phy_address = mp->phy_addr; - if (pd->speed == 0) { - cmd.autoneg = AUTONEG_ENABLE; - cmd.speed = SPEED_100; - cmd.advertising = ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full; - if (mp->mii.supports_gmii) - cmd.advertising |= ADVERTISED_1000baseT_Full; + phy_attach(mp->dev, phy->dev.bus_id, 0, PHY_INTERFACE_MODE_GMII); + + if (speed == 0) { + phy->autoneg = AUTONEG_ENABLE; + phy->speed = 0; + phy->duplex = 0; + phy->advertising = phy->supported | ADVERTISED_Autoneg; } else { - cmd.autoneg = AUTONEG_DISABLE; - cmd.speed = pd->speed; - cmd.duplex = pd->duplex; + phy->autoneg = AUTONEG_DISABLE; + phy->advertising = 0; + phy->speed = speed; + phy->duplex = duplex; } - - mv643xx_eth_set_settings(mp->dev, &cmd); - - return 0; + phy_start_aneg(phy); } static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) @@ -2499,7 +2566,7 @@ static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) } pscr = MAX_RX_PACKET_9700BYTE | SERIAL_PORT_CONTROL_RESERVED; - if (mp->phy_addr == -1) { + if (mp->phy == NULL) { pscr |= DISABLE_AUTO_NEG_SPEED_GMII; if (speed == SPEED_1000) pscr |= SET_GMII_SPEED_TO_1000; @@ -2538,7 +2605,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) return -ENODEV; } - dev = alloc_etherdev(sizeof(struct mv643xx_eth_private)); + dev = alloc_etherdev_mq(sizeof(struct mv643xx_eth_private), 8); if (!dev) return -ENOMEM; @@ -2549,33 +2616,47 @@ static int mv643xx_eth_probe(struct platform_device *pdev) mp->port_num = pd->port_number; mp->dev = dev; -#ifdef MV643XX_ETH_NAPI - netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 64); -#endif set_params(mp, pd); + dev->real_num_tx_queues = mp->txq_count; - spin_lock_init(&mp->lock); - - mib_counters_clear(mp); - INIT_WORK(&mp->tx_timeout_task, tx_timeout_task); - - if (mp->phy_addr != -1) { - err = phy_init(mp, pd); - if (err) - goto out; + if (pd->phy_addr != MV643XX_ETH_PHY_NONE) + mp->phy = phy_scan(mp, pd->phy_addr); + if (mp->phy != NULL) { + phy_init(mp, pd->speed, pd->duplex); SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops); } else { SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless); } + init_pscr(mp, pd->speed, pd->duplex); + mib_counters_clear(mp); + + init_timer(&mp->mib_counters_timer); + mp->mib_counters_timer.data = (unsigned long)mp; + mp->mib_counters_timer.function = mib_counters_timer_wrapper; + mp->mib_counters_timer.expires = jiffies + 30 * HZ; + add_timer(&mp->mib_counters_timer); + + spin_lock_init(&mp->mib_counters_lock); + + INIT_WORK(&mp->tx_timeout_task, tx_timeout_task); + + netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 128); + + init_timer(&mp->rx_oom); + mp->rx_oom.data = (unsigned long)mp; + mp->rx_oom.function = oom_timer_wrapper; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); BUG_ON(!res); dev->irq = res->start; + dev->get_stats = mv643xx_eth_get_stats; dev->hard_start_xmit = mv643xx_eth_xmit; dev->open = mv643xx_eth_open; dev->stop = mv643xx_eth_stop; @@ -2590,14 +2671,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->watchdog_timeo = 2 * HZ; dev->base_addr = 0; -#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX - /* - * Zero copy can only work if we use Discovery II memory. Else, we will - * have to map the buffers to ISA memory which is only 16 MB - */ dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM; -#endif SET_NETDEV_DEV(dev, &pdev->dev); @@ -2611,16 +2686,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %s\n", mp->port_num, print_mac(mac, dev->dev_addr)); - if (dev->features & NETIF_F_SG) - dev_printk(KERN_NOTICE, &dev->dev, "scatter/gather enabled\n"); - - if (dev->features & NETIF_F_IP_CSUM) - dev_printk(KERN_NOTICE, &dev->dev, "tx checksum offload\n"); - -#ifdef MV643XX_ETH_NAPI - dev_printk(KERN_NOTICE, &dev->dev, "napi enabled\n"); -#endif - if (mp->tx_desc_sram_size > 0) dev_printk(KERN_NOTICE, &dev->dev, "configured with sram\n"); @@ -2637,6 +2702,8 @@ static int mv643xx_eth_remove(struct platform_device *pdev) struct mv643xx_eth_private *mp = platform_get_drvdata(pdev); unregister_netdev(mp->dev); + if (mp->phy != NULL) + phy_detach(mp->phy); flush_scheduled_work(); free_netdev(mp->dev); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index d6524db321a..a9aebad5265 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -75,7 +75,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.4.3-1.358" +#define MYRI10GE_VERSION_STR "1.4.3-1.369" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -102,6 +102,8 @@ MODULE_LICENSE("Dual BSD/GPL"); #define MYRI10GE_ALLOC_SIZE ((1 << MYRI10GE_ALLOC_ORDER) * PAGE_SIZE) #define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1) +#define MYRI10GE_MAX_SLICES 32 + struct myri10ge_rx_buffer_state { struct page *page; int page_offset; @@ -138,6 +140,8 @@ struct myri10ge_rx_buf { struct myri10ge_tx_buf { struct mcp_kreq_ether_send __iomem *lanai; /* lanai ptr for sendq */ + __be32 __iomem *send_go; /* "go" doorbell ptr */ + __be32 __iomem *send_stop; /* "stop" doorbell ptr */ struct mcp_kreq_ether_send *req_list; /* host shadow of sendq */ char *req_bytes; struct myri10ge_tx_buffer_state *info; @@ -149,6 +153,7 @@ struct myri10ge_tx_buf { int done ____cacheline_aligned; /* transmit slots completed */ int pkt_done; /* packets completed */ int wake_queue; + int queue_active; }; struct myri10ge_rx_done { @@ -183,7 +188,7 @@ struct myri10ge_slice_state { dma_addr_t fw_stats_bus; int watchdog_tx_done; int watchdog_tx_req; -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA int cached_dca_tag; int cpu; __be32 __iomem *dca_tag; @@ -215,7 +220,7 @@ struct myri10ge_priv { int msi_enabled; int msix_enabled; struct msix_entry *msix_vectors; -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA int dca_enabled; #endif u32 link_state; @@ -418,6 +423,12 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, return -ENOSYS; } else if (result == MXGEFW_CMD_ERROR_UNALIGNED) { return -E2BIG; + } else if (result == MXGEFW_CMD_ERROR_RANGE && + cmd == MXGEFW_CMD_ENABLE_RSS_QUEUES && + (data-> + data1 & MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES) != + 0) { + return -ERANGE; } else { dev_err(&mgp->pdev->dev, "command %d failed, result = %d\n", @@ -891,7 +902,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) struct myri10ge_slice_state *ss; int i, status; size_t bytes; -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA unsigned long dca_tag_off; #endif @@ -947,9 +958,24 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) */ cmd.data0 = mgp->num_slices; - cmd.data1 = 1; /* use MSI-X */ + cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; + if (mgp->dev->real_num_tx_queues > 1) + cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES, &cmd, 0); + + /* Firmware older than 1.4.32 only supports multiple + * RX queues, so if we get an error, first retry using a + * single TX queue before giving up */ + if (status != 0 && mgp->dev->real_num_tx_queues > 1) { + mgp->dev->real_num_tx_queues = 1; + cmd.data0 = mgp->num_slices; + cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; + status = myri10ge_send_cmd(mgp, + MXGEFW_CMD_ENABLE_RSS_QUEUES, + &cmd, 0); + } + if (status != 0) { dev_err(&mgp->pdev->dev, "failed to set number of slices\n"); @@ -986,7 +1012,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) } put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_DCA_OFFSET, &cmd, 0); dca_tag_off = cmd.data0; for (i = 0; i < mgp->num_slices; i++) { @@ -1025,7 +1051,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) return status; } -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA static void myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag) { @@ -1060,8 +1086,9 @@ static void myri10ge_setup_dca(struct myri10ge_priv *mgp) } err = dca_add_requester(&pdev->dev); if (err) { - dev_err(&pdev->dev, - "dca_add_requester() failed, err=%d\n", err); + if (err != -ENODEV) + dev_err(&pdev->dev, + "dca_add_requester() failed, err=%d\n", err); return; } mgp->dca_enabled = 1; @@ -1316,6 +1343,7 @@ myri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index) { struct pci_dev *pdev = ss->mgp->pdev; struct myri10ge_tx_buf *tx = &ss->tx; + struct netdev_queue *dev_queue; struct sk_buff *skb; int idx, len; @@ -1349,11 +1377,31 @@ myri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index) PCI_DMA_TODEVICE); } } + + dev_queue = netdev_get_tx_queue(ss->dev, ss - ss->mgp->ss); + /* + * Make a minimal effort to prevent the NIC from polling an + * idle tx queue. If we can't get the lock we leave the queue + * active. In this case, either a thread was about to start + * using the queue anyway, or we lost a race and the NIC will + * waste some of its resources polling an inactive queue for a + * while. + */ + + if ((ss->mgp->dev->real_num_tx_queues > 1) && + __netif_tx_trylock(dev_queue)) { + if (tx->req == tx->done) { + tx->queue_active = 0; + put_be32(htonl(1), tx->send_stop); + } + __netif_tx_unlock(dev_queue); + } + /* start the queue if we've stopped it */ - if (netif_queue_stopped(ss->dev) + if (netif_tx_queue_stopped(dev_queue) && tx->req - tx->done < (tx->mask >> 1)) { tx->wake_queue++; - netif_wake_queue(ss->dev); + netif_tx_wake_queue(dev_queue); } } @@ -1457,7 +1505,7 @@ static int myri10ge_poll(struct napi_struct *napi, int budget) struct net_device *netdev = ss->mgp->dev; int work_done; -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA if (ss->mgp->dca_enabled) myri10ge_update_dca(ss); #endif @@ -1481,9 +1529,9 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) u32 send_done_count; int i; - /* an interrupt on a non-zero slice is implicitly valid - * since MSI-X irqs are not shared */ - if (ss != mgp->ss) { + /* an interrupt on a non-zero receive-only slice is implicitly + * valid since MSI-X irqs are not shared */ + if ((mgp->dev->real_num_tx_queues == 1) && (ss != mgp->ss)) { netif_rx_schedule(ss->dev, &ss->napi); return (IRQ_HANDLED); } @@ -1525,7 +1573,9 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) barrier(); } - myri10ge_check_statblock(mgp); + /* Only slice 0 updates stats */ + if (ss == mgp->ss) + myri10ge_check_statblock(mgp); put_be32(htonl(3), ss->irq_claim + 1); return (IRQ_HANDLED); @@ -1686,8 +1736,8 @@ static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = { "tx_boundary", "WC", "irq", "MSI", "MSIX", "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs", "serial_number", "watchdog_resets", -#ifdef CONFIG_DCA - "dca_capable", "dca_enabled", +#ifdef CONFIG_MYRI10GE_DCA + "dca_capable_firmware", "dca_device_present", #endif "link_changes", "link_up", "dropped_link_overflow", "dropped_link_error_or_filtered", @@ -1765,7 +1815,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)mgp->read_write_dma; data[i++] = (unsigned int)mgp->serial_number; data[i++] = (unsigned int)mgp->watchdog_resets; -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL); data[i++] = (unsigned int)(mgp->dca_enabled); #endif @@ -1883,6 +1933,7 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) /* ensure req_list entries are aligned to 8 bytes */ ss->tx.req_list = (struct mcp_kreq_ether_send *) ALIGN((unsigned long)ss->tx.req_bytes, 8); + ss->tx.queue_active = 0; bytes = rx_ring_entries * sizeof(*ss->rx_small.shadow); ss->rx_small.shadow = kzalloc(bytes, GFP_KERNEL); @@ -2200,11 +2251,14 @@ static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice) int status; ss = &mgp->ss[slice]; - cmd.data0 = 0; /* single slice for now */ - status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0); - ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *) - (mgp->sram + cmd.data0); - + status = 0; + if (slice == 0 || (mgp->dev->real_num_tx_queues > 1)) { + cmd.data0 = slice; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, + &cmd, 0); + ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *) + (mgp->sram + cmd.data0); + } cmd.data0 = slice; status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd, 0); @@ -2216,6 +2270,10 @@ static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice) ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *) (mgp->sram + cmd.data0); + ss->tx.send_go = (__iomem __be32 *) + (mgp->sram + MXGEFW_ETH_SEND_GO + 64 * slice); + ss->tx.send_stop = (__iomem __be32 *) + (mgp->sram + MXGEFW_ETH_SEND_STOP + 64 * slice); return status; } @@ -2229,7 +2287,7 @@ static int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice) ss = &mgp->ss[slice]; cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus); cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus); - cmd.data2 = sizeof(struct mcp_irq_data); + cmd.data2 = sizeof(struct mcp_irq_data) | (slice << 16); status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0); if (status == -ENOSYS) { dma_addr_t bus = ss->fw_stats_bus; @@ -2270,7 +2328,9 @@ static int myri10ge_open(struct net_device *dev) if (mgp->num_slices > 1) { cmd.data0 = mgp->num_slices; - cmd.data1 = 1; /* use MSI-X */ + cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; + if (mgp->dev->real_num_tx_queues > 1) + cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES, &cmd, 0); if (status != 0) { @@ -2291,6 +2351,7 @@ static int myri10ge_open(struct net_device *dev) printk(KERN_ERR "myri10ge: %s: failed to setup rss tables\n", dev->name); + goto abort_with_nothing; } /* just enable an identity mapping */ @@ -2361,7 +2422,11 @@ static int myri10ge_open(struct net_device *dev) status = myri10ge_allocate_rings(ss); if (status != 0) goto abort_with_rings; - if (slice == 0) + + /* only firmware which supports multiple TX queues + * supports setting up the tx stats on non-zero + * slices */ + if (slice == 0 || mgp->dev->real_num_tx_queues > 1) status = myri10ge_set_stats(mgp, slice); if (status) { printk(KERN_ERR @@ -2427,7 +2492,8 @@ static int myri10ge_open(struct net_device *dev) mgp->running = MYRI10GE_ETH_RUNNING; mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ; add_timer(&mgp->watchdog_timer); - netif_wake_queue(dev); + netif_tx_wake_all_queues(dev); + return 0; abort_with_rings: @@ -2460,7 +2526,8 @@ static int myri10ge_close(struct net_device *dev) napi_disable(&mgp->ss[i].napi); } netif_carrier_off(dev); - netif_stop_queue(dev); + + netif_tx_stop_all_queues(dev); old_down_cnt = mgp->down_cnt; mb(); status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0); @@ -2565,18 +2632,21 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) struct mcp_kreq_ether_send *req; struct myri10ge_tx_buf *tx; struct skb_frag_struct *frag; + struct netdev_queue *netdev_queue; dma_addr_t bus; u32 low; __be32 high_swapped; unsigned int len; int idx, last_idx, avail, frag_cnt, frag_idx, count, mss, max_segments; - u16 pseudo_hdr_offset, cksum_offset; + u16 pseudo_hdr_offset, cksum_offset, queue; int cum_len, seglen, boundary, rdma_count; u8 flags, odd_flag; - /* always transmit through slot 0 */ - ss = mgp->ss; + queue = skb_get_queue_mapping(skb); + ss = &mgp->ss[queue]; + netdev_queue = netdev_get_tx_queue(mgp->dev, queue); tx = &ss->tx; + again: req = tx->req_list; avail = tx->mask - 1 - (tx->req - tx->done); @@ -2592,7 +2662,7 @@ again: if ((unlikely(avail < max_segments))) { /* we are out of transmit resources */ tx->stop_queue++; - netif_stop_queue(dev); + netif_tx_stop_queue(netdev_queue); return 1; } @@ -2785,10 +2855,16 @@ again: idx = ((count - 1) + tx->req) & tx->mask; tx->info[idx].last = 1; myri10ge_submit_req(tx, tx->req_list, count); + /* if using multiple tx queues, make sure NIC polls the + * current slice */ + if ((mgp->dev->real_num_tx_queues > 1) && tx->queue_active == 0) { + tx->queue_active = 1; + put_be32(htonl(1), tx->send_go); + } tx->pkt_start++; if ((avail - count) < MXGEFW_MAX_SEND_DESC) { tx->stop_queue++; - netif_stop_queue(dev); + netif_tx_stop_queue(netdev_queue); } dev->trans_start = jiffies; return 0; @@ -3366,20 +3442,21 @@ static void myri10ge_watchdog(struct work_struct *work) for (i = 0; i < mgp->num_slices; i++) { tx = &mgp->ss[i].tx; printk(KERN_INFO - "myri10ge: %s: (%d): %d %d %d %d %d\n", - mgp->dev->name, i, tx->req, tx->done, - tx->pkt_start, tx->pkt_done, + "myri10ge: %s: (%d): %d %d %d %d %d %d\n", + mgp->dev->name, i, tx->queue_active, tx->req, + tx->done, tx->pkt_start, tx->pkt_done, (int)ntohl(mgp->ss[i].fw_stats-> send_done_count)); msleep(2000); printk(KERN_INFO - "myri10ge: %s: (%d): %d %d %d %d %d\n", - mgp->dev->name, i, tx->req, tx->done, - tx->pkt_start, tx->pkt_done, + "myri10ge: %s: (%d): %d %d %d %d %d %d\n", + mgp->dev->name, i, tx->queue_active, tx->req, + tx->done, tx->pkt_start, tx->pkt_done, (int)ntohl(mgp->ss[i].fw_stats-> send_done_count)); } } + rtnl_lock(); myri10ge_close(mgp->dev); status = myri10ge_load_firmware(mgp, 1); @@ -3434,10 +3511,14 @@ static void myri10ge_watchdog_timer(unsigned long arg) /* nic seems like it might be stuck.. */ if (rx_pause_cnt != mgp->watchdog_pause) { if (net_ratelimit()) - printk(KERN_WARNING "myri10ge %s:" + printk(KERN_WARNING + "myri10ge %s slice %d:" "TX paused, check link partner\n", - mgp->dev->name); + mgp->dev->name, i); } else { + printk(KERN_WARNING + "myri10ge %s slice %d stuck:", + mgp->dev->name, i); reset_needed = 1; } } @@ -3652,7 +3733,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int status = -ENXIO; int dac_enabled; - netdev = alloc_etherdev(sizeof(*mgp)); + netdev = alloc_etherdev_mq(sizeof(*mgp), MYRI10GE_MAX_SLICES); if (netdev == NULL) { dev_err(dev, "Could not allocate ethernet device\n"); return -ENOMEM; @@ -3757,13 +3838,13 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_err(&pdev->dev, "failed to alloc slice state\n"); goto abort_with_firmware; } - + netdev->real_num_tx_queues = mgp->num_slices; status = myri10ge_reset(mgp); if (status != 0) { dev_err(&pdev->dev, "failed reset\n"); goto abort_with_slices; } -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA myri10ge_setup_dca(mgp); #endif pci_set_drvdata(pdev, mgp); @@ -3781,6 +3862,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->set_multicast_list = myri10ge_set_multicast_list; netdev->set_mac_address = myri10ge_set_mac_address; netdev->features = mgp->features; + if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; @@ -3866,7 +3948,7 @@ static void myri10ge_remove(struct pci_dev *pdev) netdev = mgp->dev; unregister_netdev(netdev); -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA myri10ge_teardown_dca(mgp); #endif myri10ge_dummy_rdma(mgp, 0); @@ -3911,7 +3993,7 @@ static struct pci_driver myri10ge_driver = { #endif }; -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA static int myri10ge_notify_dca(struct notifier_block *nb, unsigned long event, void *p) { @@ -3936,16 +4018,17 @@ static __init int myri10ge_init_module(void) printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name, MYRI10GE_VERSION_STR); - if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_SRC_PORT || - myri10ge_rss_hash < MXGEFW_RSS_HASH_TYPE_IPV4) { + if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_MAX) { printk(KERN_ERR "%s: Illegal rssh hash type %d, defaulting to source port\n", myri10ge_driver.name, myri10ge_rss_hash); myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; } -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA dca_register_notify(&myri10ge_dca_notifier); #endif + if (myri10ge_max_slices > MYRI10GE_MAX_SLICES) + myri10ge_max_slices = MYRI10GE_MAX_SLICES; return pci_register_driver(&myri10ge_driver); } @@ -3954,7 +4037,7 @@ module_init(myri10ge_init_module); static __exit void myri10ge_cleanup_module(void) { -#ifdef CONFIG_DCA +#ifdef CONFIG_MYRI10GE_DCA dca_unregister_notify(&myri10ge_dca_notifier); #endif pci_unregister_driver(&myri10ge_driver); diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 656a260fc95..3ad7589d6a1 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -1,6 +1,6 @@ /* myri_sbus.c: MyriCOM MyriNET SBUS card driver. * - * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 1999, 2006, 2008 David S. Miller (davem@davemloft.net) */ static char version[] = @@ -22,6 +22,9 @@ static char version[] = #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <net/dst.h> #include <net/arp.h> @@ -33,7 +36,6 @@ static char version[] = #include <asm/dma.h> #include <asm/byteorder.h> #include <asm/idprom.h> -#include <asm/sbus.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/auxio.h> @@ -243,7 +245,8 @@ static void myri_clean_rings(struct myri_eth *mp) u32 dma_addr; dma_addr = sbus_readl(&rxd->myri_scatters[0].addr); - sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); + dma_unmap_single(&mp->myri_op->dev, dma_addr, + RX_ALLOC_SIZE, DMA_FROM_DEVICE); dev_kfree_skb(mp->rx_skbs[i]); mp->rx_skbs[i] = NULL; } @@ -259,7 +262,9 @@ static void myri_clean_rings(struct myri_eth *mp) u32 dma_addr; dma_addr = sbus_readl(&txd->myri_gathers[0].addr); - sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE); + dma_unmap_single(&mp->myri_op->dev, dma_addr, + (skb->len + 3) & ~3, + DMA_TO_DEVICE); dev_kfree_skb(mp->tx_skbs[i]); mp->tx_skbs[i] = NULL; } @@ -288,7 +293,9 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq) skb->dev = dev; skb_put(skb, RX_ALLOC_SIZE); - dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); + dma_addr = dma_map_single(&mp->myri_op->dev, + skb->data, RX_ALLOC_SIZE, + DMA_FROM_DEVICE); sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr); sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len); sbus_writel(i, &rxd[i].ctx); @@ -344,7 +351,8 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev) DTX(("SKB[%d] ", entry)); dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr); - sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE); + dma_unmap_single(&mp->myri_op->dev, dma_addr, + skb->len, DMA_TO_DEVICE); dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; dev->stats.tx_packets++; @@ -423,9 +431,9 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) /* Check for errors. */ DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum)); - sbus_dma_sync_single_for_cpu(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&mp->myri_op->dev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, DMA_FROM_DEVICE); if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) { DRX(("ERROR[")); dev->stats.rx_errors++; @@ -442,10 +450,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) drops++; DRX(("DROP ")); dev->stats.rx_dropped++; - sbus_dma_sync_single_for_device(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, - SBUS_DMA_FROMDEVICE); + dma_sync_single_for_device(&mp->myri_op->dev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + DMA_FROM_DEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); @@ -464,17 +472,17 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) DRX(("skb_alloc(FAILED) ")); goto drop_it; } - sbus_unmap_single(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, - SBUS_DMA_FROMDEVICE); + dma_unmap_single(&mp->myri_op->dev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + DMA_FROM_DEVICE); mp->rx_skbs[index] = new_skb; new_skb->dev = dev; skb_put(new_skb, RX_ALLOC_SIZE); - dma_addr = sbus_map_single(mp->myri_sdev, - new_skb->data, - RX_ALLOC_SIZE, - SBUS_DMA_FROMDEVICE); + dma_addr = dma_map_single(&mp->myri_op->dev, + new_skb->data, + RX_ALLOC_SIZE, + DMA_FROM_DEVICE); sbus_writel(dma_addr, &rxd->myri_scatters[0].addr); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); @@ -500,10 +508,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) /* Reuse original ring buffer. */ DRX(("reuse ")); - sbus_dma_sync_single_for_device(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, - SBUS_DMA_FROMDEVICE); + dma_sync_single_for_device(&mp->myri_op->dev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + DMA_FROM_DEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); @@ -652,7 +660,8 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]); } - dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE); + dma_addr = dma_map_single(&mp->myri_op->dev, skb->data, + len, DMA_TO_DEVICE); sbus_writel(dma_addr, &txd->myri_gathers[0].addr); sbus_writel(len, &txd->myri_gathers[0].len); sbus_writel(1, &txd->num_sg); @@ -891,30 +900,30 @@ static const struct header_ops myri_header_ops = { .cache_update = myri_header_cache_update, }; -static int __devinit myri_ether_init(struct sbus_dev *sdev) +static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match) { - static int num; + struct device_node *dp = op->node; static unsigned version_printed; struct net_device *dev; - struct myri_eth *mp; - unsigned char prop_buf[32]; - int i; DECLARE_MAC_BUF(mac); + struct myri_eth *mp; + const void *prop; + static int num; + int i, len; - DET(("myri_ether_init(%p,%d):\n", sdev, num)); + DET(("myri_ether_init(%p,%d):\n", op, num)); dev = alloc_etherdev(sizeof(struct myri_eth)); - if (!dev) return -ENOMEM; if (version_printed++ == 0) printk(version); - SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); - mp = (struct myri_eth *) dev->priv; + mp = netdev_priv(dev); spin_lock_init(&mp->irq_lock); - mp->myri_sdev = sdev; + mp->myri_op = op; /* Clean out skb arrays. */ for (i = 0; i < (RX_RING_SIZE + 1); i++) @@ -924,55 +933,44 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) mp->tx_skbs[i] = NULL; /* First check for EEPROM information. */ - i = prom_getproperty(sdev->prom_node, "myrinet-eeprom-info", - (char *)&mp->eeprom, sizeof(struct myri_eeprom)); - DET(("prom_getprop(myrinet-eeprom-info) returns %d\n", i)); - if (i == 0 || i == -1) { + prop = of_get_property(dp, "myrinet-eeprom-info", &len); + + if (prop) + memcpy(&mp->eeprom, prop, sizeof(struct myri_eeprom)); + if (!prop) { /* No eeprom property, must cook up the values ourselves. */ DET(("No EEPROM: ")); mp->eeprom.bus_type = BUS_TYPE_SBUS; - mp->eeprom.cpuvers = prom_getintdefault(sdev->prom_node,"cpu_version",0); - mp->eeprom.cval = prom_getintdefault(sdev->prom_node,"clock_value",0); - mp->eeprom.ramsz = prom_getintdefault(sdev->prom_node,"sram_size",0); - DET(("cpuvers[%d] cval[%d] ramsz[%d]\n", mp->eeprom.cpuvers, - mp->eeprom.cval, mp->eeprom.ramsz)); - if (mp->eeprom.cpuvers == 0) { - DET(("EEPROM: cpuvers was zero, setting to %04x\n",CPUVERS_2_3)); + mp->eeprom.cpuvers = + of_getintprop_default(dp, "cpu_version", 0); + mp->eeprom.cval = + of_getintprop_default(dp, "clock_value", 0); + mp->eeprom.ramsz = of_getintprop_default(dp, "sram_size", 0); + if (!mp->eeprom.cpuvers) mp->eeprom.cpuvers = CPUVERS_2_3; - } - if (mp->eeprom.cpuvers < CPUVERS_3_0) { - DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n")); + if (mp->eeprom.cpuvers < CPUVERS_3_0) mp->eeprom.cval = 0; - } - if (mp->eeprom.ramsz == 0) { - DET(("EEPROM: ramsz == 0, setting to 128k\n")); + if (!mp->eeprom.ramsz) mp->eeprom.ramsz = (128 * 1024); - } - i = prom_getproperty(sdev->prom_node, "myrinet-board-id", - &prop_buf[0], 10); - DET(("EEPROM: prom_getprop(myrinet-board-id) returns %d\n", i)); - if ((i != 0) && (i != -1)) - memcpy(&mp->eeprom.id[0], &prop_buf[0], 6); + + prop = of_get_property(dp, "myrinet-board-id", &len); + if (prop) + memcpy(&mp->eeprom.id[0], prop, 6); else set_boardid_from_idprom(mp, num); - i = prom_getproperty(sdev->prom_node, "fpga_version", - &mp->eeprom.fvers[0], 32); - DET(("EEPROM: prom_getprop(fpga_version) returns %d\n", i)); - if (i == 0 || i == -1) + + prop = of_get_property(dp, "fpga_version", &len); + if (prop) + memcpy(&mp->eeprom.fvers[0], prop, 32); + else memset(&mp->eeprom.fvers[0], 0, 32); if (mp->eeprom.cpuvers == CPUVERS_4_1) { - DET(("EEPROM: cpuvers CPUVERS_4_1, ")); - if (mp->eeprom.ramsz == (128 * 1024)) { - DET(("ramsize 128k, setting to 256k, ")); + if (mp->eeprom.ramsz == (128 * 1024)) mp->eeprom.ramsz = (256 * 1024); - } - if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){ - DET(("changing cval from %08x to %08x ", - mp->eeprom.cval, 0x50e450e4)); + if ((mp->eeprom.cval == 0x40414041) || + (mp->eeprom.cval == 0x90449044)) mp->eeprom.cval = 0x50e450e4; - } - DET(("\n")); } } #ifdef DEBUG_DETECT @@ -991,8 +989,8 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) * XXX only a valid version for PCI cards? Ask feldy... */ DET(("Mapping regs for cpuvers < CPUVERS_4_0\n")); - mp->regs = sbus_ioremap(&sdev->resource[0], 0, - mp->reg_size, "MyriCOM Regs"); + mp->regs = of_ioremap(&op->resource[0], 0, + mp->reg_size, "MyriCOM Regs"); if (!mp->regs) { printk("MyriCOM: Cannot map MyriCOM registers.\n"); goto err; @@ -1001,13 +999,12 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) mp->lregs = mp->lanai + (0x10000 * 2); } else { DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n")); - mp->cregs = sbus_ioremap(&sdev->resource[0], 0, - PAGE_SIZE, "MyriCOM Control Regs"); - mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024), + mp->cregs = of_ioremap(&op->resource[0], 0, + PAGE_SIZE, "MyriCOM Control Regs"); + mp->lregs = of_ioremap(&op->resource[0], (256 * 1024), PAGE_SIZE, "MyriCOM LANAI Regs"); - mp->lanai = - sbus_ioremap(&sdev->resource[0], (512 * 1024), - mp->eeprom.ramsz, "MyriCOM SRAM"); + mp->lanai = of_ioremap(&op->resource[0], (512 * 1024), + mp->eeprom.ramsz, "MyriCOM SRAM"); } DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n", mp->cregs, mp->lregs, mp->lanai)); @@ -1039,16 +1036,15 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) myri_reset_on(mp->cregs); /* Get the supported DVMA burst sizes from our SBUS. */ - mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node, - "burst-sizes", 0x00); - - if (!sbus_can_burst64(sdev)) + mp->myri_bursts = of_getintprop_default(dp->parent, + "burst-sizes", 0x00); + if (!sbus_can_burst64()) mp->myri_bursts &= ~(DMA_BURST64); DET(("MYRI bursts %02x\n", mp->myri_bursts)); /* Encode SBUS interrupt level in second control register. */ - i = prom_getint(sdev->prom_node, "interrupts"); + i = of_getintprop_default(dp, "interrupts", 0); if (i == 0) i = 4; DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n", @@ -1063,7 +1059,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) dev->tx_timeout = &myri_tx_timeout; dev->watchdog_timeo = 5*HZ; dev->set_multicast_list = &myri_set_multicast; - dev->irq = sdev->irqs[0]; + dev->irq = op->irqs[0]; /* Register interrupt handler now. */ DET(("Requesting MYRIcom IRQ line.\n")); @@ -1088,7 +1084,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) goto err_free_irq; } - dev_set_drvdata(&sdev->ofdev.dev, mp); + dev_set_drvdata(&op->dev, mp); num++; @@ -1105,39 +1101,31 @@ err: return -ENODEV; } - -static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - - return myri_ether_init(sdev); -} - -static int __devexit myri_sbus_remove(struct of_device *dev) +static int __devexit myri_sbus_remove(struct of_device *op) { - struct myri_eth *mp = dev_get_drvdata(&dev->dev); + struct myri_eth *mp = dev_get_drvdata(&op->dev); struct net_device *net_dev = mp->dev; - unregister_netdevice(net_dev); + unregister_netdev(net_dev); free_irq(net_dev->irq, net_dev); if (mp->eeprom.cpuvers < CPUVERS_4_0) { - sbus_iounmap(mp->regs, mp->reg_size); + of_iounmap(&op->resource[0], mp->regs, mp->reg_size); } else { - sbus_iounmap(mp->cregs, PAGE_SIZE); - sbus_iounmap(mp->lregs, (256 * 1024)); - sbus_iounmap(mp->lanai, (512 * 1024)); + of_iounmap(&op->resource[0], mp->cregs, PAGE_SIZE); + of_iounmap(&op->resource[0], mp->lregs, (256 * 1024)); + of_iounmap(&op->resource[0], mp->lanai, (512 * 1024)); } free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id myri_sbus_match[] = { +static const struct of_device_id myri_sbus_match[] = { { .name = "MYRICOM,mlanai", }, @@ -1158,7 +1146,7 @@ static struct of_platform_driver myri_sbus_driver = { static int __init myri_sbus_init(void) { - return of_register_driver(&myri_sbus_driver, &sbus_bus_type); + return of_register_driver(&myri_sbus_driver, &of_bus_type); } static void __exit myri_sbus_exit(void) diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h index 5d93fcc95d5..ff363e95d9c 100644 --- a/drivers/net/myri_sbus.h +++ b/drivers/net/myri_sbus.h @@ -288,7 +288,7 @@ struct myri_eth { struct myri_eeprom eeprom; /* Local copy of EEPROM. */ unsigned int reg_size; /* Size of register space. */ unsigned int shmem_base; /* Offset to shared ram. */ - struct sbus_dev *myri_sdev; /* Our SBUS device struct. */ + struct of_device *myri_op; /* Our OF device struct. */ }; /* We use this to acquire receive skb's that we can DMA directly into. */ diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index b238ed0e8ac..f7fa3944659 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -612,7 +612,7 @@ static void undo_cable_magic(struct net_device *dev); static void check_link(struct net_device *dev); static void netdev_timer(unsigned long data); static void dump_ring(struct net_device *dev); -static void tx_timeout(struct net_device *dev); +static void ns_tx_timeout(struct net_device *dev); static int alloc_ring(struct net_device *dev); static void refill_rx(struct net_device *dev); static void init_ring(struct net_device *dev); @@ -920,7 +920,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev->set_multicast_list = &set_rx_mode; dev->change_mtu = &natsemi_change_mtu; dev->do_ioctl = &netdev_ioctl; - dev->tx_timeout = &tx_timeout; + dev->tx_timeout = &ns_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1875,7 +1875,7 @@ static void dump_ring(struct net_device *dev) } } -static void tx_timeout(struct net_device *dev) +static void ns_tx_timeout(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); @@ -3232,7 +3232,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) * suspend/resume synchronization: * entry points: * netdev_open, netdev_close, netdev_ioctl, set_rx_mode, intr_handler, - * start_tx, tx_timeout + * start_tx, ns_tx_timeout * * No function accesses the hardware without checking np->hands_off. * the check occurs under spin_lock_irq(&np->lock); diff --git a/drivers/net/ne.c b/drivers/net/ne.c index fa3ceca4e15..eb681c0d51b 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -64,6 +64,25 @@ static const char version2[] = /* Do we support clones that don't adhere to 14,15 of the SAprom ? */ #define SUPPORT_NE_BAD_CLONES +/* 0xbad = bad sig or no reset ack */ +#define BAD 0xbad + +#define MAX_NE_CARDS 4 /* Max number of NE cards per module */ +static struct platform_device *pdev_ne[MAX_NE_CARDS]; +static int io[MAX_NE_CARDS]; +static int irq[MAX_NE_CARDS]; +static int bad[MAX_NE_CARDS]; + +#ifdef MODULE +module_param_array(io, int, NULL, 0); +module_param_array(irq, int, NULL, 0); +module_param_array(bad, int, NULL, 0); +MODULE_PARM_DESC(io, "I/O base address(es),required"); +MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures"); +MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver"); +MODULE_LICENSE("GPL"); +#endif /* MODULE */ /* Do we perform extra sanity checks on stuff ? */ /* #define NE_SANITY_CHECK */ @@ -74,6 +93,10 @@ static const char version2[] = /* Do we have a non std. amount of memory? (in units of 256 byte pages) */ /* #define PACKETBUF_MEMSIZE 0x40 */ +/* This is set up so that no ISA autoprobe takes place. We can't guarantee +that the ne2k probe is the last 8390 based probe to take place (as it +is at boot) and so the probe will get confused by any other 8390 cards. +ISA device autoprobes on a running machine are not recommended anyway. */ #if !defined(MODULE) && (defined(CONFIG_ISA) || defined(CONFIG_M32R)) /* Do we need a portlist for the ISA auto-probe ? */ #define NEEDS_PORTLIST @@ -192,8 +215,13 @@ static int __init do_ne_probe(struct net_device *dev) #endif /* First check any supplied i/o locations. User knows best. <cough> */ - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ne_probe1(dev, base_addr); + if (base_addr > 0x1ff) { /* Check a single specified location. */ + int ret = ne_probe1(dev, base_addr); + if (ret) + printk(KERN_WARNING "ne.c: No NE*000 card found at " + "i/o = %#lx\n", base_addr); + return ret; + } else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; @@ -214,28 +242,6 @@ static int __init do_ne_probe(struct net_device *dev) return -ENODEV; } -#ifndef MODULE -struct net_device * __init ne_probe(int unit) -{ - struct net_device *dev = alloc_eip_netdev(); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - err = do_ne_probe(dev); - if (err) - goto out; - return dev; -out: - free_netdev(dev); - return ERR_PTR(err); -} -#endif - static int __init ne_probe_isapnp(struct net_device *dev) { int i; @@ -329,7 +335,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) with an otherwise unused dev->mem_end value of "0xBAD" will cause the driver to skip these parts of the probe. */ - bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad)); + bad_card = ((dev->base_addr != 0) && (dev->mem_end == BAD)); /* Reset card. Who knows what dain-bramaged state it was left in. */ @@ -806,46 +812,95 @@ retry: static int __init ne_drv_probe(struct platform_device *pdev) { struct net_device *dev; + int err, this_dev = pdev->id; struct resource *res; - int err, irq; - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - irq = platform_get_irq(pdev, 0); - if (!res || irq < 0) - return -ENODEV; dev = alloc_eip_netdev(); if (!dev) return -ENOMEM; - dev->irq = irq; - dev->base_addr = res->start; + + /* ne.c doesn't populate resources in platform_device, but + * rbtx4927_ne_init and rbtx4938_ne_init do register devices + * with resources. + */ + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (res) { + dev->base_addr = res->start; + dev->irq = platform_get_irq(pdev, 0); + } else { + if (this_dev < 0 || this_dev >= MAX_NE_CARDS) + return -EINVAL; + dev->base_addr = io[this_dev]; + dev->irq = irq[this_dev]; + dev->mem_end = bad[this_dev]; + } err = do_ne_probe(dev); if (err) { free_netdev(dev); return err; } platform_set_drvdata(pdev, dev); + + /* Update with any values found by probing, don't update if + * resources were specified. + */ + if (!res) { + io[this_dev] = dev->base_addr; + irq[this_dev] = dev->irq; + } return 0; } -static int __exit ne_drv_remove(struct platform_device *pdev) +static int ne_drv_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); - unregister_netdev(dev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); - free_netdev(dev); + if (dev) { + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + netif_device_detach(dev); + unregister_netdev(dev); + if (idev) + pnp_device_detach(idev); + /* Careful ne_drv_remove can be called twice, once from + * the platform_driver.remove and again when the + * platform_device is being removed. + */ + ei_status.priv = 0; + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); + free_netdev(dev); + platform_set_drvdata(pdev, NULL); + } return 0; } +/* Remove unused devices or all if true. */ +static void ne_loop_rm_unreg(int all) +{ + int this_dev; + struct platform_device *pdev; + for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { + pdev = pdev_ne[this_dev]; + /* No network device == unused */ + if (pdev && (!platform_get_drvdata(pdev) || all)) { + ne_drv_remove(pdev); + platform_device_unregister(pdev); + pdev_ne[this_dev] = NULL; + } + } +} + #ifdef CONFIG_PM static int ne_drv_suspend(struct platform_device *pdev, pm_message_t state) { struct net_device *dev = platform_get_drvdata(pdev); - if (netif_running(dev)) + if (netif_running(dev)) { + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; netif_device_detach(dev); + if (idev) + pnp_stop_dev(idev); + } return 0; } @@ -854,6 +909,9 @@ static int ne_drv_resume(struct platform_device *pdev) struct net_device *dev = platform_get_drvdata(pdev); if (netif_running(dev)) { + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_start_dev(idev); ne_reset_8390(dev); NS8390p_init(dev, 1); netif_device_attach(dev); @@ -866,7 +924,7 @@ static int ne_drv_resume(struct platform_device *pdev) #endif static struct platform_driver ne_driver = { - .remove = __exit_p(ne_drv_remove), + .remove = ne_drv_remove, .suspend = ne_drv_suspend, .resume = ne_drv_resume, .driver = { @@ -875,91 +933,96 @@ static struct platform_driver ne_driver = { }, }; -static int __init ne_init(void) +static void __init ne_add_devices(void) { - return platform_driver_probe(&ne_driver, ne_drv_probe); -} + int this_dev; + struct platform_device *pdev; -static void __exit ne_exit(void) -{ - platform_driver_unregister(&ne_driver); + for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { + if (pdev_ne[this_dev]) + continue; + pdev = platform_device_register_simple( + DRV_NAME, this_dev, NULL, 0); + if (IS_ERR(pdev)) + continue; + pdev_ne[this_dev] = pdev; + } } #ifdef MODULE -#define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device *dev_ne[MAX_NE_CARDS]; -static int io[MAX_NE_CARDS]; -static int irq[MAX_NE_CARDS]; -static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ - -module_param_array(io, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -module_param_array(bad, int, NULL, 0); -MODULE_PARM_DESC(io, "I/O base address(es),required"); -MODULE_PARM_DESC(irq, "IRQ number(s)"); -MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures"); -MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver"); -MODULE_LICENSE("GPL"); - -/* This is set up so that no ISA autoprobe takes place. We can't guarantee -that the ne2k probe is the last 8390 based probe to take place (as it -is at boot) and so the probe will get confused by any other 8390 cards. -ISA device autoprobes on a running machine are not recommended anyway. */ - -int __init init_module(void) +int __init init_module() { - int this_dev, found = 0; - int plat_found = !ne_init(); - - for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = alloc_eip_netdev(); - if (!dev) - break; - dev->irq = irq[this_dev]; - dev->mem_end = bad[this_dev]; - dev->base_addr = io[this_dev]; - if (do_ne_probe(dev) == 0) { - dev_ne[found++] = dev; - continue; - } - free_netdev(dev); - if (found || plat_found) - break; - if (io[this_dev] != 0) - printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]); - else - printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); - return -ENXIO; + int retval; + ne_add_devices(); + retval = platform_driver_probe(&ne_driver, ne_drv_probe); + if (retval) { + if (io[0] == 0) + printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\"" + " value(s) for ISA cards.\n"); + ne_loop_rm_unreg(1); + return retval; } - if (found || plat_found) - return 0; - return -ENODEV; -} -static void cleanup_card(struct net_device *dev) + /* Unregister unused platform_devices. */ + ne_loop_rm_unreg(0); + return retval; +} +#else /* MODULE */ +static int __init ne_init(void) { - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); + int retval = platform_driver_probe(&ne_driver, ne_drv_probe); + + /* Unregister unused platform_devices. */ + ne_loop_rm_unreg(0); + return retval; } +module_init(ne_init); -void __exit cleanup_module(void) +struct net_device * __init ne_probe(int unit) { int this_dev; + struct net_device *dev; + + /* Find an empty slot, that is no net_device and zero io port. */ + this_dev = 0; + while ((pdev_ne[this_dev] && platform_get_drvdata(pdev_ne[this_dev])) || + io[this_dev]) { + if (++this_dev == MAX_NE_CARDS) + return ERR_PTR(-ENOMEM); + } + + /* Get irq, io from kernel command line */ + dev = alloc_eip_netdev(); + if (!dev) + return ERR_PTR(-ENOMEM); - ne_exit(); + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + io[this_dev] = dev->base_addr; + irq[this_dev] = dev->irq; + bad[this_dev] = dev->mem_end; + + free_netdev(dev); + + ne_add_devices(); + + /* return the first device found */ for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = dev_ne[this_dev]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); + if (pdev_ne[this_dev]) { + dev = platform_get_drvdata(pdev_ne[this_dev]); + if (dev) + return dev; } } + + return ERR_PTR(-ENODEV); } -#else /* MODULE */ -module_init(ne_init); -module_exit(ne_exit); #endif /* MODULE */ + +static void __exit ne_exit(void) +{ + platform_driver_unregister(&ne_driver); + ne_loop_rm_unreg(1); +} +module_exit(ne_exit); diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 3f9af759cb9..b9bed82e1d2 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -189,7 +189,7 @@ netx_eth_interrupt(int irq, void *dev_id) if ((status & ISR_CON_HI) || (status & ISR_IND_HI)) printk("%s: unexpected status: 0x%08x\n", - __FUNCTION__, status); + __func__, status); fill_level = readl(NETX_PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(priv->id))); diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 244ab49c433..f8e601c51da 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -742,7 +742,7 @@ extern char netxen_nic_driver_name[]; } while (0) #else #define DPRINTK(klevel, fmt, args...) do { \ - printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\ + printk(KERN_##klevel PFX "%s: %s: " fmt, __func__,\ (adapter != NULL && adapter->netdev != NULL) ? \ adapter->netdev->name : NULL, \ ## args); } while(0) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 008fd6618a5..6ef3f0d84bc 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -77,18 +77,18 @@ static irqreturn_t netxen_msi_intr(int irq, void *data); /* PCI Device ID Table */ #define ENTRY(device) \ - {PCI_DEVICE(0x4040, (device)), \ + {PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \ .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0} static struct pci_device_id netxen_pci_tbl[] __devinitdata = { - ENTRY(0x0001), - ENTRY(0x0002), - ENTRY(0x0003), - ENTRY(0x0004), - ENTRY(0x0005), - ENTRY(0x0024), - ENTRY(0x0025), - ENTRY(0x0100), + ENTRY(PCI_DEVICE_ID_NX2031_10GXSR), + ENTRY(PCI_DEVICE_ID_NX2031_10GCX4), + ENTRY(PCI_DEVICE_ID_NX2031_4GCU), + ENTRY(PCI_DEVICE_ID_NX2031_IMEZ), + ENTRY(PCI_DEVICE_ID_NX2031_HMEZ), + ENTRY(PCI_DEVICE_ID_NX2031_XG_MGMT), + ENTRY(PCI_DEVICE_ID_NX2031_XG_MGMT2), + ENTRY(PCI_DEVICE_ID_NX3031), {0,} }; @@ -241,7 +241,7 @@ static void netxen_check_options(struct netxen_adapter *adapter) case NETXEN_BRDTYPE_P3_REF_QG: case NETXEN_BRDTYPE_P3_4_GB: case NETXEN_BRDTYPE_P3_4_GB_MM: - adapter->msix_supported = 0; + adapter->msix_supported = !!use_msi_x; adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G; break; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index e4765b713ab..ebc81270290 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -5984,6 +5984,56 @@ static void niu_netif_start(struct niu *np) niu_enable_interrupts(np, 1); } +static void niu_reset_buffers(struct niu *np) +{ + int i, j, k, err; + + if (np->rx_rings) { + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + for (j = 0, k = 0; j < MAX_RBR_RING_SIZE; j++) { + struct page *page; + + page = rp->rxhash[j]; + while (page) { + struct page *next = + (struct page *) page->mapping; + u64 base = page->index; + base = base >> RBR_DESCR_ADDR_SHIFT; + rp->rbr[k++] = cpu_to_le32(base); + page = next; + } + } + for (; k < MAX_RBR_RING_SIZE; k++) { + err = niu_rbr_add_page(np, rp, GFP_ATOMIC, k); + if (unlikely(err)) + break; + } + + rp->rbr_index = rp->rbr_table_size - 1; + rp->rcr_index = 0; + rp->rbr_pending = 0; + rp->rbr_refill_pending = 0; + } + } + if (np->tx_rings) { + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + for (j = 0; j < MAX_TX_RING_SIZE; j++) { + if (rp->tx_buffs[j].skb) + (void) release_tx_packet(np, rp, j); + } + + rp->pending = MAX_TX_RING_SIZE; + rp->prod = 0; + rp->cons = 0; + rp->wrap_bit = 0; + } + } +} + static void niu_reset_task(struct work_struct *work) { struct niu *np = container_of(work, struct niu, reset_task); @@ -6006,6 +6056,12 @@ static void niu_reset_task(struct work_struct *work) niu_stop_hw(np); + spin_unlock_irqrestore(&np->lock, flags); + + niu_reset_buffers(np); + + spin_lock_irqsave(&np->lock, flags); + err = niu_init_hw(np); if (!err) { np->timer.expires = jiffies + HZ; @@ -9074,7 +9130,7 @@ static int __devexit niu_of_remove(struct of_device *op) return 0; } -static struct of_device_id niu_match[] = { +static const struct of_device_id niu_match[] = { { .name = "network", .compatible = "SUNW,niusl", diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 53451c3b2c0..0a575fef29e 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -119,7 +119,7 @@ KERN_INFO " Support available from http://foo.com/bar/baz.html\n"; #ifdef NETDRV_DEBUG /* note: prints function name for you */ -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif @@ -130,7 +130,7 @@ KERN_INFO " Support available from http://foo.com/bar/baz.html\n"; # define assert(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr,__FILE__,__func__,__LINE__); \ } #endif diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 7112fd5e0e1..08c4dd89607 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -355,9 +355,10 @@ static int tc574_config(struct pcmcia_device *link) for (i = j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) break; + if (i == 0) + break; } - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestIO, i); goto failed; } @@ -377,7 +378,7 @@ static int tc574_config(struct pcmcia_device *link) tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = 0x88; - if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) { + if (pcmcia_get_first_tuple(link, &tuple) == 0) { pcmcia_get_tuple_data(link, &tuple); for (i = 0; i < 3; i++) phys_addr[i] = htons(le16_to_cpu(buf[i])); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 549a6455842..c235cdba69c 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -15,7 +15,7 @@ incorporated herein by reference. Donald Becker may be reached at becker@scyld.com - Updated for 2.5.x by Alan Cox <alan@redhat.com> + Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> ======================================================================*/ @@ -278,9 +278,10 @@ static int tc589_config(struct pcmcia_device *link) if (multi && (j & 0x80)) continue; link->io.BasePort1 = j ^ 0x300; i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) break; + if (i == 0) + break; } - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestIO, i); goto failed; } @@ -295,7 +296,7 @@ static int tc589_config(struct pcmcia_device *link) /* The 3c589 has an extra EEPROM for configuration info, including the hardware address. The 3c562 puts the address in the CIS. */ tuple.DesiredTuple = 0x88; - if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) { + if (pcmcia_get_first_tuple(link, &tuple) == 0) { pcmcia_get_tuple_data(link, &tuple); for (i = 0; i < 3; i++) phys_addr[i] = htons(le16_to_cpu(buf[i])); diff --git a/drivers/net/pcmcia/Kconfig b/drivers/net/pcmcia/Kconfig index e8f55d8ed7a..9b8f793b1cc 100644 --- a/drivers/net/pcmcia/Kconfig +++ b/drivers/net/pcmcia/Kconfig @@ -111,7 +111,7 @@ config ARCNET_COM20020_CS config PCMCIA_IBMTR tristate "IBM PCMCIA tokenring adapter support" - depends on IBMTR!=y && TR && !64BIT + depends on IBMTR!=y && TR help Say Y here if you intend to attach this type of Token Ring PCMCIA card to your computer. You then also need to say Y to "Token Ring diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 52bf11b73c6..b37a498939a 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -262,7 +262,7 @@ static int try_io_port(struct pcmcia_device *link) if (link->io.NumPorts2 > 0) { /* for master/slave multifunction cards */ link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; - link->irq.Attributes = + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; } } else { @@ -276,7 +276,8 @@ static int try_io_port(struct pcmcia_device *link) link->io.BasePort1 = j ^ 0x300; link->io.BasePort2 = (j ^ 0x300) + 0x10; ret = pcmcia_request_io(link, &link->io); - if (ret == CS_SUCCESS) return ret; + if (ret == 0) + return ret; } return ret; } else { @@ -284,59 +285,50 @@ static int try_io_port(struct pcmcia_device *link) } } +static int axnet_configcheck(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + int i; + cistpl_io_t *io = &cfg->io; + + if (cfg->index == 0 || cfg->io.nwin == 0) + return -ENODEV; + + p_dev->conf.ConfigIndex = 0x05; + /* For multifunction cards, by convention, we configure the + network function with window 0, and serial with window 1 */ + if (io->nwin > 1) { + i = (io->win[1].len > io->win[0].len); + p_dev->io.BasePort2 = io->win[1-i].base; + p_dev->io.NumPorts2 = io->win[1-i].len; + } else { + i = p_dev->io.NumPorts2 = 0; + } + p_dev->io.BasePort1 = io->win[i].base; + p_dev->io.NumPorts1 = io->win[i].len; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32) + return try_io_port(p_dev); + + return -ENODEV; +} + static int axnet_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; axnet_dev_t *info = PRIV(dev); - tuple_t tuple; - cisparse_t parse; int i, j, last_ret, last_fn; - u_short buf[64]; DECLARE_MAC_BUF(mac); DEBUG(0, "axnet_config(0x%p)\n", link); - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - /* don't trust the CIS on this; Linksys got it wrong */ link->conf.Present = 0x63; - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (last_ret == CS_SUCCESS) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - cistpl_io_t *io = &(parse.cftable_entry.io); - - if (pcmcia_get_tuple_data(link, &tuple) != 0 || - pcmcia_parse_tuple(link, &tuple, &parse) != 0 || - cfg->index == 0 || cfg->io.nwin == 0) - goto next_entry; - - link->conf.ConfigIndex = 0x05; - /* For multifunction cards, by convention, we configure the - network function with window 0, and serial with window 1 */ - if (io->nwin > 1) { - i = (io->win[1].len > io->win[0].len); - link->io.BasePort2 = io->win[1-i].base; - link->io.NumPorts2 = io->win[1-i].len; - } else { - i = link->io.NumPorts2 = 0; - } - link->io.BasePort1 = io->win[i].base; - link->io.NumPorts1 = io->win[i].len; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) { - last_ret = try_io_port(link); - if (last_ret == CS_SUCCESS) break; - } - next_entry: - last_ret = pcmcia_get_next_tuple(link, &tuple); - } - if (last_ret != CS_SUCCESS) { + last_ret = pcmcia_loop_config(link, axnet_configcheck, NULL); + if (last_ret != 0) { cs_error(link, RequestIO, last_ret); goto failed; } diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index ea9414c4d90..831090c7562 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -260,21 +260,21 @@ static int com20020_config(struct pcmcia_device *link) DEBUG(0, "com20020_config(0x%p)\n", link); DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1); - i = !CS_SUCCESS; + i = -ENODEV; if (!link->io.BasePort1) { for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) { link->io.BasePort1 = ioaddr; i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) + if (i == 0) break; } } else i = pcmcia_request_io(link, &link->io); - if (i != CS_SUCCESS) + if (i != 0) { DEBUG(1,"arcnet: requestIO failed totally!\n"); goto failed; @@ -287,7 +287,7 @@ static int com20020_config(struct pcmcia_device *link) link->irq.AssignedIRQ, link->irq.IRQInfo1, link->irq.IRQInfo2); i = pcmcia_request_irq(link, &link->irq); - if (i != CS_SUCCESS) + if (i != 0) { DEBUG(1,"arcnet: requestIRQ failed totally!\n"); goto failed; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index a550c9bd126..69d916daa7b 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -309,7 +309,8 @@ static int mfc_try_io_port(struct pcmcia_device *link) printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n"); } ret = pcmcia_request_io(link, &link->io); - if (ret == CS_SUCCESS) return ret; + if (ret == 0) + return ret; } return ret; } @@ -325,7 +326,7 @@ static int ungermann_try_io_port(struct pcmcia_device *link) for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) { link->io.BasePort1 = ioaddr; ret = pcmcia_request_io(link, &link->io); - if (ret == CS_SUCCESS) { + if (ret == 0) { /* calculate ConfigIndex value */ link->conf.ConfigIndex = ((link->io.BasePort1 & 0x0f0) >> 3) | 0x22; @@ -356,12 +357,12 @@ static int fmvj18x_config(struct pcmcia_device *link) tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_FUNCE; tuple.TupleOffset = 0; - if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) { + if (pcmcia_get_first_tuple(link, &tuple) == 0) { /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse)); link->conf.ConfigIndex = parse.cftable_entry.index; switch (link->manf_id) { case MANFID_TDK: @@ -430,10 +431,10 @@ static int fmvj18x_config(struct pcmcia_device *link) link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; ret = mfc_try_io_port(link); - if (ret != CS_SUCCESS) goto cs_failed; + if (ret != 0) goto cs_failed; } else if (cardtype == UNGERMANN) { ret = ungermann_try_io_port(link); - if (ret != CS_SUCCESS) goto cs_failed; + if (ret != 0) goto cs_failed; } else { CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); } @@ -565,7 +566,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) req.Base = 0; req.Size = 0; req.AccessSpeed = 0; i = pcmcia_request_window(&link, &req, &link->win); - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestWindow, i); return -1; } @@ -599,7 +600,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) iounmap(base); j = pcmcia_release_window(link->win); - if (j != CS_SUCCESS) + if (j != 0) cs_error(link, ReleaseWindow, j); return (i != 0x200) ? 0 : -1; @@ -620,7 +621,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) req.Base = 0; req.Size = 0; req.AccessSpeed = 0; i = pcmcia_request_window(&link, &req, &link->win); - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestWindow, i); return -1; } @@ -642,7 +643,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) iounmap(base); j = pcmcia_release_window(link->win); - if (j != CS_SUCCESS) + if (j != 0) cs_error(link, ReleaseWindow, j); return 0; diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 4eafa4f42cf..cf3cca4642f 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -238,7 +238,7 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) /* Try PRIMARY card at 0xA20-0xA23 */ link->io.BasePort1 = 0xA20; i = pcmcia_request_io(link, &link->io); - if (i != CS_SUCCESS) { + if (i != 0) { /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */ link->io.BasePort1 = 0xA24; CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index cfcbea9b7e2..448cd40aeba 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -69,7 +69,7 @@ Driver Notes and Issues History ------------------------------------------------------------------------------- Log: nmclan_cs.c,v - * 2.5.75-ac1 2003/07/11 Alan Cox <alan@redhat.com> + * 2.5.75-ac1 2003/07/11 Alan Cox <alan@lxorguk.ukuu.org.uk> * Fixed hang on card eject as we probe it * Cleaned up to use new style locking. * @@ -925,7 +925,7 @@ static void mace_tx_timeout(struct net_device *dev) printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name); #if RESET_ON_TIMEOUT printk("resetting card\n"); - pcmcia_reset_card(link, NULL); + pcmcia_reset_card(link->socket); #else /* #if RESET_ON_TIMEOUT */ printk("NOT resetting card\n"); #endif /* #if RESET_ON_TIMEOUT */ diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index ebc1ae6bcbe..e40d6301aa7 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -310,7 +310,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link) req.Base = 0; req.Size = 0; req.AccessSpeed = 0; i = pcmcia_request_window(&link, &req, &link->win); - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestWindow, i); return NULL; } @@ -333,7 +333,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link) iounmap(virt); j = pcmcia_release_window(link->win); - if (j != CS_SUCCESS) + if (j != 0) cs_error(link, ReleaseWindow, j); return (i < NR_INFO) ? hw_info+i : NULL; } /* get_hwinfo */ @@ -504,7 +504,8 @@ static int try_io_port(struct pcmcia_device *link) link->io.BasePort1 = j ^ 0x300; link->io.BasePort2 = (j ^ 0x300) + 0x10; ret = pcmcia_request_io(link, &link->io); - if (ret == CS_SUCCESS) return ret; + if (ret == 0) + return ret; } return ret; } else { @@ -512,58 +513,53 @@ static int try_io_port(struct pcmcia_device *link) } } +static int pcnet_confcheck(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + int *has_shmem = priv_data; + int i; + cistpl_io_t *io = &cfg->io; + + if (cfg->index == 0 || cfg->io.nwin == 0) + return -EINVAL; + + /* For multifunction cards, by convention, we configure the + network function with window 0, and serial with window 1 */ + if (io->nwin > 1) { + i = (io->win[1].len > io->win[0].len); + p_dev->io.BasePort2 = io->win[1-i].base; + p_dev->io.NumPorts2 = io->win[1-i].len; + } else { + i = p_dev->io.NumPorts2 = 0; + } + + *has_shmem = ((cfg->mem.nwin == 1) && + (cfg->mem.win[0].len >= 0x4000)); + p_dev->io.BasePort1 = io->win[i].base; + p_dev->io.NumPorts1 = io->win[i].len; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32) + return try_io_port(p_dev); + + return 0; +} + static int pcnet_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; pcnet_dev_t *info = PRIV(dev); - tuple_t tuple; - cisparse_t parse; - int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; + int last_ret, last_fn, start_pg, stop_pg, cm_offset; int has_shmem = 0; - u_short buf[64]; hw_info_t *local_hw_info; DECLARE_MAC_BUF(mac); DEBUG(0, "pcnet_config(0x%p)\n", link); - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (last_ret == CS_SUCCESS) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - cistpl_io_t *io = &(parse.cftable_entry.io); - - if (pcmcia_get_tuple_data(link, &tuple) != 0 || - pcmcia_parse_tuple(link, &tuple, &parse) != 0 || - cfg->index == 0 || cfg->io.nwin == 0) - goto next_entry; - - link->conf.ConfigIndex = cfg->index; - /* For multifunction cards, by convention, we configure the - network function with window 0, and serial with window 1 */ - if (io->nwin > 1) { - i = (io->win[1].len > io->win[0].len); - link->io.BasePort2 = io->win[1-i].base; - link->io.NumPorts2 = io->win[1-i].len; - } else { - i = link->io.NumPorts2 = 0; - } - has_shmem = ((cfg->mem.nwin == 1) && - (cfg->mem.win[0].len >= 0x4000)); - link->io.BasePort1 = io->win[i].base; - link->io.NumPorts1 = io->win[i].len; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) { - last_ret = try_io_port(link); - if (last_ret == CS_SUCCESS) break; - } - next_entry: - last_ret = pcmcia_get_next_tuple(link, &tuple); - } - if (last_ret != CS_SUCCESS) { + last_ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem); + if (last_ret) { cs_error(link, RequestIO, last_ret); goto failed; } diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 250eb1954c3..c74d6656d26 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -409,10 +409,13 @@ static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, { int i; - if ((i = pcmcia_get_first_tuple(handle, tuple)) != CS_SUCCESS || - (i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS) + i = pcmcia_get_first_tuple(handle, tuple); + if (i != 0) return i; - return pcmcia_parse_tuple(handle, tuple, parse); + i = pcmcia_get_tuple_data(handle, tuple); + if (i != 0) + return i; + return pcmcia_parse_tuple(tuple, parse); } static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, @@ -420,10 +423,10 @@ static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, { int i; - if ((i = pcmcia_get_next_tuple(handle, tuple)) != CS_SUCCESS || - (i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS) + if ((i = pcmcia_get_next_tuple(handle, tuple)) != 0 || + (i = pcmcia_get_tuple_data(handle, tuple)) != 0) return i; - return pcmcia_parse_tuple(handle, tuple, parse); + return pcmcia_parse_tuple(tuple, parse); } /*====================================================================== @@ -459,27 +462,36 @@ static int mhz_3288_power(struct pcmcia_device *link) return 0; } +static int mhz_mfc_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cf, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + int k; + p_dev->io.BasePort2 = cf->io.win[0].base; + for (k = 0; k < 0x400; k += 0x10) { + if (k & 0x80) + continue; + p_dev->io.BasePort1 = k ^ 0x300; + if (!pcmcia_request_io(p_dev, &p_dev->io)) + return 0; + } + return -ENODEV; +} + static int mhz_mfc_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); struct smc_cfg_mem *cfg_mem; - tuple_t *tuple; - cisparse_t *parse; - cistpl_cftable_entry_t *cf; - u_char *buf; win_req_t req; memreq_t mem; - int i, k; + int i; cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); if (!cfg_mem) - return CS_OUT_OF_RESOURCE; - - tuple = &cfg_mem->tuple; - parse = &cfg_mem->parse; - cf = &parse->cftable_entry; - buf = cfg_mem->buf; + return -ENOMEM; link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; @@ -489,27 +501,9 @@ static int mhz_mfc_config(struct pcmcia_device *link) link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; - tuple->Attributes = tuple->TupleOffset = 0; - tuple->TupleData = (cisdata_t *)buf; - tuple->TupleDataMax = 255; - tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; - - i = first_tuple(link, tuple, parse); /* The Megahertz combo cards have modem-like CIS entries, so we have to explicitly try a bunch of port combinations. */ - while (i == CS_SUCCESS) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort2 = cf->io.win[0].base; - for (k = 0; k < 0x400; k += 0x10) { - if (k & 0x80) continue; - link->io.BasePort1 = k ^ 0x300; - i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) break; - } - if (i == CS_SUCCESS) break; - i = next_tuple(link, tuple, parse); - } - if (i != CS_SUCCESS) + if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL)) goto free_cfg_mem; dev->base_addr = link->io.BasePort1; @@ -518,7 +512,7 @@ static int mhz_mfc_config(struct pcmcia_device *link) req.Base = req.Size = 0; req.AccessSpeed = 0; i = pcmcia_request_window(&link, &req, &link->win); - if (i != CS_SUCCESS) + if (i != 0) goto free_cfg_mem; smc->base = ioremap(req.Base, req.Size); mem.CardOffset = mem.Page = 0; @@ -526,14 +520,14 @@ static int mhz_mfc_config(struct pcmcia_device *link) mem.CardOffset = link->conf.ConfigBase; i = pcmcia_map_mem_page(link->win, &mem); - if ((i == CS_SUCCESS) + if ((i == 0) && (smc->manfid == MANFID_MEGAHERTZ) && (smc->cardid == PRODID_MEGAHERTZ_EM3288)) mhz_3288_power(link); free_cfg_mem: kfree(cfg_mem); - return i; + return -ENODEV; } static int mhz_setup(struct pcmcia_device *link) @@ -560,12 +554,12 @@ static int mhz_setup(struct pcmcia_device *link) /* Read the station address from the CIS. It is stored as the last (fourth) string in the Version 1 Version/ID tuple. */ tuple->DesiredTuple = CISTPL_VERS_1; - if (first_tuple(link, tuple, parse) != CS_SUCCESS) { + if (first_tuple(link, tuple, parse) != 0) { rc = -1; goto free_cfg_mem; } /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ - if (next_tuple(link, tuple, parse) != CS_SUCCESS) + if (next_tuple(link, tuple, parse) != 0) first_tuple(link, tuple, parse); if (parse->version_1.ns > 3) { station_addr = parse->version_1.str + parse->version_1.ofs[3]; @@ -577,11 +571,11 @@ static int mhz_setup(struct pcmcia_device *link) /* Another possibility: for the EM3288, in a special tuple */ tuple->DesiredTuple = 0x81; - if (pcmcia_get_first_tuple(link, tuple) != CS_SUCCESS) { + if (pcmcia_get_first_tuple(link, tuple) != 0) { rc = -1; goto free_cfg_mem; } - if (pcmcia_get_tuple_data(link, tuple) != CS_SUCCESS) { + if (pcmcia_get_tuple_data(link, tuple) != 0) { rc = -1; goto free_cfg_mem; } @@ -660,46 +654,27 @@ static int mot_setup(struct pcmcia_device *link) /*====================================================================*/ +static int smc_configcheck(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cf, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + p_dev->io.BasePort1 = cf->io.win[0].base; + p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; + return pcmcia_request_io(p_dev, &p_dev->io); +} + static int smc_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; - struct smc_cfg_mem *cfg_mem; - tuple_t *tuple; - cisparse_t *parse; - cistpl_cftable_entry_t *cf; - u_char *buf; int i; - cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); - if (!cfg_mem) - return CS_OUT_OF_RESOURCE; - - tuple = &cfg_mem->tuple; - parse = &cfg_mem->parse; - cf = &parse->cftable_entry; - buf = cfg_mem->buf; - - tuple->Attributes = tuple->TupleOffset = 0; - tuple->TupleData = (cisdata_t *)buf; - tuple->TupleDataMax = 255; - tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; - link->io.NumPorts1 = 16; - i = first_tuple(link, tuple, parse); - while (i != CS_NO_MORE_ITEMS) { - if (i == CS_SUCCESS) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) break; - } - i = next_tuple(link, tuple, parse); - } - if (i == CS_SUCCESS) - dev->base_addr = link->io.BasePort1; + i = pcmcia_loop_config(link, smc_configcheck, NULL); + if (!i) + dev->base_addr = link->io.BasePort1; - kfree(cfg_mem); return i; } @@ -715,7 +690,7 @@ static int smc_setup(struct pcmcia_device *link) cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); if (!cfg_mem) - return CS_OUT_OF_RESOURCE; + return -ENOMEM; tuple = &cfg_mem->tuple; parse = &cfg_mem->parse; @@ -728,12 +703,12 @@ static int smc_setup(struct pcmcia_device *link) /* Check for a LAN function extension tuple */ tuple->DesiredTuple = CISTPL_FUNCE; i = first_tuple(link, tuple, parse); - while (i == CS_SUCCESS) { + while (i == 0) { if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID) break; i = next_tuple(link, tuple, parse); } - if (i == CS_SUCCESS) { + if (i == 0) { node_id = (cistpl_lan_node_id_t *)parse->funce.data; if (node_id->nb == 6) { for (i = 0; i < 6; i++) @@ -780,9 +755,10 @@ static int osi_config(struct pcmcia_device *link) for (i = j = 0; j < 4; j++) { link->io.BasePort2 = com[j]; i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) break; + if (i == 0) + break; } - if (i != CS_SUCCESS) { + if (i != 0) { /* Fallback: turn off hard decode */ link->conf.ConfigIndex = 0x03; link->io.NumPorts2 = 0; @@ -815,13 +791,13 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) /* Read the station address from tuple 0x90, subtuple 0x04 */ tuple->DesiredTuple = 0x90; i = pcmcia_get_first_tuple(link, tuple); - while (i == CS_SUCCESS) { + while (i == 0) { i = pcmcia_get_tuple_data(link, tuple); - if ((i != CS_SUCCESS) || (buf[0] == 0x04)) + if ((i != 0) || (buf[0] == 0x04)) break; i = pcmcia_get_next_tuple(link, tuple); } - if (i != CS_SUCCESS) { + if (i != 0) { rc = -1; goto free_cfg_mem; } @@ -959,8 +935,11 @@ static int check_sig(struct pcmcia_device *link) ======================================================================*/ -#define CS_EXIT_TEST(ret, svc, label) \ -if (ret != CS_SUCCESS) { cs_error(link, svc, ret); goto label; } +#define CS_EXIT_TEST(ret, svc, label) \ +if (ret != 0) { \ + cs_error(link, svc, ret); \ + goto label; \ +} static int smc91c92_config(struct pcmcia_device *link) { diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index f6c4698ce73..e1fd585e713 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -353,7 +353,7 @@ typedef struct local_info_t { * Some more prototypes */ static int do_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void do_tx_timeout(struct net_device *dev); +static void xirc_tx_timeout(struct net_device *dev); static void xirc2ps_tx_timeout_task(struct work_struct *work); static struct net_device_stats *do_get_stats(struct net_device *dev); static void set_addresses(struct net_device *dev); @@ -377,7 +377,7 @@ first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) if ((err = pcmcia_get_first_tuple(handle, tuple)) == 0 && (err = pcmcia_get_tuple_data(handle, tuple)) == 0) - err = pcmcia_parse_tuple(handle, tuple, parse); + err = pcmcia_parse_tuple(tuple, parse); return err; } @@ -388,7 +388,7 @@ next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) if ((err = pcmcia_get_next_tuple(handle, tuple)) == 0 && (err = pcmcia_get_tuple_data(handle, tuple)) == 0) - err = pcmcia_parse_tuple(handle, tuple, parse); + err = pcmcia_parse_tuple(tuple, parse); return err; } @@ -590,7 +590,7 @@ xirc2ps_probe(struct pcmcia_device *link) dev->open = &do_open; dev->stop = &do_stop; #ifdef HAVE_TX_TIMEOUT - dev->tx_timeout = do_tx_timeout; + dev->tx_timeout = xirc_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task); #endif @@ -715,6 +715,47 @@ has_ce2_string(struct pcmcia_device * p_dev) return 0; } +static int +xirc2ps_config_modem(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cf, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + unsigned int ioaddr; + + if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) { + for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { + p_dev->io.BasePort2 = cf->io.win[0].base; + p_dev->io.BasePort1 = ioaddr; + if (!pcmcia_request_io(p_dev, &p_dev->io)) + return 0; + } + } + return -ENODEV; +} + +static int +xirc2ps_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cf, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + int *pass = priv_data; + + if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) { + p_dev->io.BasePort2 = cf->io.win[0].base; + p_dev->io.BasePort1 = p_dev->io.BasePort2 + + (*pass ? (cf->index & 0x20 ? -24:8) + : (cf->index & 0x20 ? 8:-24)); + if (!pcmcia_request_io(p_dev, &p_dev->io)) + return 0; + } + return -ENODEV; + +} + /**************** * xirc2ps_config() is scheduled to run after a CARD_INSERTION event * is received, to configure the PCMCIA socket, and to make the @@ -725,13 +766,12 @@ xirc2ps_config(struct pcmcia_device * link) { struct net_device *dev = link->priv; local_info_t *local = netdev_priv(dev); + unsigned int ioaddr; tuple_t tuple; cisparse_t parse; - unsigned int ioaddr; int err, i; u_char buf[64]; cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; - cistpl_cftable_entry_t *cf = &parse.cftable_entry; DECLARE_MAC_BUF(mac); local->dingo_ccr = NULL; @@ -846,19 +886,8 @@ xirc2ps_config(struct pcmcia_device * link) /* Take the Modem IO port from the CIS and scan for a free * Ethernet port */ link->io.NumPorts1 = 16; /* no Mako stuff anymore */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - for (err = first_tuple(link, &tuple, &parse); !err; - err = next_tuple(link, &tuple, &parse)) { - if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) { - for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { - link->conf.ConfigIndex = cf->index ; - link->io.BasePort2 = cf->io.win[0].base; - link->io.BasePort1 = ioaddr; - if (!(err=pcmcia_request_io(link, &link->io))) - goto port_found; - } - } - } + if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL)) + goto port_found; } else { link->io.NumPorts1 = 18; /* We do 2 passes here: The first one uses the regular mapping and @@ -866,21 +895,9 @@ xirc2ps_config(struct pcmcia_device * link) * mirrored every 32 bytes. Actually we use a mirrored port for * the Mako if (on the first pass) the COR bit 5 is set. */ - for (pass=0; pass < 2; pass++) { - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - for (err = first_tuple(link, &tuple, &parse); !err; - err = next_tuple(link, &tuple, &parse)){ - if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8){ - link->conf.ConfigIndex = cf->index ; - link->io.BasePort2 = cf->io.win[0].base; - link->io.BasePort1 = link->io.BasePort2 - + (pass ? (cf->index & 0x20 ? -24:8) - : (cf->index & 0x20 ? 8:-24)); - if (!(err=pcmcia_request_io(link, &link->io))) + for (pass=0; pass < 2; pass++) + if (!pcmcia_loop_config(link, xirc2ps_config_check, &pass)) goto port_found; - } - } - } /* if special option: * try to configure as Ethernet only. * .... */ @@ -1335,7 +1352,7 @@ xirc2ps_tx_timeout_task(struct work_struct *work) } static void -do_tx_timeout(struct net_device *dev) +xirc_tx_timeout(struct net_device *dev) { local_info_t *lp = netdev_priv(dev); lp->stats.tx_errors++; diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 4e07956a483..cf24cc34deb 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -24,7 +24,7 @@ struct fixed_mdio_bus { int irqs[PHY_MAX_ADDR]; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; struct list_head phys; }; @@ -115,8 +115,7 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) static int fixed_mdio_read(struct mii_bus *bus, int phy_id, int reg_num) { - struct fixed_mdio_bus *fmb = container_of(bus, struct fixed_mdio_bus, - mii_bus); + struct fixed_mdio_bus *fmb = bus->priv; struct fixed_phy *fp; if (reg_num >= MII_REGS_NUM) @@ -213,19 +212,28 @@ static int __init fixed_mdio_bus_init(void) goto err_pdev; } - snprintf(fmb->mii_bus.id, MII_BUS_ID_SIZE, "0"); - fmb->mii_bus.name = "Fixed MDIO Bus"; - fmb->mii_bus.dev = &pdev->dev; - fmb->mii_bus.read = &fixed_mdio_read; - fmb->mii_bus.write = &fixed_mdio_write; - fmb->mii_bus.irq = fmb->irqs; + fmb->mii_bus = mdiobus_alloc(); + if (fmb->mii_bus == NULL) { + ret = -ENOMEM; + goto err_mdiobus_reg; + } - ret = mdiobus_register(&fmb->mii_bus); + snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "0"); + fmb->mii_bus->name = "Fixed MDIO Bus"; + fmb->mii_bus->priv = fmb; + fmb->mii_bus->parent = &pdev->dev; + fmb->mii_bus->read = &fixed_mdio_read; + fmb->mii_bus->write = &fixed_mdio_write; + fmb->mii_bus->irq = fmb->irqs; + + ret = mdiobus_register(fmb->mii_bus); if (ret) - goto err_mdiobus_reg; + goto err_mdiobus_alloc; return 0; +err_mdiobus_alloc: + mdiobus_free(fmb->mii_bus); err_mdiobus_reg: platform_device_unregister(pdev); err_pdev: @@ -238,7 +246,8 @@ static void __exit fixed_mdio_bus_exit(void) struct fixed_mdio_bus *fmb = &platform_fmb; struct fixed_phy *fp, *tmp; - mdiobus_unregister(&fmb->mii_bus); + mdiobus_unregister(fmb->mii_bus); + mdiobus_free(fmb->mii_bus); platform_device_unregister(pdev); list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c index c01b78013dd..2576055b350 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c @@ -165,7 +165,7 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) { struct mii_bus *bus; - bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + bus = mdiobus_alloc(); if (!bus) return NULL; @@ -184,7 +184,7 @@ void free_mdio_bitbang(struct mii_bus *bus) struct mdiobb_ctrl *ctrl = bus->priv; module_put(ctrl->ops->owner); - kfree(bus); + mdiobus_free(bus); } EXPORT_SYMBOL(free_mdio_bitbang); diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c index 7edfc0c3483..2ff97754e57 100644 --- a/drivers/net/phy/mdio-ofgpio.c +++ b/drivers/net/phy/mdio-ofgpio.c @@ -122,7 +122,7 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, new_bus = alloc_mdio_bitbang(&bitbang->ctrl); if (!new_bus) - goto out_free_priv; + goto out_free_bitbang; new_bus->name = "GPIO Bitbanged MII", @@ -142,7 +142,7 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, if (!strcmp(np->type, "ethernet-phy")) add_phy(new_bus, np); - new_bus->dev = &ofdev->dev; + new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); ret = mdiobus_register(new_bus); @@ -155,9 +155,9 @@ out_free_irqs: dev_set_drvdata(&ofdev->dev, NULL); kfree(new_bus->irq); out_free_bus: - kfree(new_bus); -out_free_priv: free_mdio_bitbang(new_bus); +out_free_bitbang: + kfree(bitbang); out: return ret; } @@ -168,11 +168,10 @@ static int mdio_ofgpio_remove(struct of_device *ofdev) struct mdio_gpio_info *bitbang = bus->priv; mdiobus_unregister(bus); + kfree(bus->irq); free_mdio_bitbang(bus); dev_set_drvdata(&ofdev->dev, NULL); - kfree(bus->irq); kfree(bitbang); - kfree(bus); return 0; } diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 94e0b7ed76f..d0ed1ef284a 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -36,6 +36,43 @@ #include <asm/uaccess.h> /** + * mdiobus_alloc - allocate a mii_bus structure + * + * Description: called by a bus driver to allocate an mii_bus + * structure to fill in. + */ +struct mii_bus *mdiobus_alloc(void) +{ + struct mii_bus *bus; + + bus = kzalloc(sizeof(*bus), GFP_KERNEL); + if (bus != NULL) + bus->state = MDIOBUS_ALLOCATED; + + return bus; +} +EXPORT_SYMBOL(mdiobus_alloc); + +/** + * mdiobus_release - mii_bus device release callback + * @d: the target struct device that contains the mii_bus + * + * Description: called when the last reference to an mii_bus is + * dropped, to free the underlying memory. + */ +static void mdiobus_release(struct device *d) +{ + struct mii_bus *bus = to_mii_bus(d); + BUG_ON(bus->state != MDIOBUS_RELEASED); + kfree(bus); +} + +static struct class mdio_bus_class = { + .name = "mdio_bus", + .dev_release = mdiobus_release, +}; + +/** * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus * @bus: target mii_bus * @@ -54,55 +91,36 @@ int mdiobus_register(struct mii_bus *bus) NULL == bus->write) return -EINVAL; - mutex_init(&bus->mdio_lock); - - if (bus->reset) - bus->reset(bus); - - for (i = 0; i < PHY_MAX_ADDR; i++) { - struct phy_device *phydev; - - if (bus->phy_mask & (1 << i)) { - bus->phy_map[i] = NULL; - continue; - } - - phydev = get_phy_device(bus, i); + BUG_ON(bus->state != MDIOBUS_ALLOCATED && + bus->state != MDIOBUS_UNREGISTERED); - if (IS_ERR(phydev)) - return PTR_ERR(phydev); + bus->dev.parent = bus->parent; + bus->dev.class = &mdio_bus_class; + bus->dev.groups = NULL; + memcpy(bus->dev.bus_id, bus->id, MII_BUS_ID_SIZE); - /* There's a PHY at this address - * We need to set: - * 1) IRQ - * 2) bus_id - * 3) parent - * 4) bus - * 5) mii_bus - * And, we need to register it */ - if (phydev) { - phydev->irq = bus->irq[i]; + err = device_register(&bus->dev); + if (err) { + printk(KERN_ERR "mii_bus %s failed to register\n", bus->id); + return -EINVAL; + } - phydev->dev.parent = bus->dev; - phydev->dev.bus = &mdio_bus_type; - snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, i); + bus->state = MDIOBUS_REGISTERED; - phydev->bus = bus; + mutex_init(&bus->mdio_lock); - /* Run all of the fixups for this PHY */ - phy_scan_fixups(phydev); + if (bus->reset) + bus->reset(bus); - err = device_register(&phydev->dev); + for (i = 0; i < PHY_MAX_ADDR; i++) { + bus->phy_map[i] = NULL; + if ((bus->phy_mask & (1 << i)) == 0) { + struct phy_device *phydev; - if (err) { - printk(KERN_ERR "phy %d failed to register\n", - i); - phy_device_free(phydev); - phydev = NULL; - } + phydev = mdiobus_scan(bus, i); + if (IS_ERR(phydev)) + err = PTR_ERR(phydev); } - - bus->phy_map[i] = phydev; } pr_info("%s: probed\n", bus->name); @@ -115,6 +133,10 @@ void mdiobus_unregister(struct mii_bus *bus) { int i; + BUG_ON(bus->state != MDIOBUS_REGISTERED); + bus->state = MDIOBUS_UNREGISTERED; + + device_unregister(&bus->dev); for (i = 0; i < PHY_MAX_ADDR; i++) { if (bus->phy_map[i]) device_unregister(&bus->phy_map[i]->dev); @@ -123,6 +145,122 @@ void mdiobus_unregister(struct mii_bus *bus) EXPORT_SYMBOL(mdiobus_unregister); /** + * mdiobus_free - free a struct mii_bus + * @bus: mii_bus to free + * + * This function releases the reference to the underlying device + * object in the mii_bus. If this is the last reference, the mii_bus + * will be freed. + */ +void mdiobus_free(struct mii_bus *bus) +{ + /* + * For compatibility with error handling in drivers. + */ + if (bus->state == MDIOBUS_ALLOCATED) { + kfree(bus); + return; + } + + BUG_ON(bus->state != MDIOBUS_UNREGISTERED); + bus->state = MDIOBUS_RELEASED; + + put_device(&bus->dev); +} +EXPORT_SYMBOL(mdiobus_free); + +struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) +{ + struct phy_device *phydev; + int err; + + phydev = get_phy_device(bus, addr); + if (IS_ERR(phydev) || phydev == NULL) + return phydev; + + /* There's a PHY at this address + * We need to set: + * 1) IRQ + * 2) bus_id + * 3) parent + * 4) bus + * 5) mii_bus + * And, we need to register it */ + + phydev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; + + phydev->dev.parent = bus->parent; + phydev->dev.bus = &mdio_bus_type; + snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, addr); + + phydev->bus = bus; + + /* Run all of the fixups for this PHY */ + phy_scan_fixups(phydev); + + err = device_register(&phydev->dev); + if (err) { + printk(KERN_ERR "phy %d failed to register\n", addr); + phy_device_free(phydev); + phydev = NULL; + } + + bus->phy_map[addr] = phydev; + + return phydev; +} +EXPORT_SYMBOL(mdiobus_scan); + +/** + * mdiobus_read - Convenience function for reading a given MII mgmt register + * @bus: the mii_bus struct + * @addr: the phy address + * @regnum: register number to read + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum) +{ + int retval; + + BUG_ON(in_interrupt()); + + mutex_lock(&bus->mdio_lock); + retval = bus->read(bus, addr, regnum); + mutex_unlock(&bus->mdio_lock); + + return retval; +} +EXPORT_SYMBOL(mdiobus_read); + +/** + * mdiobus_write - Convenience function for writing a given MII mgmt register + * @bus: the mii_bus struct + * @addr: the phy address + * @regnum: register number to write + * @val: value to write to @regnum + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val) +{ + int err; + + BUG_ON(in_interrupt()); + + mutex_lock(&bus->mdio_lock); + err = bus->write(bus, addr, regnum, val); + mutex_unlock(&bus->mdio_lock); + + return err; +} +EXPORT_SYMBOL(mdiobus_write); + +/** * mdio_bus_match - determine if given PHY driver supports the given PHY device * @dev: target PHY device * @drv: given PHY driver @@ -174,10 +312,20 @@ EXPORT_SYMBOL(mdio_bus_type); int __init mdio_bus_init(void) { - return bus_register(&mdio_bus_type); + int ret; + + ret = class_register(&mdio_bus_class); + if (!ret) { + ret = bus_register(&mdio_bus_type); + if (ret) + class_unregister(&mdio_bus_class); + } + + return ret; } void mdio_bus_exit(void) { + class_unregister(&mdio_bus_class); bus_unregister(&mdio_bus_type); } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 45cc2914d34..df4e6257d4a 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -58,55 +58,6 @@ EXPORT_SYMBOL(phy_print_status); /** - * phy_read - Convenience function for reading a given PHY register - * @phydev: the phy_device struct - * @regnum: register number to read - * - * NOTE: MUST NOT be called from interrupt context, - * because the bus read/write functions may wait for an interrupt - * to conclude the operation. - */ -int phy_read(struct phy_device *phydev, u16 regnum) -{ - int retval; - struct mii_bus *bus = phydev->bus; - - BUG_ON(in_interrupt()); - - mutex_lock(&bus->mdio_lock); - retval = bus->read(bus, phydev->addr, regnum); - mutex_unlock(&bus->mdio_lock); - - return retval; -} -EXPORT_SYMBOL(phy_read); - -/** - * phy_write - Convenience function for writing a given PHY register - * @phydev: the phy_device struct - * @regnum: register number to write - * @val: value to write to @regnum - * - * NOTE: MUST NOT be called from interrupt context, - * because the bus read/write functions may wait for an interrupt - * to conclude the operation. - */ -int phy_write(struct phy_device *phydev, u16 regnum, u16 val) -{ - int err; - struct mii_bus *bus = phydev->bus; - - BUG_ON(in_interrupt()); - - mutex_lock(&bus->mdio_lock); - err = bus->write(bus, phydev->addr, regnum, val); - mutex_unlock(&bus->mdio_lock); - - return err; -} -EXPORT_SYMBOL(phy_write); - -/** * phy_clear_interrupt - Ack the phy device's interrupt * @phydev: the phy_device struct * @@ -366,7 +317,8 @@ int phy_mii_ioctl(struct phy_device *phydev, switch (cmd) { case SIOCGMIIPHY: mii_data->phy_id = phydev->addr; - break; + /* fall through */ + case SIOCGMIIREG: mii_data->val_out = phy_read(phydev, mii_data->reg_num); break; @@ -413,7 +365,7 @@ int phy_mii_ioctl(struct phy_device *phydev, break; default: - return -ENOTTY; + return -EOPNOTSUPP; } return 0; @@ -728,6 +680,12 @@ static void phy_change(struct work_struct *work) if (err) goto irq_enable_err; + /* Stop timer and run the state queue now. The work function for + * state_queue will start the timer up again. + */ + del_timer(&phydev->phy_timer); + schedule_work(&phydev->state_queue); + return; irq_enable_err: diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 16a0e7de588..e11b03b2b25 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -309,11 +309,6 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); -static int phy_compare_id(struct device *dev, void *data) -{ - return strcmp((char *)data, dev->bus_id) ? 0 : 1; -} - /** * phy_attach - attach a network device to a particular PHY device * @dev: network device to attach @@ -337,8 +332,7 @@ struct phy_device *phy_attach(struct net_device *dev, /* Search the list of PHY devices on the mdio bus for the * PHY with the requested name */ - d = bus_find_device(bus, NULL, (void *)bus_id, phy_compare_id); - + d = bus_find_device_by_name(bus, NULL, bus_id); if (d) { phydev = to_phy_device(d); } else { @@ -419,13 +413,14 @@ EXPORT_SYMBOL(phy_detach); * * Description: Writes MII_ADVERTISE with the appropriate values, * after sanitizing the values to make sure we only advertise - * what is supported. + * what is supported. Returns < 0 on error, 0 if the PHY's advertisement + * hasn't changed, and > 0 if it has changed. */ int genphy_config_advert(struct phy_device *phydev) { u32 advertise; - int adv; - int err; + int oldadv, adv; + int err, changed = 0; /* Only allow advertising what * this PHY supports */ @@ -433,7 +428,7 @@ int genphy_config_advert(struct phy_device *phydev) advertise = phydev->advertising; /* Setup standard advertisement */ - adv = phy_read(phydev, MII_ADVERTISE); + oldadv = adv = phy_read(phydev, MII_ADVERTISE); if (adv < 0) return adv; @@ -453,15 +448,18 @@ int genphy_config_advert(struct phy_device *phydev) if (advertise & ADVERTISED_Asym_Pause) adv |= ADVERTISE_PAUSE_ASYM; - err = phy_write(phydev, MII_ADVERTISE, adv); + if (adv != oldadv) { + err = phy_write(phydev, MII_ADVERTISE, adv); - if (err < 0) - return err; + if (err < 0) + return err; + changed = 1; + } /* Configure gigabit if it's supported */ if (phydev->supported & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) { - adv = phy_read(phydev, MII_CTRL1000); + oldadv = adv = phy_read(phydev, MII_CTRL1000); if (adv < 0) return adv; @@ -471,13 +469,17 @@ int genphy_config_advert(struct phy_device *phydev) adv |= ADVERTISE_1000HALF; if (advertise & SUPPORTED_1000baseT_Full) adv |= ADVERTISE_1000FULL; - err = phy_write(phydev, MII_CTRL1000, adv); - if (err < 0) - return err; + if (adv != oldadv) { + err = phy_write(phydev, MII_CTRL1000, adv); + + if (err < 0) + return err; + changed = 1; + } } - return adv; + return changed; } EXPORT_SYMBOL(genphy_config_advert); @@ -549,6 +551,7 @@ int genphy_restart_aneg(struct phy_device *phydev) return ctl; } +EXPORT_SYMBOL(genphy_restart_aneg); /** @@ -561,19 +564,22 @@ int genphy_restart_aneg(struct phy_device *phydev) */ int genphy_config_aneg(struct phy_device *phydev) { - int err = 0; + int result = 0; if (AUTONEG_ENABLE == phydev->autoneg) { - err = genphy_config_advert(phydev); + int result = genphy_config_advert(phydev); - if (err < 0) - return err; + if (result < 0) /* error */ + return result; - err = genphy_restart_aneg(phydev); + /* Only restart aneg if we are advertising something different + * than we were before. */ + if (result > 0) + result = genphy_restart_aneg(phydev); } else - err = genphy_setup_forced(phydev); + result = genphy_setup_forced(phydev); - return err; + return result; } EXPORT_SYMBOL(genphy_config_aneg); diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index ddccc074a76..7e857e938ad 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -866,8 +866,8 @@ static int __init ppp_init(void) err = PTR_ERR(ppp_class); goto out_chrdev; } - device_create_drvdata(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), - NULL, "ppp"); + device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, + "ppp"); } out: @@ -1833,9 +1833,11 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) /* If the queue is getting long, don't wait any longer for packets before the start of the queue. */ - if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN - && seq_before(ppp->minseq, ppp->mrq.next->sequence)) - ppp->minseq = ppp->mrq.next->sequence; + if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN) { + struct sk_buff *skb = skb_peek(&ppp->mrq); + if (seq_before(ppp->minseq, skb->sequence)) + ppp->minseq = skb->sequence; + } /* Pull completed packets off the queue and receive them. */ while ((skb = ppp_mp_reconstruct(ppp))) @@ -1861,10 +1863,11 @@ ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb) /* N.B. we don't need to lock the list lock because we have the ppp unit receive-side lock. */ - for (p = list->next; p != (struct sk_buff *)list; p = p->next) + skb_queue_walk(list, p) { if (seq_before(seq, p->sequence)) break; - __skb_insert(skb, p->prev, p, list); + } + __skb_queue_before(list, p, skb); } /* @@ -2124,13 +2127,9 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg) || ccp_option[1] < 2 || ccp_option[1] > data.length) goto out; - cp = find_compressor(ccp_option[0]); -#ifdef CONFIG_KMOD - if (!cp) { - request_module("ppp-compress-%d", ccp_option[0]); - cp = find_compressor(ccp_option[0]); - } -#endif /* CONFIG_KMOD */ + cp = try_then_request_module( + find_compressor(ccp_option[0]), + "ppp-compress-%d", ccp_option[0]); if (!cp) goto out; diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index ff175e8f36b..185b1dff10a 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -353,7 +353,7 @@ static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_ spin_lock_bh(&session->reorder_q.lock); skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { if (PPPOL2TP_SKB_CB(skbp)->ns > ns) { - __skb_insert(skb, skbp->prev, skbp, &session->reorder_q); + __skb_queue_before(&session->reorder_q, skbp, skb); PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n", session->name, ns, PPPOL2TP_SKB_CB(skbp)->ns, diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index c6898c1fc54..03aecc97fb4 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -115,13 +115,8 @@ static int pppox_create(struct net *net, struct socket *sock, int protocol) goto out; rc = -EPROTONOSUPPORT; -#ifdef CONFIG_KMOD - if (!pppox_protos[protocol]) { - char buffer[32]; - sprintf(buffer, "pppox-proto-%d", protocol); - request_module(buffer); - } -#endif + if (!pppox_protos[protocol]) + request_module("pppox-proto-%d", protocol); if (!pppox_protos[protocol] || !try_module_get(pppox_protos[protocol]->owner)) goto out; diff --git a/drivers/net/qlge/Makefile b/drivers/net/qlge/Makefile new file mode 100644 index 00000000000..8a197658d76 --- /dev/null +++ b/drivers/net/qlge/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Qlogic 10GbE PCI Express ethernet driver +# + +obj-$(CONFIG_QLGE) += qlge.o + +qlge-objs := qlge_main.o qlge_dbg.o qlge_mpi.o qlge_ethtool.o diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h new file mode 100644 index 00000000000..38116f9d416 --- /dev/null +++ b/drivers/net/qlge/qlge.h @@ -0,0 +1,1593 @@ +/* + * QLogic QLA41xx NIC HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qlge for copyright and licensing details. + */ +#ifndef _QLGE_H_ +#define _QLGE_H_ + +#include <linux/pci.h> +#include <linux/netdevice.h> + +/* + * General definitions... + */ +#define DRV_NAME "qlge" +#define DRV_STRING "QLogic 10 Gigabit PCI-E Ethernet Driver " +#define DRV_VERSION "v1.00.00-b3" + +#define PFX "qlge: " +#define QPRINTK(qdev, nlevel, klevel, fmt, args...) \ + do { \ + if (!((qdev)->msg_enable & NETIF_MSG_##nlevel)) \ + ; \ + else \ + dev_printk(KERN_##klevel, &((qdev)->pdev->dev), \ + "%s: " fmt, __func__, ##args); \ + } while (0) + +#define QLGE_VENDOR_ID 0x1077 +#define QLGE_DEVICE_ID1 0x8012 +#define QLGE_DEVICE_ID 0x8000 + +#define MAX_RX_RINGS 128 +#define MAX_TX_RINGS 128 + +#define NUM_TX_RING_ENTRIES 256 +#define NUM_RX_RING_ENTRIES 256 + +#define NUM_SMALL_BUFFERS 512 +#define NUM_LARGE_BUFFERS 512 + +#define SMALL_BUFFER_SIZE 256 +#define LARGE_BUFFER_SIZE PAGE_SIZE +#define MAX_SPLIT_SIZE 1023 +#define QLGE_SB_PAD 32 + +#define DFLT_COALESCE_WAIT 100 /* 100 usec wait for coalescing */ +#define MAX_INTER_FRAME_WAIT 10 /* 10 usec max interframe-wait for coalescing */ +#define DFLT_INTER_FRAME_WAIT (MAX_INTER_FRAME_WAIT/2) +#define UDELAY_COUNT 3 +#define UDELAY_DELAY 10 + + +#define TX_DESC_PER_IOCB 8 +/* The maximum number of frags we handle is based + * on PAGE_SIZE... + */ +#if (PAGE_SHIFT == 12) || (PAGE_SHIFT == 13) /* 4k & 8k pages */ +#define TX_DESC_PER_OAL ((MAX_SKB_FRAGS - TX_DESC_PER_IOCB) + 2) +#else /* all other page sizes */ +#define TX_DESC_PER_OAL 0 +#endif + +#define DB_PAGE_SIZE 4096 + +/* + * Processor Address Register (PROC_ADDR) bit definitions. + */ +enum { + + /* Misc. stuff */ + MAILBOX_COUNT = 16, + + PROC_ADDR_RDY = (1 << 31), + PROC_ADDR_R = (1 << 30), + PROC_ADDR_ERR = (1 << 29), + PROC_ADDR_DA = (1 << 28), + PROC_ADDR_FUNC0_MBI = 0x00001180, + PROC_ADDR_FUNC0_MBO = (PROC_ADDR_FUNC0_MBI + MAILBOX_COUNT), + PROC_ADDR_FUNC0_CTL = 0x000011a1, + PROC_ADDR_FUNC2_MBI = 0x00001280, + PROC_ADDR_FUNC2_MBO = (PROC_ADDR_FUNC2_MBI + MAILBOX_COUNT), + PROC_ADDR_FUNC2_CTL = 0x000012a1, + PROC_ADDR_MPI_RISC = 0x00000000, + PROC_ADDR_MDE = 0x00010000, + PROC_ADDR_REGBLOCK = 0x00020000, + PROC_ADDR_RISC_REG = 0x00030000, +}; + +/* + * System Register (SYS) bit definitions. + */ +enum { + SYS_EFE = (1 << 0), + SYS_FAE = (1 << 1), + SYS_MDC = (1 << 2), + SYS_DST = (1 << 3), + SYS_DWC = (1 << 4), + SYS_EVW = (1 << 5), + SYS_OMP_DLY_MASK = 0x3f000000, + /* + * There are no values defined as of edit #15. + */ + SYS_ODI = (1 << 14), +}; + +/* + * Reset/Failover Register (RST_FO) bit definitions. + */ +enum { + RST_FO_TFO = (1 << 0), + RST_FO_RR_MASK = 0x00060000, + RST_FO_RR_CQ_CAM = 0x00000000, + RST_FO_RR_DROP = 0x00000001, + RST_FO_RR_DQ = 0x00000002, + RST_FO_RR_RCV_FUNC_CQ = 0x00000003, + RST_FO_FRB = (1 << 12), + RST_FO_MOP = (1 << 13), + RST_FO_REG = (1 << 14), + RST_FO_FR = (1 << 15), +}; + +/* + * Function Specific Control Register (FSC) bit definitions. + */ +enum { + FSC_DBRST_MASK = 0x00070000, + FSC_DBRST_256 = 0x00000000, + FSC_DBRST_512 = 0x00000001, + FSC_DBRST_768 = 0x00000002, + FSC_DBRST_1024 = 0x00000003, + FSC_DBL_MASK = 0x00180000, + FSC_DBL_DBRST = 0x00000000, + FSC_DBL_MAX_PLD = 0x00000008, + FSC_DBL_MAX_BRST = 0x00000010, + FSC_DBL_128_BYTES = 0x00000018, + FSC_EC = (1 << 5), + FSC_EPC_MASK = 0x00c00000, + FSC_EPC_INBOUND = (1 << 6), + FSC_EPC_OUTBOUND = (1 << 7), + FSC_VM_PAGESIZE_MASK = 0x07000000, + FSC_VM_PAGE_2K = 0x00000100, + FSC_VM_PAGE_4K = 0x00000200, + FSC_VM_PAGE_8K = 0x00000300, + FSC_VM_PAGE_64K = 0x00000600, + FSC_SH = (1 << 11), + FSC_DSB = (1 << 12), + FSC_STE = (1 << 13), + FSC_FE = (1 << 15), +}; + +/* + * Host Command Status Register (CSR) bit definitions. + */ +enum { + CSR_ERR_STS_MASK = 0x0000003f, + /* + * There are no valued defined as of edit #15. + */ + CSR_RR = (1 << 8), + CSR_HRI = (1 << 9), + CSR_RP = (1 << 10), + CSR_CMD_PARM_SHIFT = 22, + CSR_CMD_NOP = 0x00000000, + CSR_CMD_SET_RST = 0x1000000, + CSR_CMD_CLR_RST = 0x20000000, + CSR_CMD_SET_PAUSE = 0x30000000, + CSR_CMD_CLR_PAUSE = 0x40000000, + CSR_CMD_SET_H2R_INT = 0x50000000, + CSR_CMD_CLR_H2R_INT = 0x60000000, + CSR_CMD_PAR_EN = 0x70000000, + CSR_CMD_SET_BAD_PAR = 0x80000000, + CSR_CMD_CLR_BAD_PAR = 0x90000000, + CSR_CMD_CLR_R2PCI_INT = 0xa0000000, +}; + +/* + * Configuration Register (CFG) bit definitions. + */ +enum { + CFG_LRQ = (1 << 0), + CFG_DRQ = (1 << 1), + CFG_LR = (1 << 2), + CFG_DR = (1 << 3), + CFG_LE = (1 << 5), + CFG_LCQ = (1 << 6), + CFG_DCQ = (1 << 7), + CFG_Q_SHIFT = 8, + CFG_Q_MASK = 0x7f000000, +}; + +/* + * Status Register (STS) bit definitions. + */ +enum { + STS_FE = (1 << 0), + STS_PI = (1 << 1), + STS_PL0 = (1 << 2), + STS_PL1 = (1 << 3), + STS_PI0 = (1 << 4), + STS_PI1 = (1 << 5), + STS_FUNC_ID_MASK = 0x000000c0, + STS_FUNC_ID_SHIFT = 6, + STS_F0E = (1 << 8), + STS_F1E = (1 << 9), + STS_F2E = (1 << 10), + STS_F3E = (1 << 11), + STS_NFE = (1 << 12), +}; + +/* + * Interrupt Enable Register (INTR_EN) bit definitions. + */ +enum { + INTR_EN_INTR_MASK = 0x007f0000, + INTR_EN_TYPE_MASK = 0x03000000, + INTR_EN_TYPE_ENABLE = 0x00000100, + INTR_EN_TYPE_DISABLE = 0x00000200, + INTR_EN_TYPE_READ = 0x00000300, + INTR_EN_IHD = (1 << 13), + INTR_EN_IHD_MASK = (INTR_EN_IHD << 16), + INTR_EN_EI = (1 << 14), + INTR_EN_EN = (1 << 15), +}; + +/* + * Interrupt Mask Register (INTR_MASK) bit definitions. + */ +enum { + INTR_MASK_PI = (1 << 0), + INTR_MASK_HL0 = (1 << 1), + INTR_MASK_LH0 = (1 << 2), + INTR_MASK_HL1 = (1 << 3), + INTR_MASK_LH1 = (1 << 4), + INTR_MASK_SE = (1 << 5), + INTR_MASK_LSC = (1 << 6), + INTR_MASK_MC = (1 << 7), + INTR_MASK_LINK_IRQS = INTR_MASK_LSC | INTR_MASK_SE | INTR_MASK_MC, +}; + +/* + * Register (REV_ID) bit definitions. + */ +enum { + REV_ID_MASK = 0x0000000f, + REV_ID_NICROLL_SHIFT = 0, + REV_ID_NICREV_SHIFT = 4, + REV_ID_XGROLL_SHIFT = 8, + REV_ID_XGREV_SHIFT = 12, + REV_ID_CHIPREV_SHIFT = 28, +}; + +/* + * Force ECC Error Register (FRC_ECC_ERR) bit definitions. + */ +enum { + FRC_ECC_ERR_VW = (1 << 12), + FRC_ECC_ERR_VB = (1 << 13), + FRC_ECC_ERR_NI = (1 << 14), + FRC_ECC_ERR_NO = (1 << 15), + FRC_ECC_PFE_SHIFT = 16, + FRC_ECC_ERR_DO = (1 << 18), + FRC_ECC_P14 = (1 << 19), +}; + +/* + * Error Status Register (ERR_STS) bit definitions. + */ +enum { + ERR_STS_NOF = (1 << 0), + ERR_STS_NIF = (1 << 1), + ERR_STS_DRP = (1 << 2), + ERR_STS_XGP = (1 << 3), + ERR_STS_FOU = (1 << 4), + ERR_STS_FOC = (1 << 5), + ERR_STS_FOF = (1 << 6), + ERR_STS_FIU = (1 << 7), + ERR_STS_FIC = (1 << 8), + ERR_STS_FIF = (1 << 9), + ERR_STS_MOF = (1 << 10), + ERR_STS_TA = (1 << 11), + ERR_STS_MA = (1 << 12), + ERR_STS_MPE = (1 << 13), + ERR_STS_SCE = (1 << 14), + ERR_STS_STE = (1 << 15), + ERR_STS_FOW = (1 << 16), + ERR_STS_UE = (1 << 17), + ERR_STS_MCH = (1 << 26), + ERR_STS_LOC_SHIFT = 27, +}; + +/* + * RAM Debug Address Register (RAM_DBG_ADDR) bit definitions. + */ +enum { + RAM_DBG_ADDR_FW = (1 << 30), + RAM_DBG_ADDR_FR = (1 << 31), +}; + +/* + * Semaphore Register (SEM) bit definitions. + */ +enum { + /* + * Example: + * reg = SEM_XGMAC0_MASK | (SEM_SET << SEM_XGMAC0_SHIFT) + */ + SEM_CLEAR = 0, + SEM_SET = 1, + SEM_FORCE = 3, + SEM_XGMAC0_SHIFT = 0, + SEM_XGMAC1_SHIFT = 2, + SEM_ICB_SHIFT = 4, + SEM_MAC_ADDR_SHIFT = 6, + SEM_FLASH_SHIFT = 8, + SEM_PROBE_SHIFT = 10, + SEM_RT_IDX_SHIFT = 12, + SEM_PROC_REG_SHIFT = 14, + SEM_XGMAC0_MASK = 0x00030000, + SEM_XGMAC1_MASK = 0x000c0000, + SEM_ICB_MASK = 0x00300000, + SEM_MAC_ADDR_MASK = 0x00c00000, + SEM_FLASH_MASK = 0x03000000, + SEM_PROBE_MASK = 0x0c000000, + SEM_RT_IDX_MASK = 0x30000000, + SEM_PROC_REG_MASK = 0xc0000000, +}; + +/* + * 10G MAC Address Register (XGMAC_ADDR) bit definitions. + */ +enum { + XGMAC_ADDR_RDY = (1 << 31), + XGMAC_ADDR_R = (1 << 30), + XGMAC_ADDR_XME = (1 << 29), + + /* XGMAC control registers */ + PAUSE_SRC_LO = 0x00000100, + PAUSE_SRC_HI = 0x00000104, + GLOBAL_CFG = 0x00000108, + GLOBAL_CFG_RESET = (1 << 0), + GLOBAL_CFG_JUMBO = (1 << 6), + GLOBAL_CFG_TX_STAT_EN = (1 << 10), + GLOBAL_CFG_RX_STAT_EN = (1 << 11), + TX_CFG = 0x0000010c, + TX_CFG_RESET = (1 << 0), + TX_CFG_EN = (1 << 1), + TX_CFG_PREAM = (1 << 2), + RX_CFG = 0x00000110, + RX_CFG_RESET = (1 << 0), + RX_CFG_EN = (1 << 1), + RX_CFG_PREAM = (1 << 2), + FLOW_CTL = 0x0000011c, + PAUSE_OPCODE = 0x00000120, + PAUSE_TIMER = 0x00000124, + PAUSE_FRM_DEST_LO = 0x00000128, + PAUSE_FRM_DEST_HI = 0x0000012c, + MAC_TX_PARAMS = 0x00000134, + MAC_TX_PARAMS_JUMBO = (1 << 31), + MAC_TX_PARAMS_SIZE_SHIFT = 16, + MAC_RX_PARAMS = 0x00000138, + MAC_SYS_INT = 0x00000144, + MAC_SYS_INT_MASK = 0x00000148, + MAC_MGMT_INT = 0x0000014c, + MAC_MGMT_IN_MASK = 0x00000150, + EXT_ARB_MODE = 0x000001fc, + + /* XGMAC TX statistics registers */ + TX_PKTS = 0x00000200, + TX_BYTES = 0x00000208, + TX_MCAST_PKTS = 0x00000210, + TX_BCAST_PKTS = 0x00000218, + TX_UCAST_PKTS = 0x00000220, + TX_CTL_PKTS = 0x00000228, + TX_PAUSE_PKTS = 0x00000230, + TX_64_PKT = 0x00000238, + TX_65_TO_127_PKT = 0x00000240, + TX_128_TO_255_PKT = 0x00000248, + TX_256_511_PKT = 0x00000250, + TX_512_TO_1023_PKT = 0x00000258, + TX_1024_TO_1518_PKT = 0x00000260, + TX_1519_TO_MAX_PKT = 0x00000268, + TX_UNDERSIZE_PKT = 0x00000270, + TX_OVERSIZE_PKT = 0x00000278, + + /* XGMAC statistics control registers */ + RX_HALF_FULL_DET = 0x000002a0, + TX_HALF_FULL_DET = 0x000002a4, + RX_OVERFLOW_DET = 0x000002a8, + TX_OVERFLOW_DET = 0x000002ac, + RX_HALF_FULL_MASK = 0x000002b0, + TX_HALF_FULL_MASK = 0x000002b4, + RX_OVERFLOW_MASK = 0x000002b8, + TX_OVERFLOW_MASK = 0x000002bc, + STAT_CNT_CTL = 0x000002c0, + STAT_CNT_CTL_CLEAR_TX = (1 << 0), + STAT_CNT_CTL_CLEAR_RX = (1 << 1), + AUX_RX_HALF_FULL_DET = 0x000002d0, + AUX_TX_HALF_FULL_DET = 0x000002d4, + AUX_RX_OVERFLOW_DET = 0x000002d8, + AUX_TX_OVERFLOW_DET = 0x000002dc, + AUX_RX_HALF_FULL_MASK = 0x000002f0, + AUX_TX_HALF_FULL_MASK = 0x000002f4, + AUX_RX_OVERFLOW_MASK = 0x000002f8, + AUX_TX_OVERFLOW_MASK = 0x000002fc, + + /* XGMAC RX statistics registers */ + RX_BYTES = 0x00000300, + RX_BYTES_OK = 0x00000308, + RX_PKTS = 0x00000310, + RX_PKTS_OK = 0x00000318, + RX_BCAST_PKTS = 0x00000320, + RX_MCAST_PKTS = 0x00000328, + RX_UCAST_PKTS = 0x00000330, + RX_UNDERSIZE_PKTS = 0x00000338, + RX_OVERSIZE_PKTS = 0x00000340, + RX_JABBER_PKTS = 0x00000348, + RX_UNDERSIZE_FCERR_PKTS = 0x00000350, + RX_DROP_EVENTS = 0x00000358, + RX_FCERR_PKTS = 0x00000360, + RX_ALIGN_ERR = 0x00000368, + RX_SYMBOL_ERR = 0x00000370, + RX_MAC_ERR = 0x00000378, + RX_CTL_PKTS = 0x00000380, + RX_PAUSE_PKTS = 0x00000384, + RX_64_PKTS = 0x00000390, + RX_65_TO_127_PKTS = 0x00000398, + RX_128_255_PKTS = 0x000003a0, + RX_256_511_PKTS = 0x000003a8, + RX_512_TO_1023_PKTS = 0x000003b0, + RX_1024_TO_1518_PKTS = 0x000003b8, + RX_1519_TO_MAX_PKTS = 0x000003c0, + RX_LEN_ERR_PKTS = 0x000003c8, + + /* XGMAC MDIO control registers */ + MDIO_TX_DATA = 0x00000400, + MDIO_RX_DATA = 0x00000410, + MDIO_CMD = 0x00000420, + MDIO_PHY_ADDR = 0x00000430, + MDIO_PORT = 0x00000440, + MDIO_STATUS = 0x00000450, + + /* XGMAC AUX statistics registers */ +}; + +/* + * Enhanced Transmission Schedule Registers (NIC_ETS,CNA_ETS) bit definitions. + */ +enum { + ETS_QUEUE_SHIFT = 29, + ETS_REF = (1 << 26), + ETS_RS = (1 << 27), + ETS_P = (1 << 28), + ETS_FC_COS_SHIFT = 23, +}; + +/* + * Flash Address Register (FLASH_ADDR) bit definitions. + */ +enum { + FLASH_ADDR_RDY = (1 << 31), + FLASH_ADDR_R = (1 << 30), + FLASH_ADDR_ERR = (1 << 29), +}; + +/* + * Stop CQ Processing Register (CQ_STOP) bit definitions. + */ +enum { + CQ_STOP_QUEUE_MASK = (0x007f0000), + CQ_STOP_TYPE_MASK = (0x03000000), + CQ_STOP_TYPE_START = 0x00000100, + CQ_STOP_TYPE_STOP = 0x00000200, + CQ_STOP_TYPE_READ = 0x00000300, + CQ_STOP_EN = (1 << 15), +}; + +/* + * MAC Protocol Address Index Register (MAC_ADDR_IDX) bit definitions. + */ +enum { + MAC_ADDR_IDX_SHIFT = 4, + MAC_ADDR_TYPE_SHIFT = 16, + MAC_ADDR_TYPE_MASK = 0x000f0000, + MAC_ADDR_TYPE_CAM_MAC = 0x00000000, + MAC_ADDR_TYPE_MULTI_MAC = 0x00010000, + MAC_ADDR_TYPE_VLAN = 0x00020000, + MAC_ADDR_TYPE_MULTI_FLTR = 0x00030000, + MAC_ADDR_TYPE_FC_MAC = 0x00040000, + MAC_ADDR_TYPE_MGMT_MAC = 0x00050000, + MAC_ADDR_TYPE_MGMT_VLAN = 0x00060000, + MAC_ADDR_TYPE_MGMT_V4 = 0x00070000, + MAC_ADDR_TYPE_MGMT_V6 = 0x00080000, + MAC_ADDR_TYPE_MGMT_TU_DP = 0x00090000, + MAC_ADDR_ADR = (1 << 25), + MAC_ADDR_RS = (1 << 26), + MAC_ADDR_E = (1 << 27), + MAC_ADDR_MR = (1 << 30), + MAC_ADDR_MW = (1 << 31), + MAX_MULTICAST_ENTRIES = 32, +}; + +/* + * MAC Protocol Address Index Register (SPLT_HDR) bit definitions. + */ +enum { + SPLT_HDR_EP = (1 << 31), +}; + +/* + * FCoE Receive Configuration Register (FC_RCV_CFG) bit definitions. + */ +enum { + FC_RCV_CFG_ECT = (1 << 15), + FC_RCV_CFG_DFH = (1 << 20), + FC_RCV_CFG_DVF = (1 << 21), + FC_RCV_CFG_RCE = (1 << 27), + FC_RCV_CFG_RFE = (1 << 28), + FC_RCV_CFG_TEE = (1 << 29), + FC_RCV_CFG_TCE = (1 << 30), + FC_RCV_CFG_TFE = (1 << 31), +}; + +/* + * NIC Receive Configuration Register (NIC_RCV_CFG) bit definitions. + */ +enum { + NIC_RCV_CFG_PPE = (1 << 0), + NIC_RCV_CFG_VLAN_MASK = 0x00060000, + NIC_RCV_CFG_VLAN_ALL = 0x00000000, + NIC_RCV_CFG_VLAN_MATCH_ONLY = 0x00000002, + NIC_RCV_CFG_VLAN_MATCH_AND_NON = 0x00000004, + NIC_RCV_CFG_VLAN_NONE_AND_NON = 0x00000006, + NIC_RCV_CFG_RV = (1 << 3), + NIC_RCV_CFG_DFQ_MASK = (0x7f000000), + NIC_RCV_CFG_DFQ_SHIFT = 8, + NIC_RCV_CFG_DFQ = 0, /* HARDCODE default queue to 0. */ +}; + +/* + * Mgmt Receive Configuration Register (MGMT_RCV_CFG) bit definitions. + */ +enum { + MGMT_RCV_CFG_ARP = (1 << 0), + MGMT_RCV_CFG_DHC = (1 << 1), + MGMT_RCV_CFG_DHS = (1 << 2), + MGMT_RCV_CFG_NP = (1 << 3), + MGMT_RCV_CFG_I6N = (1 << 4), + MGMT_RCV_CFG_I6R = (1 << 5), + MGMT_RCV_CFG_DH6 = (1 << 6), + MGMT_RCV_CFG_UD1 = (1 << 7), + MGMT_RCV_CFG_UD0 = (1 << 8), + MGMT_RCV_CFG_BCT = (1 << 9), + MGMT_RCV_CFG_MCT = (1 << 10), + MGMT_RCV_CFG_DM = (1 << 11), + MGMT_RCV_CFG_RM = (1 << 12), + MGMT_RCV_CFG_STL = (1 << 13), + MGMT_RCV_CFG_VLAN_MASK = 0xc0000000, + MGMT_RCV_CFG_VLAN_ALL = 0x00000000, + MGMT_RCV_CFG_VLAN_MATCH_ONLY = 0x00004000, + MGMT_RCV_CFG_VLAN_MATCH_AND_NON = 0x00008000, + MGMT_RCV_CFG_VLAN_NONE_AND_NON = 0x0000c000, +}; + +/* + * Routing Index Register (RT_IDX) bit definitions. + */ +enum { + RT_IDX_IDX_SHIFT = 8, + RT_IDX_TYPE_MASK = 0x000f0000, + RT_IDX_TYPE_RT = 0x00000000, + RT_IDX_TYPE_RT_INV = 0x00010000, + RT_IDX_TYPE_NICQ = 0x00020000, + RT_IDX_TYPE_NICQ_INV = 0x00030000, + RT_IDX_DST_MASK = 0x00700000, + RT_IDX_DST_RSS = 0x00000000, + RT_IDX_DST_CAM_Q = 0x00100000, + RT_IDX_DST_COS_Q = 0x00200000, + RT_IDX_DST_DFLT_Q = 0x00300000, + RT_IDX_DST_DEST_Q = 0x00400000, + RT_IDX_RS = (1 << 26), + RT_IDX_E = (1 << 27), + RT_IDX_MR = (1 << 30), + RT_IDX_MW = (1 << 31), + + /* Nic Queue format - type 2 bits */ + RT_IDX_BCAST = (1 << 0), + RT_IDX_MCAST = (1 << 1), + RT_IDX_MCAST_MATCH = (1 << 2), + RT_IDX_MCAST_REG_MATCH = (1 << 3), + RT_IDX_MCAST_HASH_MATCH = (1 << 4), + RT_IDX_FC_MACH = (1 << 5), + RT_IDX_ETH_FCOE = (1 << 6), + RT_IDX_CAM_HIT = (1 << 7), + RT_IDX_CAM_BIT0 = (1 << 8), + RT_IDX_CAM_BIT1 = (1 << 9), + RT_IDX_VLAN_TAG = (1 << 10), + RT_IDX_VLAN_MATCH = (1 << 11), + RT_IDX_VLAN_FILTER = (1 << 12), + RT_IDX_ETH_SKIP1 = (1 << 13), + RT_IDX_ETH_SKIP2 = (1 << 14), + RT_IDX_BCAST_MCAST_MATCH = (1 << 15), + RT_IDX_802_3 = (1 << 16), + RT_IDX_LLDP = (1 << 17), + RT_IDX_UNUSED018 = (1 << 18), + RT_IDX_UNUSED019 = (1 << 19), + RT_IDX_UNUSED20 = (1 << 20), + RT_IDX_UNUSED21 = (1 << 21), + RT_IDX_ERR = (1 << 22), + RT_IDX_VALID = (1 << 23), + RT_IDX_TU_CSUM_ERR = (1 << 24), + RT_IDX_IP_CSUM_ERR = (1 << 25), + RT_IDX_MAC_ERR = (1 << 26), + RT_IDX_RSS_TCP6 = (1 << 27), + RT_IDX_RSS_TCP4 = (1 << 28), + RT_IDX_RSS_IPV6 = (1 << 29), + RT_IDX_RSS_IPV4 = (1 << 30), + RT_IDX_RSS_MATCH = (1 << 31), + + /* Hierarchy for the NIC Queue Mask */ + RT_IDX_ALL_ERR_SLOT = 0, + RT_IDX_MAC_ERR_SLOT = 0, + RT_IDX_IP_CSUM_ERR_SLOT = 1, + RT_IDX_TCP_UDP_CSUM_ERR_SLOT = 2, + RT_IDX_BCAST_SLOT = 3, + RT_IDX_MCAST_MATCH_SLOT = 4, + RT_IDX_ALLMULTI_SLOT = 5, + RT_IDX_UNUSED6_SLOT = 6, + RT_IDX_UNUSED7_SLOT = 7, + RT_IDX_RSS_MATCH_SLOT = 8, + RT_IDX_RSS_IPV4_SLOT = 8, + RT_IDX_RSS_IPV6_SLOT = 9, + RT_IDX_RSS_TCP4_SLOT = 10, + RT_IDX_RSS_TCP6_SLOT = 11, + RT_IDX_CAM_HIT_SLOT = 12, + RT_IDX_UNUSED013 = 13, + RT_IDX_UNUSED014 = 14, + RT_IDX_PROMISCUOUS_SLOT = 15, + RT_IDX_MAX_SLOTS = 16, +}; + +/* + * Control Register Set Map + */ +enum { + PROC_ADDR = 0, /* Use semaphore */ + PROC_DATA = 0x04, /* Use semaphore */ + SYS = 0x08, + RST_FO = 0x0c, + FSC = 0x10, + CSR = 0x14, + LED = 0x18, + ICB_RID = 0x1c, /* Use semaphore */ + ICB_L = 0x20, /* Use semaphore */ + ICB_H = 0x24, /* Use semaphore */ + CFG = 0x28, + BIOS_ADDR = 0x2c, + STS = 0x30, + INTR_EN = 0x34, + INTR_MASK = 0x38, + ISR1 = 0x3c, + ISR2 = 0x40, + ISR3 = 0x44, + ISR4 = 0x48, + REV_ID = 0x4c, + FRC_ECC_ERR = 0x50, + ERR_STS = 0x54, + RAM_DBG_ADDR = 0x58, + RAM_DBG_DATA = 0x5c, + ECC_ERR_CNT = 0x60, + SEM = 0x64, + GPIO_1 = 0x68, /* Use semaphore */ + GPIO_2 = 0x6c, /* Use semaphore */ + GPIO_3 = 0x70, /* Use semaphore */ + RSVD2 = 0x74, + XGMAC_ADDR = 0x78, /* Use semaphore */ + XGMAC_DATA = 0x7c, /* Use semaphore */ + NIC_ETS = 0x80, + CNA_ETS = 0x84, + FLASH_ADDR = 0x88, /* Use semaphore */ + FLASH_DATA = 0x8c, /* Use semaphore */ + CQ_STOP = 0x90, + PAGE_TBL_RID = 0x94, + WQ_PAGE_TBL_LO = 0x98, + WQ_PAGE_TBL_HI = 0x9c, + CQ_PAGE_TBL_LO = 0xa0, + CQ_PAGE_TBL_HI = 0xa4, + MAC_ADDR_IDX = 0xa8, /* Use semaphore */ + MAC_ADDR_DATA = 0xac, /* Use semaphore */ + COS_DFLT_CQ1 = 0xb0, + COS_DFLT_CQ2 = 0xb4, + ETYPE_SKIP1 = 0xb8, + ETYPE_SKIP2 = 0xbc, + SPLT_HDR = 0xc0, + FC_PAUSE_THRES = 0xc4, + NIC_PAUSE_THRES = 0xc8, + FC_ETHERTYPE = 0xcc, + FC_RCV_CFG = 0xd0, + NIC_RCV_CFG = 0xd4, + FC_COS_TAGS = 0xd8, + NIC_COS_TAGS = 0xdc, + MGMT_RCV_CFG = 0xe0, + RT_IDX = 0xe4, + RT_DATA = 0xe8, + RSVD7 = 0xec, + XG_SERDES_ADDR = 0xf0, + XG_SERDES_DATA = 0xf4, + PRB_MX_ADDR = 0xf8, /* Use semaphore */ + PRB_MX_DATA = 0xfc, /* Use semaphore */ +}; + +/* + * CAM output format. + */ +enum { + CAM_OUT_ROUTE_FC = 0, + CAM_OUT_ROUTE_NIC = 1, + CAM_OUT_FUNC_SHIFT = 2, + CAM_OUT_RV = (1 << 4), + CAM_OUT_SH = (1 << 15), + CAM_OUT_CQ_ID_SHIFT = 5, +}; + +/* + * Mailbox definitions + */ +enum { + /* Asynchronous Event Notifications */ + AEN_SYS_ERR = 0x00008002, + AEN_LINK_UP = 0x00008011, + AEN_LINK_DOWN = 0x00008012, + AEN_IDC_CMPLT = 0x00008100, + AEN_IDC_REQ = 0x00008101, + AEN_FW_INIT_DONE = 0x00008400, + AEN_FW_INIT_FAIL = 0x00008401, + + /* Mailbox Command Opcodes. */ + MB_CMD_NOP = 0x00000000, + MB_CMD_EX_FW = 0x00000002, + MB_CMD_MB_TEST = 0x00000006, + MB_CMD_CSUM_TEST = 0x00000007, /* Verify Checksum */ + MB_CMD_ABOUT_FW = 0x00000008, + MB_CMD_LOAD_RISC_RAM = 0x0000000b, + MB_CMD_DUMP_RISC_RAM = 0x0000000c, + MB_CMD_WRITE_RAM = 0x0000000d, + MB_CMD_READ_RAM = 0x0000000f, + MB_CMD_STOP_FW = 0x00000014, + MB_CMD_MAKE_SYS_ERR = 0x0000002a, + MB_CMD_INIT_FW = 0x00000060, + MB_CMD_GET_INIT_CB = 0x00000061, + MB_CMD_GET_FW_STATE = 0x00000069, + MB_CMD_IDC_REQ = 0x00000100, /* Inter-Driver Communication */ + MB_CMD_IDC_ACK = 0x00000101, /* Inter-Driver Communication */ + MB_CMD_SET_WOL_MODE = 0x00000110, /* Wake On Lan */ + MB_WOL_DISABLE = 0x00000000, + MB_WOL_MAGIC_PKT = 0x00000001, + MB_WOL_FLTR = 0x00000002, + MB_WOL_UCAST = 0x00000004, + MB_WOL_MCAST = 0x00000008, + MB_WOL_BCAST = 0x00000010, + MB_WOL_LINK_UP = 0x00000020, + MB_WOL_LINK_DOWN = 0x00000040, + MB_CMD_SET_WOL_FLTR = 0x00000111, /* Wake On Lan Filter */ + MB_CMD_CLEAR_WOL_FLTR = 0x00000112, /* Wake On Lan Filter */ + MB_CMD_SET_WOL_MAGIC = 0x00000113, /* Wake On Lan Magic Packet */ + MB_CMD_CLEAR_WOL_MAGIC = 0x00000114, /* Wake On Lan Magic Packet */ + MB_CMD_PORT_RESET = 0x00000120, + MB_CMD_SET_PORT_CFG = 0x00000122, + MB_CMD_GET_PORT_CFG = 0x00000123, + MB_CMD_SET_ASIC_VOLTS = 0x00000130, + MB_CMD_GET_SNS_DATA = 0x00000131, /* Temp and Volt Sense data. */ + + /* Mailbox Command Status. */ + MB_CMD_STS_GOOD = 0x00004000, /* Success. */ + MB_CMD_STS_INTRMDT = 0x00001000, /* Intermediate Complete. */ + MB_CMD_STS_ERR = 0x00004005, /* Error. */ +}; + +struct mbox_params { + u32 mbox_in[MAILBOX_COUNT]; + u32 mbox_out[MAILBOX_COUNT]; + int in_count; + int out_count; +}; + +struct flash_params { + u8 dev_id_str[4]; + u16 size; + u16 csum; + u16 ver; + u16 sub_dev_id; + u8 mac_addr[6]; + u16 res; +}; + + +/* + * doorbell space for the rx ring context + */ +struct rx_doorbell_context { + u32 cnsmr_idx; /* 0x00 */ + u32 valid; /* 0x04 */ + u32 reserved[4]; /* 0x08-0x14 */ + u32 lbq_prod_idx; /* 0x18 */ + u32 sbq_prod_idx; /* 0x1c */ +}; + +/* + * doorbell space for the tx ring context + */ +struct tx_doorbell_context { + u32 prod_idx; /* 0x00 */ + u32 valid; /* 0x04 */ + u32 reserved[4]; /* 0x08-0x14 */ + u32 lbq_prod_idx; /* 0x18 */ + u32 sbq_prod_idx; /* 0x1c */ +}; + +/* DATA STRUCTURES SHARED WITH HARDWARE. */ + +struct bq_element { + u32 addr_lo; +#define BQ_END 0x00000001 +#define BQ_CONT 0x00000002 +#define BQ_MASK 0x00000003 + u32 addr_hi; +} __attribute((packed)); + +struct tx_buf_desc { + __le64 addr; + __le32 len; +#define TX_DESC_LEN_MASK 0x000fffff +#define TX_DESC_C 0x40000000 +#define TX_DESC_E 0x80000000 +} __attribute((packed)); + +/* + * IOCB Definitions... + */ + +#define OPCODE_OB_MAC_IOCB 0x01 +#define OPCODE_OB_MAC_TSO_IOCB 0x02 +#define OPCODE_IB_MAC_IOCB 0x20 +#define OPCODE_IB_MPI_IOCB 0x21 +#define OPCODE_IB_AE_IOCB 0x3f + +struct ob_mac_iocb_req { + u8 opcode; + u8 flags1; +#define OB_MAC_IOCB_REQ_OI 0x01 +#define OB_MAC_IOCB_REQ_I 0x02 +#define OB_MAC_IOCB_REQ_D 0x08 +#define OB_MAC_IOCB_REQ_F 0x10 + u8 flags2; + u8 flags3; +#define OB_MAC_IOCB_DFP 0x02 +#define OB_MAC_IOCB_V 0x04 + __le32 reserved1[2]; + __le16 frame_len; +#define OB_MAC_IOCB_LEN_MASK 0x3ffff + __le16 reserved2; + __le32 tid; + __le32 txq_idx; + __le32 reserved3; + __le16 vlan_tci; + __le16 reserved4; + struct tx_buf_desc tbd[TX_DESC_PER_IOCB]; +} __attribute((packed)); + +struct ob_mac_iocb_rsp { + u8 opcode; /* */ + u8 flags1; /* */ +#define OB_MAC_IOCB_RSP_OI 0x01 /* */ +#define OB_MAC_IOCB_RSP_I 0x02 /* */ +#define OB_MAC_IOCB_RSP_E 0x08 /* */ +#define OB_MAC_IOCB_RSP_S 0x10 /* too Short */ +#define OB_MAC_IOCB_RSP_L 0x20 /* too Large */ +#define OB_MAC_IOCB_RSP_P 0x40 /* Padded */ + u8 flags2; /* */ + u8 flags3; /* */ +#define OB_MAC_IOCB_RSP_B 0x80 /* */ + __le32 tid; + __le32 txq_idx; + __le32 reserved[13]; +} __attribute((packed)); + +struct ob_mac_tso_iocb_req { + u8 opcode; + u8 flags1; +#define OB_MAC_TSO_IOCB_OI 0x01 +#define OB_MAC_TSO_IOCB_I 0x02 +#define OB_MAC_TSO_IOCB_D 0x08 +#define OB_MAC_TSO_IOCB_IP4 0x40 +#define OB_MAC_TSO_IOCB_IP6 0x80 + u8 flags2; +#define OB_MAC_TSO_IOCB_LSO 0x20 +#define OB_MAC_TSO_IOCB_UC 0x40 +#define OB_MAC_TSO_IOCB_TC 0x80 + u8 flags3; +#define OB_MAC_TSO_IOCB_IC 0x01 +#define OB_MAC_TSO_IOCB_DFP 0x02 +#define OB_MAC_TSO_IOCB_V 0x04 + __le32 reserved1[2]; + __le32 frame_len; + __le32 tid; + __le32 txq_idx; + __le16 total_hdrs_len; + __le16 net_trans_offset; +#define OB_MAC_TRANSPORT_HDR_SHIFT 6 + __le16 vlan_tci; + __le16 mss; + struct tx_buf_desc tbd[TX_DESC_PER_IOCB]; +} __attribute((packed)); + +struct ob_mac_tso_iocb_rsp { + u8 opcode; + u8 flags1; +#define OB_MAC_TSO_IOCB_RSP_OI 0x01 +#define OB_MAC_TSO_IOCB_RSP_I 0x02 +#define OB_MAC_TSO_IOCB_RSP_E 0x08 +#define OB_MAC_TSO_IOCB_RSP_S 0x10 +#define OB_MAC_TSO_IOCB_RSP_L 0x20 +#define OB_MAC_TSO_IOCB_RSP_P 0x40 + u8 flags2; /* */ + u8 flags3; /* */ +#define OB_MAC_TSO_IOCB_RSP_B 0x8000 + __le32 tid; + __le32 txq_idx; + __le32 reserved2[13]; +} __attribute((packed)); + +struct ib_mac_iocb_rsp { + u8 opcode; /* 0x20 */ + u8 flags1; +#define IB_MAC_IOCB_RSP_OI 0x01 /* Overide intr delay */ +#define IB_MAC_IOCB_RSP_I 0x02 /* Disble Intr Generation */ +#define IB_MAC_IOCB_RSP_TE 0x04 /* Checksum error */ +#define IB_MAC_IOCB_RSP_NU 0x08 /* No checksum rcvd */ +#define IB_MAC_IOCB_RSP_IE 0x10 /* IPv4 checksum error */ +#define IB_MAC_IOCB_RSP_M_MASK 0x60 /* Multicast info */ +#define IB_MAC_IOCB_RSP_M_NONE 0x00 /* Not mcast frame */ +#define IB_MAC_IOCB_RSP_M_HASH 0x20 /* HASH mcast frame */ +#define IB_MAC_IOCB_RSP_M_REG 0x40 /* Registered mcast frame */ +#define IB_MAC_IOCB_RSP_M_PROM 0x60 /* Promiscuous mcast frame */ +#define IB_MAC_IOCB_RSP_B 0x80 /* Broadcast frame */ + u8 flags2; +#define IB_MAC_IOCB_RSP_P 0x01 /* Promiscuous frame */ +#define IB_MAC_IOCB_RSP_V 0x02 /* Vlan tag present */ +#define IB_MAC_IOCB_RSP_ERR_MASK 0x1c /* */ +#define IB_MAC_IOCB_RSP_ERR_CODE_ERR 0x04 +#define IB_MAC_IOCB_RSP_ERR_OVERSIZE 0x08 +#define IB_MAC_IOCB_RSP_ERR_UNDERSIZE 0x10 +#define IB_MAC_IOCB_RSP_ERR_PREAMBLE 0x14 +#define IB_MAC_IOCB_RSP_ERR_FRAME_LEN 0x18 +#define IB_MAC_IOCB_RSP_ERR_CRC 0x1c +#define IB_MAC_IOCB_RSP_U 0x20 /* UDP packet */ +#define IB_MAC_IOCB_RSP_T 0x40 /* TCP packet */ +#define IB_MAC_IOCB_RSP_FO 0x80 /* Failover port */ + u8 flags3; +#define IB_MAC_IOCB_RSP_RSS_MASK 0x07 /* RSS mask */ +#define IB_MAC_IOCB_RSP_M_NONE 0x00 /* No RSS match */ +#define IB_MAC_IOCB_RSP_M_IPV4 0x04 /* IPv4 RSS match */ +#define IB_MAC_IOCB_RSP_M_IPV6 0x02 /* IPv6 RSS match */ +#define IB_MAC_IOCB_RSP_M_TCP_V4 0x05 /* TCP with IPv4 */ +#define IB_MAC_IOCB_RSP_M_TCP_V6 0x03 /* TCP with IPv6 */ +#define IB_MAC_IOCB_RSP_V4 0x08 /* IPV4 */ +#define IB_MAC_IOCB_RSP_V6 0x10 /* IPV6 */ +#define IB_MAC_IOCB_RSP_IH 0x20 /* Split after IP header */ +#define IB_MAC_IOCB_RSP_DS 0x40 /* data is in small buffer */ +#define IB_MAC_IOCB_RSP_DL 0x80 /* data is in large buffer */ + __le32 data_len; /* */ + __le32 data_addr_lo; /* */ + __le32 data_addr_hi; /* */ + __le32 rss; /* */ + __le16 vlan_id; /* 12 bits */ +#define IB_MAC_IOCB_RSP_C 0x1000 /* VLAN CFI bit */ +#define IB_MAC_IOCB_RSP_COS_SHIFT 12 /* class of service value */ + + __le16 reserved1; + __le32 reserved2[6]; + __le32 flags4; +#define IB_MAC_IOCB_RSP_HV 0x20000000 /* */ +#define IB_MAC_IOCB_RSP_HS 0x40000000 /* */ +#define IB_MAC_IOCB_RSP_HL 0x80000000 /* */ + __le32 hdr_len; /* */ + __le32 hdr_addr_lo; /* */ + __le32 hdr_addr_hi; /* */ +} __attribute((packed)); + +struct ib_ae_iocb_rsp { + u8 opcode; + u8 flags1; +#define IB_AE_IOCB_RSP_OI 0x01 +#define IB_AE_IOCB_RSP_I 0x02 + u8 event; +#define LINK_UP_EVENT 0x00 +#define LINK_DOWN_EVENT 0x01 +#define CAM_LOOKUP_ERR_EVENT 0x06 +#define SOFT_ECC_ERROR_EVENT 0x07 +#define MGMT_ERR_EVENT 0x08 +#define TEN_GIG_MAC_EVENT 0x09 +#define GPI0_H2L_EVENT 0x10 +#define GPI0_L2H_EVENT 0x20 +#define GPI1_H2L_EVENT 0x11 +#define GPI1_L2H_EVENT 0x21 +#define PCI_ERR_ANON_BUF_RD 0x40 + u8 q_id; + __le32 reserved[15]; +} __attribute((packed)); + +/* + * These three structures are for generic + * handling of ib and ob iocbs. + */ +struct ql_net_rsp_iocb { + u8 opcode; + u8 flags0; + __le16 length; + __le32 tid; + __le32 reserved[14]; +} __attribute((packed)); + +struct net_req_iocb { + u8 opcode; + u8 flags0; + __le16 flags1; + __le32 tid; + __le32 reserved1[30]; +} __attribute((packed)); + +/* + * tx ring initialization control block for chip. + * It is defined as: + * "Work Queue Initialization Control Block" + */ +struct wqicb { + __le16 len; +#define Q_LEN_V (1 << 4) +#define Q_LEN_CPP_CONT 0x0000 +#define Q_LEN_CPP_16 0x0001 +#define Q_LEN_CPP_32 0x0002 +#define Q_LEN_CPP_64 0x0003 + __le16 flags; +#define Q_PRI_SHIFT 1 +#define Q_FLAGS_LC 0x1000 +#define Q_FLAGS_LB 0x2000 +#define Q_FLAGS_LI 0x4000 +#define Q_FLAGS_LO 0x8000 + __le16 cq_id_rss; +#define Q_CQ_ID_RSS_RV 0x8000 + __le16 rid; + __le32 addr_lo; + __le32 addr_hi; + __le32 cnsmr_idx_addr_lo; + __le32 cnsmr_idx_addr_hi; +} __attribute((packed)); + +/* + * rx ring initialization control block for chip. + * It is defined as: + * "Completion Queue Initialization Control Block" + */ +struct cqicb { + u8 msix_vect; + u8 reserved1; + u8 reserved2; + u8 flags; +#define FLAGS_LV 0x08 +#define FLAGS_LS 0x10 +#define FLAGS_LL 0x20 +#define FLAGS_LI 0x40 +#define FLAGS_LC 0x80 + __le16 len; +#define LEN_V (1 << 4) +#define LEN_CPP_CONT 0x0000 +#define LEN_CPP_32 0x0001 +#define LEN_CPP_64 0x0002 +#define LEN_CPP_128 0x0003 + __le16 rid; + __le32 addr_lo; + __le32 addr_hi; + __le32 prod_idx_addr_lo; + __le32 prod_idx_addr_hi; + __le16 pkt_delay; + __le16 irq_delay; + __le32 lbq_addr_lo; + __le32 lbq_addr_hi; + __le16 lbq_buf_size; + __le16 lbq_len; /* entry count */ + __le32 sbq_addr_lo; + __le32 sbq_addr_hi; + __le16 sbq_buf_size; + __le16 sbq_len; /* entry count */ +} __attribute((packed)); + +struct ricb { + u8 base_cq; +#define RSS_L4K 0x80 + u8 flags; +#define RSS_L6K 0x01 +#define RSS_LI 0x02 +#define RSS_LB 0x04 +#define RSS_LM 0x08 +#define RSS_RI4 0x10 +#define RSS_RT4 0x20 +#define RSS_RI6 0x40 +#define RSS_RT6 0x80 + __le16 mask; + __le32 hash_cq_id[256]; + __le32 ipv6_hash_key[10]; + __le32 ipv4_hash_key[4]; +} __attribute((packed)); + +/* SOFTWARE/DRIVER DATA STRUCTURES. */ + +struct oal { + struct tx_buf_desc oal[TX_DESC_PER_OAL]; +}; + +struct map_list { + DECLARE_PCI_UNMAP_ADDR(mapaddr); + DECLARE_PCI_UNMAP_LEN(maplen); +}; + +struct tx_ring_desc { + struct sk_buff *skb; + struct ob_mac_iocb_req *queue_entry; + int index; + struct oal oal; + struct map_list map[MAX_SKB_FRAGS + 1]; + int map_cnt; + struct tx_ring_desc *next; +}; + +struct bq_desc { + union { + struct page *lbq_page; + struct sk_buff *skb; + } p; + struct bq_element *bq; + int index; + DECLARE_PCI_UNMAP_ADDR(mapaddr); + DECLARE_PCI_UNMAP_LEN(maplen); +}; + +#define QL_TXQ_IDX(qdev, skb) (smp_processor_id()%(qdev->tx_ring_count)) + +struct tx_ring { + /* + * queue info. + */ + struct wqicb wqicb; /* structure used to inform chip of new queue */ + void *wq_base; /* pci_alloc:virtual addr for tx */ + dma_addr_t wq_base_dma; /* pci_alloc:dma addr for tx */ + u32 *cnsmr_idx_sh_reg; /* shadow copy of consumer idx */ + dma_addr_t cnsmr_idx_sh_reg_dma; /* dma-shadow copy of consumer */ + u32 wq_size; /* size in bytes of queue area */ + u32 wq_len; /* number of entries in queue */ + void __iomem *prod_idx_db_reg; /* doorbell area index reg at offset 0x00 */ + void __iomem *valid_db_reg; /* doorbell area valid reg at offset 0x04 */ + u16 prod_idx; /* current value for prod idx */ + u16 cq_id; /* completion (rx) queue for tx completions */ + u8 wq_id; /* queue id for this entry */ + u8 reserved1[3]; + struct tx_ring_desc *q; /* descriptor list for the queue */ + spinlock_t lock; + atomic_t tx_count; /* counts down for every outstanding IO */ + atomic_t queue_stopped; /* Turns queue off when full. */ + struct delayed_work tx_work; + struct ql_adapter *qdev; +}; + +/* + * Type of inbound queue. + */ +enum { + DEFAULT_Q = 2, /* Handles slow queue and chip/MPI events. */ + TX_Q = 3, /* Handles outbound completions. */ + RX_Q = 4, /* Handles inbound completions. */ +}; + +struct rx_ring { + struct cqicb cqicb; /* The chip's completion queue init control block. */ + + /* Completion queue elements. */ + void *cq_base; + dma_addr_t cq_base_dma; + u32 cq_size; + u32 cq_len; + u16 cq_id; + u32 *prod_idx_sh_reg; /* Shadowed producer register. */ + dma_addr_t prod_idx_sh_reg_dma; + void __iomem *cnsmr_idx_db_reg; /* PCI doorbell mem area + 0 */ + u32 cnsmr_idx; /* current sw idx */ + struct ql_net_rsp_iocb *curr_entry; /* next entry on queue */ + void __iomem *valid_db_reg; /* PCI doorbell mem area + 0x04 */ + + /* Large buffer queue elements. */ + u32 lbq_len; /* entry count */ + u32 lbq_size; /* size in bytes of queue */ + u32 lbq_buf_size; + void *lbq_base; + dma_addr_t lbq_base_dma; + void *lbq_base_indirect; + dma_addr_t lbq_base_indirect_dma; + struct bq_desc *lbq; /* array of control blocks */ + void __iomem *lbq_prod_idx_db_reg; /* PCI doorbell mem area + 0x18 */ + u32 lbq_prod_idx; /* current sw prod idx */ + u32 lbq_curr_idx; /* next entry we expect */ + u32 lbq_clean_idx; /* beginning of new descs */ + u32 lbq_free_cnt; /* free buffer desc cnt */ + + /* Small buffer queue elements. */ + u32 sbq_len; /* entry count */ + u32 sbq_size; /* size in bytes of queue */ + u32 sbq_buf_size; + void *sbq_base; + dma_addr_t sbq_base_dma; + void *sbq_base_indirect; + dma_addr_t sbq_base_indirect_dma; + struct bq_desc *sbq; /* array of control blocks */ + void __iomem *sbq_prod_idx_db_reg; /* PCI doorbell mem area + 0x1c */ + u32 sbq_prod_idx; /* current sw prod idx */ + u32 sbq_curr_idx; /* next entry we expect */ + u32 sbq_clean_idx; /* beginning of new descs */ + u32 sbq_free_cnt; /* free buffer desc cnt */ + + /* Misc. handler elements. */ + u32 type; /* Type of queue, tx, rx, or default. */ + u32 irq; /* Which vector this ring is assigned. */ + u32 cpu; /* Which CPU this should run on. */ + char name[IFNAMSIZ + 5]; + struct napi_struct napi; + struct delayed_work rx_work; + u8 reserved; + struct ql_adapter *qdev; +}; + +/* + * RSS Initialization Control Block + */ +struct hash_id { + u8 value[4]; +}; + +struct nic_stats { + /* + * These stats come from offset 200h to 278h + * in the XGMAC register. + */ + u64 tx_pkts; + u64 tx_bytes; + u64 tx_mcast_pkts; + u64 tx_bcast_pkts; + u64 tx_ucast_pkts; + u64 tx_ctl_pkts; + u64 tx_pause_pkts; + u64 tx_64_pkt; + u64 tx_65_to_127_pkt; + u64 tx_128_to_255_pkt; + u64 tx_256_511_pkt; + u64 tx_512_to_1023_pkt; + u64 tx_1024_to_1518_pkt; + u64 tx_1519_to_max_pkt; + u64 tx_undersize_pkt; + u64 tx_oversize_pkt; + + /* + * These stats come from offset 300h to 3C8h + * in the XGMAC register. + */ + u64 rx_bytes; + u64 rx_bytes_ok; + u64 rx_pkts; + u64 rx_pkts_ok; + u64 rx_bcast_pkts; + u64 rx_mcast_pkts; + u64 rx_ucast_pkts; + u64 rx_undersize_pkts; + u64 rx_oversize_pkts; + u64 rx_jabber_pkts; + u64 rx_undersize_fcerr_pkts; + u64 rx_drop_events; + u64 rx_fcerr_pkts; + u64 rx_align_err; + u64 rx_symbol_err; + u64 rx_mac_err; + u64 rx_ctl_pkts; + u64 rx_pause_pkts; + u64 rx_64_pkts; + u64 rx_65_to_127_pkts; + u64 rx_128_255_pkts; + u64 rx_256_511_pkts; + u64 rx_512_to_1023_pkts; + u64 rx_1024_to_1518_pkts; + u64 rx_1519_to_max_pkts; + u64 rx_len_err_pkts; +}; + +/* + * intr_context structure is used during initialization + * to hook the interrupts. It is also used in a single + * irq environment as a context to the ISR. + */ +struct intr_context { + struct ql_adapter *qdev; + u32 intr; + u32 hooked; + u32 intr_en_mask; /* value/mask used to enable this intr */ + u32 intr_dis_mask; /* value/mask used to disable this intr */ + u32 intr_read_mask; /* value/mask used to read this intr */ + char name[IFNAMSIZ * 2]; + atomic_t irq_cnt; /* irq_cnt is used in single vector + * environment. It's incremented for each + * irq handler that is scheduled. When each + * handler finishes it decrements irq_cnt and + * enables interrupts if it's zero. */ + irq_handler_t handler; +}; + +/* adapter flags definitions. */ +enum { + QL_ADAPTER_UP = (1 << 0), /* Adapter has been brought up. */ + QL_LEGACY_ENABLED = (1 << 3), + QL_MSI_ENABLED = (1 << 3), + QL_MSIX_ENABLED = (1 << 4), + QL_DMA64 = (1 << 5), + QL_PROMISCUOUS = (1 << 6), + QL_ALLMULTI = (1 << 7), +}; + +/* link_status bit definitions */ +enum { + LOOPBACK_MASK = 0x00000700, + LOOPBACK_PCS = 0x00000100, + LOOPBACK_HSS = 0x00000200, + LOOPBACK_EXT = 0x00000300, + PAUSE_MASK = 0x000000c0, + PAUSE_STD = 0x00000040, + PAUSE_PRI = 0x00000080, + SPEED_MASK = 0x00000038, + SPEED_100Mb = 0x00000000, + SPEED_1Gb = 0x00000008, + SPEED_10Gb = 0x00000010, + LINK_TYPE_MASK = 0x00000007, + LINK_TYPE_XFI = 0x00000001, + LINK_TYPE_XAUI = 0x00000002, + LINK_TYPE_XFI_BP = 0x00000003, + LINK_TYPE_XAUI_BP = 0x00000004, + LINK_TYPE_10GBASET = 0x00000005, +}; + +/* + * The main Adapter structure definition. + * This structure has all fields relevant to the hardware. + */ +struct ql_adapter { + struct ricb ricb; + unsigned long flags; + u32 wol; + + struct nic_stats nic_stats; + + struct vlan_group *vlgrp; + + /* PCI Configuration information for this device */ + struct pci_dev *pdev; + struct net_device *ndev; /* Parent NET device */ + + /* Hardware information */ + u32 chip_rev_id; + u32 func; /* PCI function for this adapter */ + + spinlock_t adapter_lock; + spinlock_t hw_lock; + spinlock_t stats_lock; + spinlock_t legacy_lock; /* used for maintaining legacy intr sync */ + + /* PCI Bus Relative Register Addresses */ + void __iomem *reg_base; + void __iomem *doorbell_area; + u32 doorbell_area_size; + + u32 msg_enable; + + /* Page for Shadow Registers */ + void *rx_ring_shadow_reg_area; + dma_addr_t rx_ring_shadow_reg_dma; + void *tx_ring_shadow_reg_area; + dma_addr_t tx_ring_shadow_reg_dma; + + u32 mailbox_in; + u32 mailbox_out; + + int tx_ring_size; + int rx_ring_size; + u32 intr_count; + struct msix_entry *msi_x_entry; + struct intr_context intr_context[MAX_RX_RINGS]; + + int (*legacy_check) (struct ql_adapter *); + + int tx_ring_count; /* One per online CPU. */ + u32 rss_ring_first_cq_id;/* index of first inbound (rss) rx_ring */ + u32 rss_ring_count; /* One per online CPU. */ + /* + * rx_ring_count = + * one default queue + + * (CPU count * outbound completion rx_ring) + + * (CPU count * inbound (RSS) completion rx_ring) + */ + int rx_ring_count; + int ring_mem_size; + void *ring_mem; + struct rx_ring *rx_ring; + int rx_csum; + struct tx_ring *tx_ring; + u32 default_rx_queue; + + u16 rx_coalesce_usecs; /* cqicb->int_delay */ + u16 rx_max_coalesced_frames; /* cqicb->pkt_int_delay */ + u16 tx_coalesce_usecs; /* cqicb->int_delay */ + u16 tx_max_coalesced_frames; /* cqicb->pkt_int_delay */ + + u32 xg_sem_mask; + u32 port_link_up; + u32 port_init; + u32 link_status; + + struct flash_params flash; + + struct net_device_stats stats; + struct workqueue_struct *q_workqueue; + struct workqueue_struct *workqueue; + struct delayed_work asic_reset_work; + struct delayed_work mpi_reset_work; + struct delayed_work mpi_work; +}; + +/* + * Typical Register accessor for memory mapped device. + */ +static inline u32 ql_read32(const struct ql_adapter *qdev, int reg) +{ + return readl(qdev->reg_base + reg); +} + +/* + * Typical Register accessor for memory mapped device. + */ +static inline void ql_write32(const struct ql_adapter *qdev, int reg, u32 val) +{ + writel(val, qdev->reg_base + reg); +} + +/* + * Doorbell Registers: + * Doorbell registers are virtual registers in the PCI memory space. + * The space is allocated by the chip during PCI initialization. The + * device driver finds the doorbell address in BAR 3 in PCI config space. + * The registers are used to control outbound and inbound queues. For + * example, the producer index for an outbound queue. Each queue uses + * 1 4k chunk of memory. The lower half of the space is for outbound + * queues. The upper half is for inbound queues. + */ +static inline void ql_write_db_reg(u32 val, void __iomem *addr) +{ + writel(val, addr); + mmiowb(); +} + +/* + * Shadow Registers: + * Outbound queues have a consumer index that is maintained by the chip. + * Inbound queues have a producer index that is maintained by the chip. + * For lower overhead, these registers are "shadowed" to host memory + * which allows the device driver to track the queue progress without + * PCI reads. When an entry is placed on an inbound queue, the chip will + * update the relevant index register and then copy the value to the + * shadow register in host memory. + */ +static inline unsigned int ql_read_sh_reg(const volatile void *addr) +{ + return *(volatile unsigned int __force *)addr; +} + +extern char qlge_driver_name[]; +extern const char qlge_driver_version[]; +extern const struct ethtool_ops qlge_ethtool_ops; + +extern int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask); +extern void ql_sem_unlock(struct ql_adapter *qdev, u32 sem_mask); +extern int ql_read_xgmac_reg(struct ql_adapter *qdev, u32 reg, u32 *data); +extern int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index, + u32 *value); +extern int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value); +extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, + u16 q_id); +void ql_queue_fw_error(struct ql_adapter *qdev); +void ql_mpi_work(struct work_struct *work); +void ql_mpi_reset_work(struct work_struct *work); +int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit); +void ql_queue_asic_error(struct ql_adapter *qdev); +void ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); +void ql_set_ethtool_ops(struct net_device *ndev); +int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data); + +#if 1 +#define QL_ALL_DUMP +#define QL_REG_DUMP +#define QL_DEV_DUMP +#define QL_CB_DUMP +/* #define QL_IB_DUMP */ +/* #define QL_OB_DUMP */ +#endif + +#ifdef QL_REG_DUMP +extern void ql_dump_xgmac_control_regs(struct ql_adapter *qdev); +extern void ql_dump_routing_entries(struct ql_adapter *qdev); +extern void ql_dump_regs(struct ql_adapter *qdev); +#define QL_DUMP_REGS(qdev) ql_dump_regs(qdev) +#define QL_DUMP_ROUTE(qdev) ql_dump_routing_entries(qdev) +#define QL_DUMP_XGMAC_CONTROL_REGS(qdev) ql_dump_xgmac_control_regs(qdev) +#else +#define QL_DUMP_REGS(qdev) +#define QL_DUMP_ROUTE(qdev) +#define QL_DUMP_XGMAC_CONTROL_REGS(qdev) +#endif + +#ifdef QL_STAT_DUMP +extern void ql_dump_stat(struct ql_adapter *qdev); +#define QL_DUMP_STAT(qdev) ql_dump_stat(qdev) +#else +#define QL_DUMP_STAT(qdev) +#endif + +#ifdef QL_DEV_DUMP +extern void ql_dump_qdev(struct ql_adapter *qdev); +#define QL_DUMP_QDEV(qdev) ql_dump_qdev(qdev) +#else +#define QL_DUMP_QDEV(qdev) +#endif + +#ifdef QL_CB_DUMP +extern void ql_dump_wqicb(struct wqicb *wqicb); +extern void ql_dump_tx_ring(struct tx_ring *tx_ring); +extern void ql_dump_ricb(struct ricb *ricb); +extern void ql_dump_cqicb(struct cqicb *cqicb); +extern void ql_dump_rx_ring(struct rx_ring *rx_ring); +extern void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id); +#define QL_DUMP_RICB(ricb) ql_dump_ricb(ricb) +#define QL_DUMP_WQICB(wqicb) ql_dump_wqicb(wqicb) +#define QL_DUMP_TX_RING(tx_ring) ql_dump_tx_ring(tx_ring) +#define QL_DUMP_CQICB(cqicb) ql_dump_cqicb(cqicb) +#define QL_DUMP_RX_RING(rx_ring) ql_dump_rx_ring(rx_ring) +#define QL_DUMP_HW_CB(qdev, size, bit, q_id) \ + ql_dump_hw_cb(qdev, size, bit, q_id) +#else +#define QL_DUMP_RICB(ricb) +#define QL_DUMP_WQICB(wqicb) +#define QL_DUMP_TX_RING(tx_ring) +#define QL_DUMP_CQICB(cqicb) +#define QL_DUMP_RX_RING(rx_ring) +#define QL_DUMP_HW_CB(qdev, size, bit, q_id) +#endif + +#ifdef QL_OB_DUMP +extern void ql_dump_tx_desc(struct tx_buf_desc *tbd); +extern void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb); +extern void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp); +#define QL_DUMP_OB_MAC_IOCB(ob_mac_iocb) ql_dump_ob_mac_iocb(ob_mac_iocb) +#define QL_DUMP_OB_MAC_RSP(ob_mac_rsp) ql_dump_ob_mac_rsp(ob_mac_rsp) +#else +#define QL_DUMP_OB_MAC_IOCB(ob_mac_iocb) +#define QL_DUMP_OB_MAC_RSP(ob_mac_rsp) +#endif + +#ifdef QL_IB_DUMP +extern void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp); +#define QL_DUMP_IB_MAC_RSP(ib_mac_rsp) ql_dump_ib_mac_rsp(ib_mac_rsp) +#else +#define QL_DUMP_IB_MAC_RSP(ib_mac_rsp) +#endif + +#ifdef QL_ALL_DUMP +extern void ql_dump_all(struct ql_adapter *qdev); +#define QL_DUMP_ALL(qdev) ql_dump_all(qdev) +#else +#define QL_DUMP_ALL(qdev) +#endif + +#endif /* _QLGE_H_ */ diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c new file mode 100644 index 00000000000..47df304a02c --- /dev/null +++ b/drivers/net/qlge/qlge_dbg.c @@ -0,0 +1,858 @@ +#include "qlge.h" + +#ifdef QL_REG_DUMP +static void ql_dump_intr_states(struct ql_adapter *qdev) +{ + int i; + u32 value; + for (i = 0; i < qdev->intr_count; i++) { + ql_write32(qdev, INTR_EN, qdev->intr_context[i].intr_read_mask); + value = ql_read32(qdev, INTR_EN); + printk(KERN_ERR PFX + "%s: Interrupt %d is %s.\n", + qdev->ndev->name, i, + (value & INTR_EN_EN ? "enabled" : "disabled")); + } +} + +void ql_dump_xgmac_control_regs(struct ql_adapter *qdev) +{ + u32 data; + if (ql_sem_spinlock(qdev, qdev->xg_sem_mask)) { + printk(KERN_ERR "%s: Couldn't get xgmac sem.\n", __func__); + return; + } + ql_read_xgmac_reg(qdev, PAUSE_SRC_LO, &data); + printk(KERN_ERR PFX "%s: PAUSE_SRC_LO = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, PAUSE_SRC_HI, &data); + printk(KERN_ERR PFX "%s: PAUSE_SRC_HI = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, GLOBAL_CFG, &data); + printk(KERN_ERR PFX "%s: GLOBAL_CFG = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, TX_CFG, &data); + printk(KERN_ERR PFX "%s: TX_CFG = 0x%.08x.\n", qdev->ndev->name, data); + ql_read_xgmac_reg(qdev, RX_CFG, &data); + printk(KERN_ERR PFX "%s: RX_CFG = 0x%.08x.\n", qdev->ndev->name, data); + ql_read_xgmac_reg(qdev, FLOW_CTL, &data); + printk(KERN_ERR PFX "%s: FLOW_CTL = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, PAUSE_OPCODE, &data); + printk(KERN_ERR PFX "%s: PAUSE_OPCODE = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, PAUSE_TIMER, &data); + printk(KERN_ERR PFX "%s: PAUSE_TIMER = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, PAUSE_FRM_DEST_LO, &data); + printk(KERN_ERR PFX "%s: PAUSE_FRM_DEST_LO = 0x%.08x.\n", + qdev->ndev->name, data); + ql_read_xgmac_reg(qdev, PAUSE_FRM_DEST_HI, &data); + printk(KERN_ERR PFX "%s: PAUSE_FRM_DEST_HI = 0x%.08x.\n", + qdev->ndev->name, data); + ql_read_xgmac_reg(qdev, MAC_TX_PARAMS, &data); + printk(KERN_ERR PFX "%s: MAC_TX_PARAMS = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, MAC_RX_PARAMS, &data); + printk(KERN_ERR PFX "%s: MAC_RX_PARAMS = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, MAC_SYS_INT, &data); + printk(KERN_ERR PFX "%s: MAC_SYS_INT = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, MAC_SYS_INT_MASK, &data); + printk(KERN_ERR PFX "%s: MAC_SYS_INT_MASK = 0x%.08x.\n", + qdev->ndev->name, data); + ql_read_xgmac_reg(qdev, MAC_MGMT_INT, &data); + printk(KERN_ERR PFX "%s: MAC_MGMT_INT = 0x%.08x.\n", qdev->ndev->name, + data); + ql_read_xgmac_reg(qdev, MAC_MGMT_IN_MASK, &data); + printk(KERN_ERR PFX "%s: MAC_MGMT_IN_MASK = 0x%.08x.\n", + qdev->ndev->name, data); + ql_read_xgmac_reg(qdev, EXT_ARB_MODE, &data); + printk(KERN_ERR PFX "%s: EXT_ARB_MODE = 0x%.08x.\n", qdev->ndev->name, + data); + ql_sem_unlock(qdev, qdev->xg_sem_mask); + +} + +static void ql_dump_ets_regs(struct ql_adapter *qdev) +{ +} + +static void ql_dump_cam_entries(struct ql_adapter *qdev) +{ + int i; + u32 value[3]; + for (i = 0; i < 4; i++) { + if (ql_get_mac_addr_reg(qdev, MAC_ADDR_TYPE_CAM_MAC, i, value)) { + printk(KERN_ERR PFX + "%s: Failed read of mac index register.\n", + __func__); + return; + } else { + if (value[0]) + printk(KERN_ERR PFX + "%s: CAM index %d CAM Lookup Lower = 0x%.08x:%.08x, Output = 0x%.08x.\n", + qdev->ndev->name, i, value[1], value[0], + value[2]); + } + } + for (i = 0; i < 32; i++) { + if (ql_get_mac_addr_reg + (qdev, MAC_ADDR_TYPE_MULTI_MAC, i, value)) { + printk(KERN_ERR PFX + "%s: Failed read of mac index register.\n", + __func__); + return; + } else { + if (value[0]) + printk(KERN_ERR PFX + "%s: MCAST index %d CAM Lookup Lower = 0x%.08x:%.08x.\n", + qdev->ndev->name, i, value[1], value[0]); + } + } +} + +void ql_dump_routing_entries(struct ql_adapter *qdev) +{ + int i; + u32 value; + for (i = 0; i < 16; i++) { + value = 0; + if (ql_get_routing_reg(qdev, i, &value)) { + printk(KERN_ERR PFX + "%s: Failed read of routing index register.\n", + __func__); + return; + } else { + if (value) + printk(KERN_ERR PFX + "%s: Routing Mask %d = 0x%.08x.\n", + qdev->ndev->name, i, value); + } + } +} + +void ql_dump_regs(struct ql_adapter *qdev) +{ + printk(KERN_ERR PFX "reg dump for function #%d.\n", qdev->func); + printk(KERN_ERR PFX "SYS = 0x%x.\n", + ql_read32(qdev, SYS)); + printk(KERN_ERR PFX "RST_FO = 0x%x.\n", + ql_read32(qdev, RST_FO)); + printk(KERN_ERR PFX "FSC = 0x%x.\n", + ql_read32(qdev, FSC)); + printk(KERN_ERR PFX "CSR = 0x%x.\n", + ql_read32(qdev, CSR)); + printk(KERN_ERR PFX "ICB_RID = 0x%x.\n", + ql_read32(qdev, ICB_RID)); + printk(KERN_ERR PFX "ICB_L = 0x%x.\n", + ql_read32(qdev, ICB_L)); + printk(KERN_ERR PFX "ICB_H = 0x%x.\n", + ql_read32(qdev, ICB_H)); + printk(KERN_ERR PFX "CFG = 0x%x.\n", + ql_read32(qdev, CFG)); + printk(KERN_ERR PFX "BIOS_ADDR = 0x%x.\n", + ql_read32(qdev, BIOS_ADDR)); + printk(KERN_ERR PFX "STS = 0x%x.\n", + ql_read32(qdev, STS)); + printk(KERN_ERR PFX "INTR_EN = 0x%x.\n", + ql_read32(qdev, INTR_EN)); + printk(KERN_ERR PFX "INTR_MASK = 0x%x.\n", + ql_read32(qdev, INTR_MASK)); + printk(KERN_ERR PFX "ISR1 = 0x%x.\n", + ql_read32(qdev, ISR1)); + printk(KERN_ERR PFX "ISR2 = 0x%x.\n", + ql_read32(qdev, ISR2)); + printk(KERN_ERR PFX "ISR3 = 0x%x.\n", + ql_read32(qdev, ISR3)); + printk(KERN_ERR PFX "ISR4 = 0x%x.\n", + ql_read32(qdev, ISR4)); + printk(KERN_ERR PFX "REV_ID = 0x%x.\n", + ql_read32(qdev, REV_ID)); + printk(KERN_ERR PFX "FRC_ECC_ERR = 0x%x.\n", + ql_read32(qdev, FRC_ECC_ERR)); + printk(KERN_ERR PFX "ERR_STS = 0x%x.\n", + ql_read32(qdev, ERR_STS)); + printk(KERN_ERR PFX "RAM_DBG_ADDR = 0x%x.\n", + ql_read32(qdev, RAM_DBG_ADDR)); + printk(KERN_ERR PFX "RAM_DBG_DATA = 0x%x.\n", + ql_read32(qdev, RAM_DBG_DATA)); + printk(KERN_ERR PFX "ECC_ERR_CNT = 0x%x.\n", + ql_read32(qdev, ECC_ERR_CNT)); + printk(KERN_ERR PFX "SEM = 0x%x.\n", + ql_read32(qdev, SEM)); + printk(KERN_ERR PFX "GPIO_1 = 0x%x.\n", + ql_read32(qdev, GPIO_1)); + printk(KERN_ERR PFX "GPIO_2 = 0x%x.\n", + ql_read32(qdev, GPIO_2)); + printk(KERN_ERR PFX "GPIO_3 = 0x%x.\n", + ql_read32(qdev, GPIO_3)); + printk(KERN_ERR PFX "XGMAC_ADDR = 0x%x.\n", + ql_read32(qdev, XGMAC_ADDR)); + printk(KERN_ERR PFX "XGMAC_DATA = 0x%x.\n", + ql_read32(qdev, XGMAC_DATA)); + printk(KERN_ERR PFX "NIC_ETS = 0x%x.\n", + ql_read32(qdev, NIC_ETS)); + printk(KERN_ERR PFX "CNA_ETS = 0x%x.\n", + ql_read32(qdev, CNA_ETS)); + printk(KERN_ERR PFX "FLASH_ADDR = 0x%x.\n", + ql_read32(qdev, FLASH_ADDR)); + printk(KERN_ERR PFX "FLASH_DATA = 0x%x.\n", + ql_read32(qdev, FLASH_DATA)); + printk(KERN_ERR PFX "CQ_STOP = 0x%x.\n", + ql_read32(qdev, CQ_STOP)); + printk(KERN_ERR PFX "PAGE_TBL_RID = 0x%x.\n", + ql_read32(qdev, PAGE_TBL_RID)); + printk(KERN_ERR PFX "WQ_PAGE_TBL_LO = 0x%x.\n", + ql_read32(qdev, WQ_PAGE_TBL_LO)); + printk(KERN_ERR PFX "WQ_PAGE_TBL_HI = 0x%x.\n", + ql_read32(qdev, WQ_PAGE_TBL_HI)); + printk(KERN_ERR PFX "CQ_PAGE_TBL_LO = 0x%x.\n", + ql_read32(qdev, CQ_PAGE_TBL_LO)); + printk(KERN_ERR PFX "CQ_PAGE_TBL_HI = 0x%x.\n", + ql_read32(qdev, CQ_PAGE_TBL_HI)); + printk(KERN_ERR PFX "COS_DFLT_CQ1 = 0x%x.\n", + ql_read32(qdev, COS_DFLT_CQ1)); + printk(KERN_ERR PFX "COS_DFLT_CQ2 = 0x%x.\n", + ql_read32(qdev, COS_DFLT_CQ2)); + printk(KERN_ERR PFX "SPLT_HDR = 0x%x.\n", + ql_read32(qdev, SPLT_HDR)); + printk(KERN_ERR PFX "FC_PAUSE_THRES = 0x%x.\n", + ql_read32(qdev, FC_PAUSE_THRES)); + printk(KERN_ERR PFX "NIC_PAUSE_THRES = 0x%x.\n", + ql_read32(qdev, NIC_PAUSE_THRES)); + printk(KERN_ERR PFX "FC_ETHERTYPE = 0x%x.\n", + ql_read32(qdev, FC_ETHERTYPE)); + printk(KERN_ERR PFX "FC_RCV_CFG = 0x%x.\n", + ql_read32(qdev, FC_RCV_CFG)); + printk(KERN_ERR PFX "NIC_RCV_CFG = 0x%x.\n", + ql_read32(qdev, NIC_RCV_CFG)); + printk(KERN_ERR PFX "FC_COS_TAGS = 0x%x.\n", + ql_read32(qdev, FC_COS_TAGS)); + printk(KERN_ERR PFX "NIC_COS_TAGS = 0x%x.\n", + ql_read32(qdev, NIC_COS_TAGS)); + printk(KERN_ERR PFX "MGMT_RCV_CFG = 0x%x.\n", + ql_read32(qdev, MGMT_RCV_CFG)); + printk(KERN_ERR PFX "XG_SERDES_ADDR = 0x%x.\n", + ql_read32(qdev, XG_SERDES_ADDR)); + printk(KERN_ERR PFX "XG_SERDES_DATA = 0x%x.\n", + ql_read32(qdev, XG_SERDES_DATA)); + printk(KERN_ERR PFX "PRB_MX_ADDR = 0x%x.\n", + ql_read32(qdev, PRB_MX_ADDR)); + printk(KERN_ERR PFX "PRB_MX_DATA = 0x%x.\n", + ql_read32(qdev, PRB_MX_DATA)); + ql_dump_intr_states(qdev); + ql_dump_xgmac_control_regs(qdev); + ql_dump_ets_regs(qdev); + ql_dump_cam_entries(qdev); + ql_dump_routing_entries(qdev); +} +#endif + +#ifdef QL_STAT_DUMP +void ql_dump_stat(struct ql_adapter *qdev) +{ + printk(KERN_ERR "%s: Enter.\n", __func__); + printk(KERN_ERR "tx_pkts = %ld\n", + (unsigned long)qdev->nic_stats.tx_pkts); + printk(KERN_ERR "tx_bytes = %ld\n", + (unsigned long)qdev->nic_stats.tx_bytes); + printk(KERN_ERR "tx_mcast_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.tx_mcast_pkts); + printk(KERN_ERR "tx_bcast_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.tx_bcast_pkts); + printk(KERN_ERR "tx_ucast_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.tx_ucast_pkts); + printk(KERN_ERR "tx_ctl_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.tx_ctl_pkts); + printk(KERN_ERR "tx_pause_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.tx_pause_pkts); + printk(KERN_ERR "tx_64_pkt = %ld.\n", + (unsigned long)qdev->nic_stats.tx_64_pkt); + printk(KERN_ERR "tx_65_to_127_pkt = %ld.\n", + (unsigned long)qdev->nic_stats.tx_65_to_127_pkt); + printk(KERN_ERR "tx_128_to_255_pkt = %ld.\n", + (unsigned long)qdev->nic_stats.tx_128_to_255_pkt); + printk(KERN_ERR "tx_256_511_pkt = %ld.\n", + (unsigned long)qdev->nic_stats.tx_256_511_pkt); + printk(KERN_ERR "tx_512_to_1023_pkt = %ld.\n", + (unsigned long)qdev->nic_stats.tx_512_to_1023_pkt); + printk(KERN_ERR "tx_1024_to_1518_pkt = %ld.\n", + (unsigned long)qdev->nic_stats.tx_1024_to_1518_pkt); + printk(KERN_ERR "tx_1519_to_max_pkt = %ld.\n", + (unsigned long)qdev->nic_stats.tx_1519_to_max_pkt); + printk(KERN_ERR "tx_undersize_pkt = %ld.\n", + (unsigned long)qdev->nic_stats.tx_undersize_pkt); + printk(KERN_ERR "tx_oversize_pkt = %ld.\n", + (unsigned long)qdev->nic_stats.tx_oversize_pkt); + printk(KERN_ERR "rx_bytes = %ld.\n", + (unsigned long)qdev->nic_stats.rx_bytes); + printk(KERN_ERR "rx_bytes_ok = %ld.\n", + (unsigned long)qdev->nic_stats.rx_bytes_ok); + printk(KERN_ERR "rx_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_pkts); + printk(KERN_ERR "rx_pkts_ok = %ld.\n", + (unsigned long)qdev->nic_stats.rx_pkts_ok); + printk(KERN_ERR "rx_bcast_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_bcast_pkts); + printk(KERN_ERR "rx_mcast_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_mcast_pkts); + printk(KERN_ERR "rx_ucast_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_ucast_pkts); + printk(KERN_ERR "rx_undersize_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_undersize_pkts); + printk(KERN_ERR "rx_oversize_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_oversize_pkts); + printk(KERN_ERR "rx_jabber_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_jabber_pkts); + printk(KERN_ERR "rx_undersize_fcerr_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_undersize_fcerr_pkts); + printk(KERN_ERR "rx_drop_events = %ld.\n", + (unsigned long)qdev->nic_stats.rx_drop_events); + printk(KERN_ERR "rx_fcerr_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_fcerr_pkts); + printk(KERN_ERR "rx_align_err = %ld.\n", + (unsigned long)qdev->nic_stats.rx_align_err); + printk(KERN_ERR "rx_symbol_err = %ld.\n", + (unsigned long)qdev->nic_stats.rx_symbol_err); + printk(KERN_ERR "rx_mac_err = %ld.\n", + (unsigned long)qdev->nic_stats.rx_mac_err); + printk(KERN_ERR "rx_ctl_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_ctl_pkts); + printk(KERN_ERR "rx_pause_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_pause_pkts); + printk(KERN_ERR "rx_64_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_64_pkts); + printk(KERN_ERR "rx_65_to_127_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_65_to_127_pkts); + printk(KERN_ERR "rx_128_255_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_128_255_pkts); + printk(KERN_ERR "rx_256_511_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_256_511_pkts); + printk(KERN_ERR "rx_512_to_1023_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_512_to_1023_pkts); + printk(KERN_ERR "rx_1024_to_1518_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_1024_to_1518_pkts); + printk(KERN_ERR "rx_1519_to_max_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_1519_to_max_pkts); + printk(KERN_ERR "rx_len_err_pkts = %ld.\n", + (unsigned long)qdev->nic_stats.rx_len_err_pkts); +}; +#endif + +#ifdef QL_DEV_DUMP +void ql_dump_qdev(struct ql_adapter *qdev) +{ + int i; + printk(KERN_ERR PFX "qdev->flags = %lx.\n", + qdev->flags); + printk(KERN_ERR PFX "qdev->vlgrp = %p.\n", + qdev->vlgrp); + printk(KERN_ERR PFX "qdev->pdev = %p.\n", + qdev->pdev); + printk(KERN_ERR PFX "qdev->ndev = %p.\n", + qdev->ndev); + printk(KERN_ERR PFX "qdev->chip_rev_id = %d.\n", + qdev->chip_rev_id); + printk(KERN_ERR PFX "qdev->reg_base = %p.\n", + qdev->reg_base); + printk(KERN_ERR PFX "qdev->doorbell_area = %p.\n", + qdev->doorbell_area); + printk(KERN_ERR PFX "qdev->doorbell_area_size = %d.\n", + qdev->doorbell_area_size); + printk(KERN_ERR PFX "msg_enable = %x.\n", + qdev->msg_enable); + printk(KERN_ERR PFX "qdev->rx_ring_shadow_reg_area = %p.\n", + qdev->rx_ring_shadow_reg_area); + printk(KERN_ERR PFX "qdev->rx_ring_shadow_reg_dma = %llx.\n", + (unsigned long long) qdev->rx_ring_shadow_reg_dma); + printk(KERN_ERR PFX "qdev->tx_ring_shadow_reg_area = %p.\n", + qdev->tx_ring_shadow_reg_area); + printk(KERN_ERR PFX "qdev->tx_ring_shadow_reg_dma = %llx.\n", + (unsigned long long) qdev->tx_ring_shadow_reg_dma); + printk(KERN_ERR PFX "qdev->intr_count = %d.\n", + qdev->intr_count); + if (qdev->msi_x_entry) + for (i = 0; i < qdev->intr_count; i++) { + printk(KERN_ERR PFX + "msi_x_entry.[%d]vector = %d.\n", i, + qdev->msi_x_entry[i].vector); + printk(KERN_ERR PFX + "msi_x_entry.[%d]entry = %d.\n", i, + qdev->msi_x_entry[i].entry); + } + for (i = 0; i < qdev->intr_count; i++) { + printk(KERN_ERR PFX + "intr_context[%d].qdev = %p.\n", i, + qdev->intr_context[i].qdev); + printk(KERN_ERR PFX + "intr_context[%d].intr = %d.\n", i, + qdev->intr_context[i].intr); + printk(KERN_ERR PFX + "intr_context[%d].hooked = %d.\n", i, + qdev->intr_context[i].hooked); + printk(KERN_ERR PFX + "intr_context[%d].intr_en_mask = 0x%08x.\n", i, + qdev->intr_context[i].intr_en_mask); + printk(KERN_ERR PFX + "intr_context[%d].intr_dis_mask = 0x%08x.\n", i, + qdev->intr_context[i].intr_dis_mask); + printk(KERN_ERR PFX + "intr_context[%d].intr_read_mask = 0x%08x.\n", i, + qdev->intr_context[i].intr_read_mask); + } + printk(KERN_ERR PFX "qdev->tx_ring_count = %d.\n", qdev->tx_ring_count); + printk(KERN_ERR PFX "qdev->rx_ring_count = %d.\n", qdev->rx_ring_count); + printk(KERN_ERR PFX "qdev->ring_mem_size = %d.\n", qdev->ring_mem_size); + printk(KERN_ERR PFX "qdev->ring_mem = %p.\n", qdev->ring_mem); + printk(KERN_ERR PFX "qdev->intr_count = %d.\n", qdev->intr_count); + printk(KERN_ERR PFX "qdev->tx_ring = %p.\n", + qdev->tx_ring); + printk(KERN_ERR PFX "qdev->rss_ring_first_cq_id = %d.\n", + qdev->rss_ring_first_cq_id); + printk(KERN_ERR PFX "qdev->rss_ring_count = %d.\n", + qdev->rss_ring_count); + printk(KERN_ERR PFX "qdev->rx_ring = %p.\n", qdev->rx_ring); + printk(KERN_ERR PFX "qdev->default_rx_queue = %d.\n", + qdev->default_rx_queue); + printk(KERN_ERR PFX "qdev->xg_sem_mask = 0x%08x.\n", + qdev->xg_sem_mask); + printk(KERN_ERR PFX "qdev->port_link_up = 0x%08x.\n", + qdev->port_link_up); + printk(KERN_ERR PFX "qdev->port_init = 0x%08x.\n", + qdev->port_init); + +} +#endif + +#ifdef QL_CB_DUMP +void ql_dump_wqicb(struct wqicb *wqicb) +{ + printk(KERN_ERR PFX "Dumping wqicb stuff...\n"); + printk(KERN_ERR PFX "wqicb->len = 0x%x.\n", le16_to_cpu(wqicb->len)); + printk(KERN_ERR PFX "wqicb->flags = %x.\n", le16_to_cpu(wqicb->flags)); + printk(KERN_ERR PFX "wqicb->cq_id_rss = %d.\n", + le16_to_cpu(wqicb->cq_id_rss)); + printk(KERN_ERR PFX "wqicb->rid = 0x%x.\n", le16_to_cpu(wqicb->rid)); + printk(KERN_ERR PFX "wqicb->wq_addr_lo = 0x%.08x.\n", + le32_to_cpu(wqicb->addr_lo)); + printk(KERN_ERR PFX "wqicb->wq_addr_hi = 0x%.08x.\n", + le32_to_cpu(wqicb->addr_hi)); + printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr_lo = 0x%.08x.\n", + le32_to_cpu(wqicb->cnsmr_idx_addr_lo)); + printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr_hi = 0x%.08x.\n", + le32_to_cpu(wqicb->cnsmr_idx_addr_hi)); +} + +void ql_dump_tx_ring(struct tx_ring *tx_ring) +{ + if (tx_ring == NULL) + return; + printk(KERN_ERR PFX + "===================== Dumping tx_ring %d ===============.\n", + tx_ring->wq_id); + printk(KERN_ERR PFX "tx_ring->base = %p.\n", tx_ring->wq_base); + printk(KERN_ERR PFX "tx_ring->base_dma = 0x%llx.\n", + (unsigned long long) tx_ring->wq_base_dma); + printk(KERN_ERR PFX "tx_ring->cnsmr_idx_sh_reg = %p.\n", + tx_ring->cnsmr_idx_sh_reg); + printk(KERN_ERR PFX "tx_ring->cnsmr_idx_sh_reg_dma = 0x%llx.\n", + (unsigned long long) tx_ring->cnsmr_idx_sh_reg_dma); + printk(KERN_ERR PFX "tx_ring->size = %d.\n", tx_ring->wq_size); + printk(KERN_ERR PFX "tx_ring->len = %d.\n", tx_ring->wq_len); + printk(KERN_ERR PFX "tx_ring->prod_idx_db_reg = %p.\n", + tx_ring->prod_idx_db_reg); + printk(KERN_ERR PFX "tx_ring->valid_db_reg = %p.\n", + tx_ring->valid_db_reg); + printk(KERN_ERR PFX "tx_ring->prod_idx = %d.\n", tx_ring->prod_idx); + printk(KERN_ERR PFX "tx_ring->cq_id = %d.\n", tx_ring->cq_id); + printk(KERN_ERR PFX "tx_ring->wq_id = %d.\n", tx_ring->wq_id); + printk(KERN_ERR PFX "tx_ring->q = %p.\n", tx_ring->q); + printk(KERN_ERR PFX "tx_ring->tx_count = %d.\n", + atomic_read(&tx_ring->tx_count)); +} + +void ql_dump_ricb(struct ricb *ricb) +{ + int i; + printk(KERN_ERR PFX + "===================== Dumping ricb ===============.\n"); + printk(KERN_ERR PFX "Dumping ricb stuff...\n"); + + printk(KERN_ERR PFX "ricb->base_cq = %d.\n", ricb->base_cq & 0x1f); + printk(KERN_ERR PFX "ricb->flags = %s%s%s%s%s%s%s%s%s.\n", + ricb->base_cq & RSS_L4K ? "RSS_L4K " : "", + ricb->flags & RSS_L6K ? "RSS_L6K " : "", + ricb->flags & RSS_LI ? "RSS_LI " : "", + ricb->flags & RSS_LB ? "RSS_LB " : "", + ricb->flags & RSS_LM ? "RSS_LM " : "", + ricb->flags & RSS_RI4 ? "RSS_RI4 " : "", + ricb->flags & RSS_RT4 ? "RSS_RT4 " : "", + ricb->flags & RSS_RI6 ? "RSS_RI6 " : "", + ricb->flags & RSS_RT6 ? "RSS_RT6 " : ""); + printk(KERN_ERR PFX "ricb->mask = 0x%.04x.\n", le16_to_cpu(ricb->mask)); + for (i = 0; i < 16; i++) + printk(KERN_ERR PFX "ricb->hash_cq_id[%d] = 0x%.08x.\n", i, + le32_to_cpu(ricb->hash_cq_id[i])); + for (i = 0; i < 10; i++) + printk(KERN_ERR PFX "ricb->ipv6_hash_key[%d] = 0x%.08x.\n", i, + le32_to_cpu(ricb->ipv6_hash_key[i])); + for (i = 0; i < 4; i++) + printk(KERN_ERR PFX "ricb->ipv4_hash_key[%d] = 0x%.08x.\n", i, + le32_to_cpu(ricb->ipv4_hash_key[i])); +} + +void ql_dump_cqicb(struct cqicb *cqicb) +{ + printk(KERN_ERR PFX "Dumping cqicb stuff...\n"); + + printk(KERN_ERR PFX "cqicb->msix_vect = %d.\n", cqicb->msix_vect); + printk(KERN_ERR PFX "cqicb->flags = %x.\n", cqicb->flags); + printk(KERN_ERR PFX "cqicb->len = %d.\n", le16_to_cpu(cqicb->len)); + printk(KERN_ERR PFX "cqicb->addr_lo = %x.\n", + le32_to_cpu(cqicb->addr_lo)); + printk(KERN_ERR PFX "cqicb->addr_hi = %x.\n", + le32_to_cpu(cqicb->addr_hi)); + printk(KERN_ERR PFX "cqicb->prod_idx_addr_lo = %x.\n", + le32_to_cpu(cqicb->prod_idx_addr_lo)); + printk(KERN_ERR PFX "cqicb->prod_idx_addr_hi = %x.\n", + le32_to_cpu(cqicb->prod_idx_addr_hi)); + printk(KERN_ERR PFX "cqicb->pkt_delay = 0x%.04x.\n", + le16_to_cpu(cqicb->pkt_delay)); + printk(KERN_ERR PFX "cqicb->irq_delay = 0x%.04x.\n", + le16_to_cpu(cqicb->irq_delay)); + printk(KERN_ERR PFX "cqicb->lbq_addr_lo = %x.\n", + le32_to_cpu(cqicb->lbq_addr_lo)); + printk(KERN_ERR PFX "cqicb->lbq_addr_hi = %x.\n", + le32_to_cpu(cqicb->lbq_addr_hi)); + printk(KERN_ERR PFX "cqicb->lbq_buf_size = 0x%.04x.\n", + le16_to_cpu(cqicb->lbq_buf_size)); + printk(KERN_ERR PFX "cqicb->lbq_len = 0x%.04x.\n", + le16_to_cpu(cqicb->lbq_len)); + printk(KERN_ERR PFX "cqicb->sbq_addr_lo = %x.\n", + le32_to_cpu(cqicb->sbq_addr_lo)); + printk(KERN_ERR PFX "cqicb->sbq_addr_hi = %x.\n", + le32_to_cpu(cqicb->sbq_addr_hi)); + printk(KERN_ERR PFX "cqicb->sbq_buf_size = 0x%.04x.\n", + le16_to_cpu(cqicb->sbq_buf_size)); + printk(KERN_ERR PFX "cqicb->sbq_len = 0x%.04x.\n", + le16_to_cpu(cqicb->sbq_len)); +} + +void ql_dump_rx_ring(struct rx_ring *rx_ring) +{ + if (rx_ring == NULL) + return; + printk(KERN_ERR PFX + "===================== Dumping rx_ring %d ===============.\n", + rx_ring->cq_id); + printk(KERN_ERR PFX "Dumping rx_ring %d, type = %s%s%s.\n", + rx_ring->cq_id, rx_ring->type == DEFAULT_Q ? "DEFAULT" : "", + rx_ring->type == TX_Q ? "OUTBOUND COMPLETIONS" : "", + rx_ring->type == RX_Q ? "INBOUND_COMPLETIONS" : ""); + printk(KERN_ERR PFX "rx_ring->cqicb = %p.\n", &rx_ring->cqicb); + printk(KERN_ERR PFX "rx_ring->cq_base = %p.\n", rx_ring->cq_base); + printk(KERN_ERR PFX "rx_ring->cq_base_dma = %llx.\n", + (unsigned long long) rx_ring->cq_base_dma); + printk(KERN_ERR PFX "rx_ring->cq_size = %d.\n", rx_ring->cq_size); + printk(KERN_ERR PFX "rx_ring->cq_len = %d.\n", rx_ring->cq_len); + printk(KERN_ERR PFX + "rx_ring->prod_idx_sh_reg, addr = %p, value = %d.\n", + rx_ring->prod_idx_sh_reg, + rx_ring->prod_idx_sh_reg ? *(rx_ring->prod_idx_sh_reg) : 0); + printk(KERN_ERR PFX "rx_ring->prod_idx_sh_reg_dma = %llx.\n", + (unsigned long long) rx_ring->prod_idx_sh_reg_dma); + printk(KERN_ERR PFX "rx_ring->cnsmr_idx_db_reg = %p.\n", + rx_ring->cnsmr_idx_db_reg); + printk(KERN_ERR PFX "rx_ring->cnsmr_idx = %d.\n", rx_ring->cnsmr_idx); + printk(KERN_ERR PFX "rx_ring->curr_entry = %p.\n", rx_ring->curr_entry); + printk(KERN_ERR PFX "rx_ring->valid_db_reg = %p.\n", + rx_ring->valid_db_reg); + + printk(KERN_ERR PFX "rx_ring->lbq_base = %p.\n", rx_ring->lbq_base); + printk(KERN_ERR PFX "rx_ring->lbq_base_dma = %llx.\n", + (unsigned long long) rx_ring->lbq_base_dma); + printk(KERN_ERR PFX "rx_ring->lbq_base_indirect = %p.\n", + rx_ring->lbq_base_indirect); + printk(KERN_ERR PFX "rx_ring->lbq_base_indirect_dma = %llx.\n", + (unsigned long long) rx_ring->lbq_base_indirect_dma); + printk(KERN_ERR PFX "rx_ring->lbq = %p.\n", rx_ring->lbq); + printk(KERN_ERR PFX "rx_ring->lbq_len = %d.\n", rx_ring->lbq_len); + printk(KERN_ERR PFX "rx_ring->lbq_size = %d.\n", rx_ring->lbq_size); + printk(KERN_ERR PFX "rx_ring->lbq_prod_idx_db_reg = %p.\n", + rx_ring->lbq_prod_idx_db_reg); + printk(KERN_ERR PFX "rx_ring->lbq_prod_idx = %d.\n", + rx_ring->lbq_prod_idx); + printk(KERN_ERR PFX "rx_ring->lbq_curr_idx = %d.\n", + rx_ring->lbq_curr_idx); + printk(KERN_ERR PFX "rx_ring->lbq_clean_idx = %d.\n", + rx_ring->lbq_clean_idx); + printk(KERN_ERR PFX "rx_ring->lbq_free_cnt = %d.\n", + rx_ring->lbq_free_cnt); + printk(KERN_ERR PFX "rx_ring->lbq_buf_size = %d.\n", + rx_ring->lbq_buf_size); + + printk(KERN_ERR PFX "rx_ring->sbq_base = %p.\n", rx_ring->sbq_base); + printk(KERN_ERR PFX "rx_ring->sbq_base_dma = %llx.\n", + (unsigned long long) rx_ring->sbq_base_dma); + printk(KERN_ERR PFX "rx_ring->sbq_base_indirect = %p.\n", + rx_ring->sbq_base_indirect); + printk(KERN_ERR PFX "rx_ring->sbq_base_indirect_dma = %llx.\n", + (unsigned long long) rx_ring->sbq_base_indirect_dma); + printk(KERN_ERR PFX "rx_ring->sbq = %p.\n", rx_ring->sbq); + printk(KERN_ERR PFX "rx_ring->sbq_len = %d.\n", rx_ring->sbq_len); + printk(KERN_ERR PFX "rx_ring->sbq_size = %d.\n", rx_ring->sbq_size); + printk(KERN_ERR PFX "rx_ring->sbq_prod_idx_db_reg addr = %p.\n", + rx_ring->sbq_prod_idx_db_reg); + printk(KERN_ERR PFX "rx_ring->sbq_prod_idx = %d.\n", + rx_ring->sbq_prod_idx); + printk(KERN_ERR PFX "rx_ring->sbq_curr_idx = %d.\n", + rx_ring->sbq_curr_idx); + printk(KERN_ERR PFX "rx_ring->sbq_clean_idx = %d.\n", + rx_ring->sbq_clean_idx); + printk(KERN_ERR PFX "rx_ring->sbq_free_cnt = %d.\n", + rx_ring->sbq_free_cnt); + printk(KERN_ERR PFX "rx_ring->sbq_buf_size = %d.\n", + rx_ring->sbq_buf_size); + printk(KERN_ERR PFX "rx_ring->cq_id = %d.\n", rx_ring->cq_id); + printk(KERN_ERR PFX "rx_ring->irq = %d.\n", rx_ring->irq); + printk(KERN_ERR PFX "rx_ring->cpu = %d.\n", rx_ring->cpu); + printk(KERN_ERR PFX "rx_ring->qdev = %p.\n", rx_ring->qdev); +} + +void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id) +{ + void *ptr; + + printk(KERN_ERR PFX "%s: Enter.\n", __func__); + + ptr = kmalloc(size, GFP_ATOMIC); + if (ptr == NULL) { + printk(KERN_ERR PFX "%s: Couldn't allocate a buffer.\n", + __func__); + return; + } + + if (ql_write_cfg(qdev, ptr, size, bit, q_id)) { + printk(KERN_ERR "%s: Failed to upload control block!\n", + __func__); + goto fail_it; + } + switch (bit) { + case CFG_DRQ: + ql_dump_wqicb((struct wqicb *)ptr); + break; + case CFG_DCQ: + ql_dump_cqicb((struct cqicb *)ptr); + break; + case CFG_DR: + ql_dump_ricb((struct ricb *)ptr); + break; + default: + printk(KERN_ERR PFX "%s: Invalid bit value = %x.\n", + __func__, bit); + break; + } +fail_it: + kfree(ptr); +} +#endif + +#ifdef QL_OB_DUMP +void ql_dump_tx_desc(struct tx_buf_desc *tbd) +{ + printk(KERN_ERR PFX "tbd->addr = 0x%llx\n", + le64_to_cpu((u64) tbd->addr)); + printk(KERN_ERR PFX "tbd->len = %d\n", + le32_to_cpu(tbd->len & TX_DESC_LEN_MASK)); + printk(KERN_ERR PFX "tbd->flags = %s %s\n", + tbd->len & TX_DESC_C ? "C" : ".", + tbd->len & TX_DESC_E ? "E" : "."); + tbd++; + printk(KERN_ERR PFX "tbd->addr = 0x%llx\n", + le64_to_cpu((u64) tbd->addr)); + printk(KERN_ERR PFX "tbd->len = %d\n", + le32_to_cpu(tbd->len & TX_DESC_LEN_MASK)); + printk(KERN_ERR PFX "tbd->flags = %s %s\n", + tbd->len & TX_DESC_C ? "C" : ".", + tbd->len & TX_DESC_E ? "E" : "."); + tbd++; + printk(KERN_ERR PFX "tbd->addr = 0x%llx\n", + le64_to_cpu((u64) tbd->addr)); + printk(KERN_ERR PFX "tbd->len = %d\n", + le32_to_cpu(tbd->len & TX_DESC_LEN_MASK)); + printk(KERN_ERR PFX "tbd->flags = %s %s\n", + tbd->len & TX_DESC_C ? "C" : ".", + tbd->len & TX_DESC_E ? "E" : "."); + +} + +void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb) +{ + struct ob_mac_tso_iocb_req *ob_mac_tso_iocb = + (struct ob_mac_tso_iocb_req *)ob_mac_iocb; + struct tx_buf_desc *tbd; + u16 frame_len; + + printk(KERN_ERR PFX "%s\n", __func__); + printk(KERN_ERR PFX "opcode = %s\n", + (ob_mac_iocb->opcode == OPCODE_OB_MAC_IOCB) ? "MAC" : "TSO"); + printk(KERN_ERR PFX "flags1 = %s %s %s %s %s\n", + ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_OI ? "OI" : "", + ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_I ? "I" : "", + ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_D ? "D" : "", + ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_IP4 ? "IP4" : "", + ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_IP6 ? "IP6" : ""); + printk(KERN_ERR PFX "flags2 = %s %s %s\n", + ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_LSO ? "LSO" : "", + ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_UC ? "UC" : "", + ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_TC ? "TC" : ""); + printk(KERN_ERR PFX "flags3 = %s %s %s \n", + ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_IC ? "IC" : "", + ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_DFP ? "DFP" : "", + ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_V ? "V" : ""); + printk(KERN_ERR PFX "tid = %x\n", ob_mac_iocb->tid); + printk(KERN_ERR PFX "txq_idx = %d\n", ob_mac_iocb->txq_idx); + printk(KERN_ERR PFX "vlan_tci = %x\n", ob_mac_tso_iocb->vlan_tci); + if (ob_mac_iocb->opcode == OPCODE_OB_MAC_TSO_IOCB) { + printk(KERN_ERR PFX "frame_len = %d\n", + le32_to_cpu(ob_mac_tso_iocb->frame_len)); + printk(KERN_ERR PFX "mss = %d\n", + le16_to_cpu(ob_mac_tso_iocb->mss)); + printk(KERN_ERR PFX "prot_hdr_len = %d\n", + le16_to_cpu(ob_mac_tso_iocb->total_hdrs_len)); + printk(KERN_ERR PFX "hdr_offset = 0x%.04x\n", + le16_to_cpu(ob_mac_tso_iocb->net_trans_offset)); + frame_len = le32_to_cpu(ob_mac_tso_iocb->frame_len); + } else { + printk(KERN_ERR PFX "frame_len = %d\n", + le16_to_cpu(ob_mac_iocb->frame_len)); + frame_len = le16_to_cpu(ob_mac_iocb->frame_len); + } + tbd = &ob_mac_iocb->tbd[0]; + ql_dump_tx_desc(tbd); +} + +void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp) +{ + printk(KERN_ERR PFX "%s\n", __func__); + printk(KERN_ERR PFX "opcode = %d\n", ob_mac_rsp->opcode); + printk(KERN_ERR PFX "flags = %s %s %s %s %s %s %s\n", + ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_OI ? "OI" : ".", + ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_I ? "I" : ".", + ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_E ? "E" : ".", + ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_S ? "S" : ".", + ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_L ? "L" : ".", + ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_P ? "P" : ".", + ob_mac_rsp->flags2 & OB_MAC_IOCB_RSP_B ? "B" : "."); + printk(KERN_ERR PFX "tid = %x\n", ob_mac_rsp->tid); +} +#endif + +#ifdef QL_IB_DUMP +void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp) +{ + printk(KERN_ERR PFX "%s\n", __func__); + printk(KERN_ERR PFX "opcode = 0x%x\n", ib_mac_rsp->opcode); + printk(KERN_ERR PFX "flags1 = %s%s%s%s%s%s\n", + ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_OI ? "OI " : "", + ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_I ? "I " : "", + ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_TE ? "TE " : "", + ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_NU ? "NU " : "", + ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_IE ? "IE " : "", + ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_B ? "B " : ""); + + if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) + printk(KERN_ERR PFX "%s%s%s Multicast.\n", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_REG ? "Registered" : "", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : ""); + + printk(KERN_ERR PFX "flags2 = %s%s%s%s%s\n", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) ? "P " : "", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? "V " : "", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) ? "U " : "", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) ? "T " : "", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_FO) ? "FO " : ""); + + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) + printk(KERN_ERR PFX "%s%s%s%s%s error.\n", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) == + IB_MAC_IOCB_RSP_ERR_OVERSIZE ? "oversize" : "", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) == + IB_MAC_IOCB_RSP_ERR_UNDERSIZE ? "undersize" : "", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) == + IB_MAC_IOCB_RSP_ERR_PREAMBLE ? "preamble" : "", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) == + IB_MAC_IOCB_RSP_ERR_FRAME_LEN ? "frame length" : "", + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) == + IB_MAC_IOCB_RSP_ERR_CRC ? "CRC" : ""); + + printk(KERN_ERR PFX "flags3 = %s%s.\n", + ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS ? "DS " : "", + ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL ? "DL " : ""); + + if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) + printk(KERN_ERR PFX "RSS flags = %s%s%s%s.\n", + ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) == + IB_MAC_IOCB_RSP_M_IPV4) ? "IPv4 RSS" : "", + ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) == + IB_MAC_IOCB_RSP_M_IPV6) ? "IPv6 RSS " : "", + ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) == + IB_MAC_IOCB_RSP_M_TCP_V4) ? "TCP/IPv4 RSS" : "", + ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) == + IB_MAC_IOCB_RSP_M_TCP_V6) ? "TCP/IPv6 RSS" : ""); + + printk(KERN_ERR PFX "data_len = %d\n", + le32_to_cpu(ib_mac_rsp->data_len)); + printk(KERN_ERR PFX "data_addr_hi = 0x%x\n", + le32_to_cpu(ib_mac_rsp->data_addr_hi)); + printk(KERN_ERR PFX "data_addr_lo = 0x%x\n", + le32_to_cpu(ib_mac_rsp->data_addr_lo)); + if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) + printk(KERN_ERR PFX "rss = %x\n", + le32_to_cpu(ib_mac_rsp->rss)); + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) + printk(KERN_ERR PFX "vlan_id = %x\n", + le16_to_cpu(ib_mac_rsp->vlan_id)); + + printk(KERN_ERR PFX "flags4 = %s%s%s.\n", + le32_to_cpu(ib_mac_rsp-> + flags4) & IB_MAC_IOCB_RSP_HV ? "HV " : "", + le32_to_cpu(ib_mac_rsp-> + flags4) & IB_MAC_IOCB_RSP_HS ? "HS " : "", + le32_to_cpu(ib_mac_rsp-> + flags4) & IB_MAC_IOCB_RSP_HL ? "HL " : ""); + + if (le32_to_cpu(ib_mac_rsp->flags4) & IB_MAC_IOCB_RSP_HV) { + printk(KERN_ERR PFX "hdr length = %d.\n", + le32_to_cpu(ib_mac_rsp->hdr_len)); + printk(KERN_ERR PFX "hdr addr_hi = 0x%x.\n", + le32_to_cpu(ib_mac_rsp->hdr_addr_hi)); + printk(KERN_ERR PFX "hdr addr_lo = 0x%x.\n", + le32_to_cpu(ib_mac_rsp->hdr_addr_lo)); + } +} +#endif + +#ifdef QL_ALL_DUMP +void ql_dump_all(struct ql_adapter *qdev) +{ + int i; + + QL_DUMP_REGS(qdev); + QL_DUMP_QDEV(qdev); + for (i = 0; i < qdev->tx_ring_count; i++) { + QL_DUMP_TX_RING(&qdev->tx_ring[i]); + QL_DUMP_WQICB((struct wqicb *)&qdev->tx_ring[i]); + } + for (i = 0; i < qdev->rx_ring_count; i++) { + QL_DUMP_RX_RING(&qdev->rx_ring[i]); + QL_DUMP_CQICB((struct cqicb *)&qdev->rx_ring[i]); + } +} +#endif diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c new file mode 100644 index 00000000000..b62fbd4bf00 --- /dev/null +++ b/drivers/net/qlge/qlge_ethtool.c @@ -0,0 +1,414 @@ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/module.h> +#include <linux/list.h> +#include <linux/pci.h> +#include <linux/dma-mapping.h> +#include <linux/pagemap.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/dmapool.h> +#include <linux/mempool.h> +#include <linux/spinlock.h> +#include <linux/kthread.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <net/ipv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/skbuff.h> +#include <linux/rtnetlink.h> +#include <linux/if_vlan.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> + +#include <linux/version.h> + +#include "qlge.h" + +static int ql_update_ring_coalescing(struct ql_adapter *qdev) +{ + int i, status = 0; + struct rx_ring *rx_ring; + struct cqicb *cqicb; + + if (!netif_running(qdev->ndev)) + return status; + + spin_lock(&qdev->hw_lock); + /* Skip the default queue, and update the outbound handler + * queues if they changed. + */ + cqicb = (struct cqicb *)&qdev->rx_ring[1]; + if (le16_to_cpu(cqicb->irq_delay) != qdev->tx_coalesce_usecs || + le16_to_cpu(cqicb->pkt_delay) != qdev->tx_max_coalesced_frames) { + for (i = 1; i < qdev->rss_ring_first_cq_id; i++, rx_ring++) { + rx_ring = &qdev->rx_ring[i]; + cqicb = (struct cqicb *)rx_ring; + cqicb->irq_delay = le16_to_cpu(qdev->tx_coalesce_usecs); + cqicb->pkt_delay = + le16_to_cpu(qdev->tx_max_coalesced_frames); + cqicb->flags = FLAGS_LI; + status = ql_write_cfg(qdev, cqicb, sizeof(cqicb), + CFG_LCQ, rx_ring->cq_id); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to load CQICB.\n"); + goto exit; + } + } + } + + /* Update the inbound (RSS) handler queues if they changed. */ + cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_first_cq_id]; + if (le16_to_cpu(cqicb->irq_delay) != qdev->rx_coalesce_usecs || + le16_to_cpu(cqicb->pkt_delay) != qdev->rx_max_coalesced_frames) { + for (i = qdev->rss_ring_first_cq_id; + i <= qdev->rss_ring_first_cq_id + qdev->rss_ring_count; + i++) { + rx_ring = &qdev->rx_ring[i]; + cqicb = (struct cqicb *)rx_ring; + cqicb->irq_delay = le16_to_cpu(qdev->rx_coalesce_usecs); + cqicb->pkt_delay = + le16_to_cpu(qdev->rx_max_coalesced_frames); + cqicb->flags = FLAGS_LI; + status = ql_write_cfg(qdev, cqicb, sizeof(cqicb), + CFG_LCQ, rx_ring->cq_id); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to load CQICB.\n"); + goto exit; + } + } + } +exit: + spin_unlock(&qdev->hw_lock); + return status; +} + +void ql_update_stats(struct ql_adapter *qdev) +{ + u32 i; + u64 data; + u64 *iter = &qdev->nic_stats.tx_pkts; + + spin_lock(&qdev->stats_lock); + if (ql_sem_spinlock(qdev, qdev->xg_sem_mask)) { + QPRINTK(qdev, DRV, ERR, + "Couldn't get xgmac sem.\n"); + goto quit; + } + /* + * Get TX statistics. + */ + for (i = 0x200; i < 0x280; i += 8) { + if (ql_read_xgmac_reg64(qdev, i, &data)) { + QPRINTK(qdev, DRV, ERR, + "Error reading status register 0x%.04x.\n", i); + goto end; + } else + *iter = data; + iter++; + } + + /* + * Get RX statistics. + */ + for (i = 0x300; i < 0x3d0; i += 8) { + if (ql_read_xgmac_reg64(qdev, i, &data)) { + QPRINTK(qdev, DRV, ERR, + "Error reading status register 0x%.04x.\n", i); + goto end; + } else + *iter = data; + iter++; + } + +end: + ql_sem_unlock(qdev, qdev->xg_sem_mask); +quit: + spin_unlock(&qdev->stats_lock); + + QL_DUMP_STAT(qdev); + + return; +} + +static char ql_stats_str_arr[][ETH_GSTRING_LEN] = { + {"tx_pkts"}, + {"tx_bytes"}, + {"tx_mcast_pkts"}, + {"tx_bcast_pkts"}, + {"tx_ucast_pkts"}, + {"tx_ctl_pkts"}, + {"tx_pause_pkts"}, + {"tx_64_pkts"}, + {"tx_65_to_127_pkts"}, + {"tx_128_to_255_pkts"}, + {"tx_256_511_pkts"}, + {"tx_512_to_1023_pkts"}, + {"tx_1024_to_1518_pkts"}, + {"tx_1519_to_max_pkts"}, + {"tx_undersize_pkts"}, + {"tx_oversize_pkts"}, + {"rx_bytes"}, + {"rx_bytes_ok"}, + {"rx_pkts"}, + {"rx_pkts_ok"}, + {"rx_bcast_pkts"}, + {"rx_mcast_pkts"}, + {"rx_ucast_pkts"}, + {"rx_undersize_pkts"}, + {"rx_oversize_pkts"}, + {"rx_jabber_pkts"}, + {"rx_undersize_fcerr_pkts"}, + {"rx_drop_events"}, + {"rx_fcerr_pkts"}, + {"rx_align_err"}, + {"rx_symbol_err"}, + {"rx_mac_err"}, + {"rx_ctl_pkts"}, + {"rx_pause_pkts"}, + {"rx_64_pkts"}, + {"rx_65_to_127_pkts"}, + {"rx_128_255_pkts"}, + {"rx_256_511_pkts"}, + {"rx_512_to_1023_pkts"}, + {"rx_1024_to_1518_pkts"}, + {"rx_1519_to_max_pkts"}, + {"rx_len_err_pkts"}, +}; + +static void ql_get_strings(struct net_device *dev, u32 stringset, u8 *buf) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(buf, ql_stats_str_arr, sizeof(ql_stats_str_arr)); + break; + } +} + +static int ql_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ql_stats_str_arr); + default: + return -EOPNOTSUPP; + } +} + +static void +ql_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *stats, u64 *data) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + struct nic_stats *s = &qdev->nic_stats; + + ql_update_stats(qdev); + + *data++ = s->tx_pkts; + *data++ = s->tx_bytes; + *data++ = s->tx_mcast_pkts; + *data++ = s->tx_bcast_pkts; + *data++ = s->tx_ucast_pkts; + *data++ = s->tx_ctl_pkts; + *data++ = s->tx_pause_pkts; + *data++ = s->tx_64_pkt; + *data++ = s->tx_65_to_127_pkt; + *data++ = s->tx_128_to_255_pkt; + *data++ = s->tx_256_511_pkt; + *data++ = s->tx_512_to_1023_pkt; + *data++ = s->tx_1024_to_1518_pkt; + *data++ = s->tx_1519_to_max_pkt; + *data++ = s->tx_undersize_pkt; + *data++ = s->tx_oversize_pkt; + *data++ = s->rx_bytes; + *data++ = s->rx_bytes_ok; + *data++ = s->rx_pkts; + *data++ = s->rx_pkts_ok; + *data++ = s->rx_bcast_pkts; + *data++ = s->rx_mcast_pkts; + *data++ = s->rx_ucast_pkts; + *data++ = s->rx_undersize_pkts; + *data++ = s->rx_oversize_pkts; + *data++ = s->rx_jabber_pkts; + *data++ = s->rx_undersize_fcerr_pkts; + *data++ = s->rx_drop_events; + *data++ = s->rx_fcerr_pkts; + *data++ = s->rx_align_err; + *data++ = s->rx_symbol_err; + *data++ = s->rx_mac_err; + *data++ = s->rx_ctl_pkts; + *data++ = s->rx_pause_pkts; + *data++ = s->rx_64_pkts; + *data++ = s->rx_65_to_127_pkts; + *data++ = s->rx_128_255_pkts; + *data++ = s->rx_256_511_pkts; + *data++ = s->rx_512_to_1023_pkts; + *data++ = s->rx_1024_to_1518_pkts; + *data++ = s->rx_1519_to_max_pkts; + *data++ = s->rx_len_err_pkts; +} + +static int ql_get_settings(struct net_device *ndev, + struct ethtool_cmd *ecmd) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + + ecmd->supported = SUPPORTED_10000baseT_Full; + ecmd->advertising = ADVERTISED_10000baseT_Full; + ecmd->autoneg = AUTONEG_ENABLE; + ecmd->transceiver = XCVR_EXTERNAL; + if ((qdev->link_status & LINK_TYPE_MASK) == LINK_TYPE_10GBASET) { + ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg); + ecmd->advertising |= (ADVERTISED_TP | ADVERTISED_Autoneg); + ecmd->port = PORT_TP; + } else { + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising |= ADVERTISED_FIBRE; + ecmd->port = PORT_FIBRE; + } + + ecmd->speed = SPEED_10000; + ecmd->duplex = DUPLEX_FULL; + + return 0; +} + +static void ql_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *drvinfo) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + strncpy(drvinfo->driver, qlge_driver_name, 32); + strncpy(drvinfo->version, qlge_driver_version, 32); + strncpy(drvinfo->fw_version, "N/A", 32); + strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32); + drvinfo->n_stats = 0; + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +} + +static int ql_get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + struct ql_adapter *qdev = netdev_priv(dev); + + c->rx_coalesce_usecs = qdev->rx_coalesce_usecs; + c->tx_coalesce_usecs = qdev->tx_coalesce_usecs; + + /* This chip coalesces as follows: + * If a packet arrives, hold off interrupts until + * cqicb->int_delay expires, but if no other packets arrive don't + * wait longer than cqicb->pkt_int_delay. But ethtool doesn't use a + * timer to coalesce on a frame basis. So, we have to take ethtool's + * max_coalesced_frames value and convert it to a delay in microseconds. + * We do this by using a basic thoughput of 1,000,000 frames per + * second @ (1024 bytes). This means one frame per usec. So it's a + * simple one to one ratio. + */ + c->rx_max_coalesced_frames = qdev->rx_max_coalesced_frames; + c->tx_max_coalesced_frames = qdev->tx_max_coalesced_frames; + + return 0; +} + +static int ql_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *c) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + + /* Validate user parameters. */ + if (c->rx_coalesce_usecs > qdev->rx_ring_size / 2) + return -EINVAL; + /* Don't wait more than 10 usec. */ + if (c->rx_max_coalesced_frames > MAX_INTER_FRAME_WAIT) + return -EINVAL; + if (c->tx_coalesce_usecs > qdev->tx_ring_size / 2) + return -EINVAL; + if (c->tx_max_coalesced_frames > MAX_INTER_FRAME_WAIT) + return -EINVAL; + + /* Verify a change took place before updating the hardware. */ + if (qdev->rx_coalesce_usecs == c->rx_coalesce_usecs && + qdev->tx_coalesce_usecs == c->tx_coalesce_usecs && + qdev->rx_max_coalesced_frames == c->rx_max_coalesced_frames && + qdev->tx_max_coalesced_frames == c->tx_max_coalesced_frames) + return 0; + + qdev->rx_coalesce_usecs = c->rx_coalesce_usecs; + qdev->tx_coalesce_usecs = c->tx_coalesce_usecs; + qdev->rx_max_coalesced_frames = c->rx_max_coalesced_frames; + qdev->tx_max_coalesced_frames = c->tx_max_coalesced_frames; + + return ql_update_ring_coalescing(qdev); +} + +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); + return qdev->msg_enable; +} + +static void ql_set_msglevel(struct net_device *ndev, u32 value) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + qdev->msg_enable = value; +} + +const struct ethtool_ops qlge_ethtool_ops = { + .get_settings = ql_get_settings, + .get_drvinfo = ql_get_drvinfo, + .get_msglevel = ql_get_msglevel, + .set_msglevel = ql_set_msglevel, + .get_link = ethtool_op_get_link, + .get_rx_csum = ql_get_rx_csum, + .set_rx_csum = ql_set_rx_csum, + .get_tx_csum = ethtool_op_get_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, + .get_strings = ql_get_strings, + .get_ethtool_stats = ql_get_ethtool_stats, +}; + diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c new file mode 100644 index 00000000000..4b2caa6b7ac --- /dev/null +++ b/drivers/net/qlge/qlge_main.c @@ -0,0 +1,3956 @@ +/* + * QLogic qlge NIC HBA Driver + * Copyright (c) 2003-2008 QLogic Corporation + * See LICENSE.qlge for copyright and licensing details. + * Author: Linux qlge network device driver by + * Ron Mercer <ron.mercer@qlogic.com> + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/module.h> +#include <linux/list.h> +#include <linux/pci.h> +#include <linux/dma-mapping.h> +#include <linux/pagemap.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/dmapool.h> +#include <linux/mempool.h> +#include <linux/spinlock.h> +#include <linux/kthread.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <net/ipv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/skbuff.h> +#include <linux/rtnetlink.h> +#include <linux/if_vlan.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <net/ip6_checksum.h> + +#include "qlge.h" + +char qlge_driver_name[] = DRV_NAME; +const char qlge_driver_version[] = DRV_VERSION; + +MODULE_AUTHOR("Ron Mercer <ron.mercer@qlogic.com>"); +MODULE_DESCRIPTION(DRV_STRING " "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +static const u32 default_msg = + NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | +/* NETIF_MSG_TIMER | */ + NETIF_MSG_IFDOWN | + NETIF_MSG_IFUP | + NETIF_MSG_RX_ERR | + NETIF_MSG_TX_ERR | + NETIF_MSG_TX_QUEUED | + NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS | +/* NETIF_MSG_PKTDATA | */ + NETIF_MSG_HW | NETIF_MSG_WOL | 0; + +static int debug = 0x00007fff; /* defaults above */ +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +#define MSIX_IRQ 0 +#define MSI_IRQ 1 +#define LEG_IRQ 2 +static int irq_type = MSIX_IRQ; +module_param(irq_type, int, MSIX_IRQ); +MODULE_PARM_DESC(irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); + +static struct pci_device_id qlge_pci_tbl[] __devinitdata = { + {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID)}, + {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID1)}, + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, qlge_pci_tbl); + +/* This hardware semaphore causes exclusive access to + * resources shared between the NIC driver, MPI firmware, + * FCOE firmware and the FC driver. + */ +static int ql_sem_trylock(struct ql_adapter *qdev, u32 sem_mask) +{ + u32 sem_bits = 0; + + switch (sem_mask) { + case SEM_XGMAC0_MASK: + sem_bits = SEM_SET << SEM_XGMAC0_SHIFT; + break; + case SEM_XGMAC1_MASK: + sem_bits = SEM_SET << SEM_XGMAC1_SHIFT; + break; + case SEM_ICB_MASK: + sem_bits = SEM_SET << SEM_ICB_SHIFT; + break; + case SEM_MAC_ADDR_MASK: + sem_bits = SEM_SET << SEM_MAC_ADDR_SHIFT; + break; + case SEM_FLASH_MASK: + sem_bits = SEM_SET << SEM_FLASH_SHIFT; + break; + case SEM_PROBE_MASK: + sem_bits = SEM_SET << SEM_PROBE_SHIFT; + break; + case SEM_RT_IDX_MASK: + sem_bits = SEM_SET << SEM_RT_IDX_SHIFT; + break; + case SEM_PROC_REG_MASK: + sem_bits = SEM_SET << SEM_PROC_REG_SHIFT; + break; + default: + QPRINTK(qdev, PROBE, ALERT, "Bad Semaphore mask!.\n"); + return -EINVAL; + } + + ql_write32(qdev, SEM, sem_bits | sem_mask); + return !(ql_read32(qdev, SEM) & sem_bits); +} + +int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask) +{ + unsigned int seconds = 3; + do { + if (!ql_sem_trylock(qdev, sem_mask)) + return 0; + ssleep(1); + } while (--seconds); + return -ETIMEDOUT; +} + +void ql_sem_unlock(struct ql_adapter *qdev, u32 sem_mask) +{ + ql_write32(qdev, SEM, sem_mask); + ql_read32(qdev, SEM); /* flush */ +} + +/* This function waits for a specific bit to come ready + * in a given register. It is used mostly by the initialize + * process, but is also used in kernel thread API such as + * netdev->set_multi, netdev->set_mac_address, netdev->vlan_rx_add_vid. + */ +int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 err_bit) +{ + u32 temp; + int count = UDELAY_COUNT; + + while (count) { + temp = ql_read32(qdev, reg); + + /* check for errors */ + if (temp & err_bit) { + QPRINTK(qdev, PROBE, ALERT, + "register 0x%.08x access error, value = 0x%.08x!.\n", + reg, temp); + return -EIO; + } else if (temp & bit) + return 0; + udelay(UDELAY_DELAY); + count--; + } + QPRINTK(qdev, PROBE, ALERT, + "Timed out waiting for reg %x to come ready.\n", reg); + return -ETIMEDOUT; +} + +/* The CFG register is used to download TX and RX control blocks + * to the chip. This function waits for an operation to complete. + */ +static int ql_wait_cfg(struct ql_adapter *qdev, u32 bit) +{ + int count = UDELAY_COUNT; + u32 temp; + + while (count) { + temp = ql_read32(qdev, CFG); + if (temp & CFG_LE) + return -EIO; + if (!(temp & bit)) + return 0; + udelay(UDELAY_DELAY); + count--; + } + return -ETIMEDOUT; +} + + +/* Used to issue init control blocks to hw. Maps control block, + * sets address, triggers download, waits for completion. + */ +int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, + u16 q_id) +{ + u64 map; + int status = 0; + int direction; + u32 mask; + u32 value; + + direction = + (bit & (CFG_LRQ | CFG_LR | CFG_LCQ)) ? PCI_DMA_TODEVICE : + PCI_DMA_FROMDEVICE; + + map = pci_map_single(qdev->pdev, ptr, size, direction); + if (pci_dma_mapping_error(qdev->pdev, map)) { + QPRINTK(qdev, IFUP, ERR, "Couldn't map DMA area.\n"); + return -ENOMEM; + } + + status = ql_wait_cfg(qdev, bit); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Timed out waiting for CFG to come ready.\n"); + goto exit; + } + + status = ql_sem_spinlock(qdev, SEM_ICB_MASK); + if (status) + goto exit; + ql_write32(qdev, ICB_L, (u32) map); + ql_write32(qdev, ICB_H, (u32) (map >> 32)); + ql_sem_unlock(qdev, SEM_ICB_MASK); /* does flush too */ + + mask = CFG_Q_MASK | (bit << 16); + value = bit | (q_id << CFG_Q_SHIFT); + ql_write32(qdev, CFG, (mask | value)); + + /* + * Wait for the bit to clear after signaling hw. + */ + status = ql_wait_cfg(qdev, bit); +exit: + pci_unmap_single(qdev->pdev, map, size, direction); + return status; +} + +/* Get a specific MAC address from the CAM. Used for debug and reg dump. */ +int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index, + u32 *value) +{ + u32 offset = 0; + int status; + + status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); + if (status) + return status; + switch (type) { + case MAC_ADDR_TYPE_MULTI_MAC: + case MAC_ADDR_TYPE_CAM_MAC: + { + status = + ql_wait_reg_rdy(qdev, + MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E); + if (status) + goto exit; + ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */ + (index << MAC_ADDR_IDX_SHIFT) | /* index */ + MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */ + status = + ql_wait_reg_rdy(qdev, + MAC_ADDR_IDX, MAC_ADDR_MR, MAC_ADDR_E); + if (status) + goto exit; + *value++ = ql_read32(qdev, MAC_ADDR_DATA); + status = + ql_wait_reg_rdy(qdev, + MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E); + if (status) + goto exit; + ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */ + (index << MAC_ADDR_IDX_SHIFT) | /* index */ + MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */ + status = + ql_wait_reg_rdy(qdev, + MAC_ADDR_IDX, MAC_ADDR_MR, MAC_ADDR_E); + if (status) + goto exit; + *value++ = ql_read32(qdev, MAC_ADDR_DATA); + if (type == MAC_ADDR_TYPE_CAM_MAC) { + status = + ql_wait_reg_rdy(qdev, + MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E); + if (status) + goto exit; + ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */ + (index << MAC_ADDR_IDX_SHIFT) | /* index */ + MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */ + status = + ql_wait_reg_rdy(qdev, MAC_ADDR_IDX, + MAC_ADDR_MR, MAC_ADDR_E); + if (status) + goto exit; + *value++ = ql_read32(qdev, MAC_ADDR_DATA); + } + break; + } + case MAC_ADDR_TYPE_VLAN: + case MAC_ADDR_TYPE_MULTI_FLTR: + default: + QPRINTK(qdev, IFUP, CRIT, + "Address type %d not yet supported.\n", type); + status = -EPERM; + } +exit: + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); + return status; +} + +/* Set up a MAC, multicast or VLAN address for the + * inbound frame matching. + */ +static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, + u16 index) +{ + u32 offset = 0; + int status = 0; + + status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); + if (status) + return status; + switch (type) { + case MAC_ADDR_TYPE_MULTI_MAC: + case MAC_ADDR_TYPE_CAM_MAC: + { + u32 cam_output; + u32 upper = (addr[0] << 8) | addr[1]; + u32 lower = + (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | + (addr[5]); + + QPRINTK(qdev, IFUP, INFO, + "Adding %s address %02x:%02x:%02x:%02x:%02x:%02x" + " at index %d in the CAM.\n", + ((type == + MAC_ADDR_TYPE_MULTI_MAC) ? "MULTICAST" : + "UNICAST"), addr[0], addr[1], addr[2], addr[3], + addr[4], addr[5], index); + + status = + ql_wait_reg_rdy(qdev, + MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E); + if (status) + goto exit; + ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */ + (index << MAC_ADDR_IDX_SHIFT) | /* index */ + type); /* type */ + ql_write32(qdev, MAC_ADDR_DATA, lower); + status = + ql_wait_reg_rdy(qdev, + MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E); + if (status) + goto exit; + ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */ + (index << MAC_ADDR_IDX_SHIFT) | /* index */ + type); /* type */ + ql_write32(qdev, MAC_ADDR_DATA, upper); + status = + ql_wait_reg_rdy(qdev, + MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E); + if (status) + goto exit; + ql_write32(qdev, MAC_ADDR_IDX, (offset) | /* offset */ + (index << MAC_ADDR_IDX_SHIFT) | /* index */ + type); /* type */ + /* This field should also include the queue id + and possibly the function id. Right now we hardcode + the route field to NIC core. + */ + if (type == MAC_ADDR_TYPE_CAM_MAC) { + cam_output = (CAM_OUT_ROUTE_NIC | + (qdev-> + func << CAM_OUT_FUNC_SHIFT) | + (qdev-> + rss_ring_first_cq_id << + CAM_OUT_CQ_ID_SHIFT)); + if (qdev->vlgrp) + cam_output |= CAM_OUT_RV; + /* route to NIC core */ + ql_write32(qdev, MAC_ADDR_DATA, cam_output); + } + break; + } + case MAC_ADDR_TYPE_VLAN: + { + u32 enable_bit = *((u32 *) &addr[0]); + /* For VLAN, the addr actually holds a bit that + * either enables or disables the vlan id we are + * addressing. It's either MAC_ADDR_E on or off. + * That's bit-27 we're talking about. + */ + QPRINTK(qdev, IFUP, INFO, "%s VLAN ID %d %s the CAM.\n", + (enable_bit ? "Adding" : "Removing"), + index, (enable_bit ? "to" : "from")); + + status = + ql_wait_reg_rdy(qdev, + MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E); + if (status) + goto exit; + ql_write32(qdev, MAC_ADDR_IDX, offset | /* offset */ + (index << MAC_ADDR_IDX_SHIFT) | /* index */ + type | /* type */ + enable_bit); /* enable/disable */ + break; + } + case MAC_ADDR_TYPE_MULTI_FLTR: + default: + QPRINTK(qdev, IFUP, CRIT, + "Address type %d not yet supported.\n", type); + status = -EPERM; + } +exit: + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); + return status; +} + +/* Get a specific frame routing value from the CAM. + * Used for debug and reg dump. + */ +int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value) +{ + int status = 0; + + status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); + if (status) + goto exit; + + status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, RT_IDX_E); + if (status) + goto exit; + + ql_write32(qdev, RT_IDX, + RT_IDX_TYPE_NICQ | RT_IDX_RS | (index << RT_IDX_IDX_SHIFT)); + status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MR, RT_IDX_E); + if (status) + goto exit; + *value = ql_read32(qdev, RT_DATA); +exit: + ql_sem_unlock(qdev, SEM_RT_IDX_MASK); + return status; +} + +/* The NIC function for this chip has 16 routing indexes. Each one can be used + * to route different frame types to various inbound queues. We send broadcast/ + * multicast/error frames to the default queue for slow handling, + * and CAM hit/RSS frames to the fast handling queues. + */ +static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask, + int enable) +{ + int status; + u32 value = 0; + + status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); + if (status) + return status; + + QPRINTK(qdev, IFUP, DEBUG, + "%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s mask %s the routing reg.\n", + (enable ? "Adding" : "Removing"), + ((index == RT_IDX_ALL_ERR_SLOT) ? "MAC ERROR/ALL ERROR" : ""), + ((index == RT_IDX_IP_CSUM_ERR_SLOT) ? "IP CSUM ERROR" : ""), + ((index == + RT_IDX_TCP_UDP_CSUM_ERR_SLOT) ? "TCP/UDP CSUM ERROR" : ""), + ((index == RT_IDX_BCAST_SLOT) ? "BROADCAST" : ""), + ((index == RT_IDX_MCAST_MATCH_SLOT) ? "MULTICAST MATCH" : ""), + ((index == RT_IDX_ALLMULTI_SLOT) ? "ALL MULTICAST MATCH" : ""), + ((index == RT_IDX_UNUSED6_SLOT) ? "UNUSED6" : ""), + ((index == RT_IDX_UNUSED7_SLOT) ? "UNUSED7" : ""), + ((index == RT_IDX_RSS_MATCH_SLOT) ? "RSS ALL/IPV4 MATCH" : ""), + ((index == RT_IDX_RSS_IPV6_SLOT) ? "RSS IPV6" : ""), + ((index == RT_IDX_RSS_TCP4_SLOT) ? "RSS TCP4" : ""), + ((index == RT_IDX_RSS_TCP6_SLOT) ? "RSS TCP6" : ""), + ((index == RT_IDX_CAM_HIT_SLOT) ? "CAM HIT" : ""), + ((index == RT_IDX_UNUSED013) ? "UNUSED13" : ""), + ((index == RT_IDX_UNUSED014) ? "UNUSED14" : ""), + ((index == RT_IDX_PROMISCUOUS_SLOT) ? "PROMISCUOUS" : ""), + (enable ? "to" : "from")); + + switch (mask) { + case RT_IDX_CAM_HIT: + { + value = RT_IDX_DST_CAM_Q | /* dest */ + RT_IDX_TYPE_NICQ | /* type */ + (RT_IDX_CAM_HIT_SLOT << RT_IDX_IDX_SHIFT);/* index */ + break; + } + case RT_IDX_VALID: /* Promiscuous Mode frames. */ + { + value = RT_IDX_DST_DFLT_Q | /* dest */ + RT_IDX_TYPE_NICQ | /* type */ + (RT_IDX_PROMISCUOUS_SLOT << RT_IDX_IDX_SHIFT);/* index */ + break; + } + case RT_IDX_ERR: /* Pass up MAC,IP,TCP/UDP error frames. */ + { + value = RT_IDX_DST_DFLT_Q | /* dest */ + RT_IDX_TYPE_NICQ | /* type */ + (RT_IDX_ALL_ERR_SLOT << RT_IDX_IDX_SHIFT);/* index */ + break; + } + case RT_IDX_BCAST: /* Pass up Broadcast frames to default Q. */ + { + value = RT_IDX_DST_DFLT_Q | /* dest */ + RT_IDX_TYPE_NICQ | /* type */ + (RT_IDX_BCAST_SLOT << RT_IDX_IDX_SHIFT);/* index */ + break; + } + case RT_IDX_MCAST: /* Pass up All Multicast frames. */ + { + value = RT_IDX_DST_CAM_Q | /* dest */ + RT_IDX_TYPE_NICQ | /* type */ + (RT_IDX_ALLMULTI_SLOT << RT_IDX_IDX_SHIFT);/* index */ + break; + } + case RT_IDX_MCAST_MATCH: /* Pass up matched Multicast frames. */ + { + value = RT_IDX_DST_CAM_Q | /* dest */ + RT_IDX_TYPE_NICQ | /* type */ + (RT_IDX_MCAST_MATCH_SLOT << RT_IDX_IDX_SHIFT);/* index */ + break; + } + case RT_IDX_RSS_MATCH: /* Pass up matched RSS frames. */ + { + value = RT_IDX_DST_RSS | /* dest */ + RT_IDX_TYPE_NICQ | /* type */ + (RT_IDX_RSS_MATCH_SLOT << RT_IDX_IDX_SHIFT);/* index */ + break; + } + case 0: /* Clear the E-bit on an entry. */ + { + value = RT_IDX_DST_DFLT_Q | /* dest */ + RT_IDX_TYPE_NICQ | /* type */ + (index << RT_IDX_IDX_SHIFT);/* index */ + break; + } + default: + QPRINTK(qdev, IFUP, ERR, "Mask type %d not yet supported.\n", + mask); + status = -EPERM; + goto exit; + } + + if (value) { + status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, 0); + if (status) + goto exit; + value |= (enable ? RT_IDX_E : 0); + ql_write32(qdev, RT_IDX, value); + ql_write32(qdev, RT_DATA, enable ? mask : 0); + } +exit: + ql_sem_unlock(qdev, SEM_RT_IDX_MASK); + return status; +} + +static void ql_enable_interrupts(struct ql_adapter *qdev) +{ + ql_write32(qdev, INTR_EN, (INTR_EN_EI << 16) | INTR_EN_EI); +} + +static void ql_disable_interrupts(struct ql_adapter *qdev) +{ + ql_write32(qdev, INTR_EN, (INTR_EN_EI << 16)); +} + +/* If we're running with multiple MSI-X vectors then we enable on the fly. + * Otherwise, we may have multiple outstanding workers and don't want to + * enable until the last one finishes. In this case, the irq_cnt gets + * incremented everytime we queue a worker and decremented everytime + * a worker finishes. Once it hits zero we enable the interrupt. + */ +void ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr) +{ + if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) + ql_write32(qdev, INTR_EN, + qdev->intr_context[intr].intr_en_mask); + else { + if (qdev->legacy_check) + spin_lock(&qdev->legacy_lock); + if (atomic_dec_and_test(&qdev->intr_context[intr].irq_cnt)) { + QPRINTK(qdev, INTR, ERR, "Enabling interrupt %d.\n", + intr); + ql_write32(qdev, INTR_EN, + qdev->intr_context[intr].intr_en_mask); + } else { + QPRINTK(qdev, INTR, ERR, + "Skip enable, other queue(s) are active.\n"); + } + if (qdev->legacy_check) + spin_unlock(&qdev->legacy_lock); + } +} + +static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr) +{ + u32 var = 0; + + if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) + goto exit; + else if (!atomic_read(&qdev->intr_context[intr].irq_cnt)) { + ql_write32(qdev, INTR_EN, + qdev->intr_context[intr].intr_dis_mask); + var = ql_read32(qdev, STS); + } + atomic_inc(&qdev->intr_context[intr].irq_cnt); +exit: + return var; +} + +static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev) +{ + int i; + for (i = 0; i < qdev->intr_count; i++) { + /* The enable call does a atomic_dec_and_test + * and enables only if the result is zero. + * So we precharge it here. + */ + atomic_set(&qdev->intr_context[i].irq_cnt, 1); + ql_enable_completion_interrupt(qdev, i); + } + +} + +int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data) +{ + int status = 0; + /* wait for reg to come ready */ + status = ql_wait_reg_rdy(qdev, + FLASH_ADDR, FLASH_ADDR_RDY, FLASH_ADDR_ERR); + if (status) + goto exit; + /* set up for reg read */ + ql_write32(qdev, FLASH_ADDR, FLASH_ADDR_R | offset); + /* wait for reg to come ready */ + status = ql_wait_reg_rdy(qdev, + FLASH_ADDR, FLASH_ADDR_RDY, FLASH_ADDR_ERR); + if (status) + goto exit; + /* get the data */ + *data = ql_read32(qdev, FLASH_DATA); +exit: + return status; +} + +static int ql_get_flash_params(struct ql_adapter *qdev) +{ + int i; + int status; + u32 *p = (u32 *)&qdev->flash; + + if (ql_sem_spinlock(qdev, SEM_FLASH_MASK)) + return -ETIMEDOUT; + + for (i = 0; i < sizeof(qdev->flash) / sizeof(u32); i++, p++) { + status = ql_read_flash_word(qdev, i, p); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n"); + goto exit; + } + + } +exit: + ql_sem_unlock(qdev, SEM_FLASH_MASK); + return status; +} + +/* xgmac register are located behind the xgmac_addr and xgmac_data + * register pair. Each read/write requires us to wait for the ready + * bit before reading/writing the data. + */ +static int ql_write_xgmac_reg(struct ql_adapter *qdev, u32 reg, u32 data) +{ + int status; + /* wait for reg to come ready */ + status = ql_wait_reg_rdy(qdev, + XGMAC_ADDR, XGMAC_ADDR_RDY, XGMAC_ADDR_XME); + if (status) + return status; + /* write the data to the data reg */ + ql_write32(qdev, XGMAC_DATA, data); + /* trigger the write */ + ql_write32(qdev, XGMAC_ADDR, reg); + return status; +} + +/* xgmac register are located behind the xgmac_addr and xgmac_data + * register pair. Each read/write requires us to wait for the ready + * bit before reading/writing the data. + */ +int ql_read_xgmac_reg(struct ql_adapter *qdev, u32 reg, u32 *data) +{ + int status = 0; + /* wait for reg to come ready */ + status = ql_wait_reg_rdy(qdev, + XGMAC_ADDR, XGMAC_ADDR_RDY, XGMAC_ADDR_XME); + if (status) + goto exit; + /* set up for reg read */ + ql_write32(qdev, XGMAC_ADDR, reg | XGMAC_ADDR_R); + /* wait for reg to come ready */ + status = ql_wait_reg_rdy(qdev, + XGMAC_ADDR, XGMAC_ADDR_RDY, XGMAC_ADDR_XME); + if (status) + goto exit; + /* get the data */ + *data = ql_read32(qdev, XGMAC_DATA); +exit: + return status; +} + +/* This is used for reading the 64-bit statistics regs. */ +int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data) +{ + int status = 0; + u32 hi = 0; + u32 lo = 0; + + status = ql_read_xgmac_reg(qdev, reg, &lo); + if (status) + goto exit; + + status = ql_read_xgmac_reg(qdev, reg + 4, &hi); + if (status) + goto exit; + + *data = (u64) lo | ((u64) hi << 32); + +exit: + return status; +} + +/* Take the MAC Core out of reset. + * Enable statistics counting. + * Take the transmitter/receiver out of reset. + * This functionality may be done in the MPI firmware at a + * later date. + */ +static int ql_port_initialize(struct ql_adapter *qdev) +{ + int status = 0; + u32 data; + + if (ql_sem_trylock(qdev, qdev->xg_sem_mask)) { + /* Another function has the semaphore, so + * wait for the port init bit to come ready. + */ + QPRINTK(qdev, LINK, INFO, + "Another function has the semaphore, so wait for the port init bit to come ready.\n"); + status = ql_wait_reg_rdy(qdev, STS, qdev->port_init, 0); + if (status) { + QPRINTK(qdev, LINK, CRIT, + "Port initialize timed out.\n"); + } + return status; + } + + QPRINTK(qdev, LINK, INFO, "Got xgmac semaphore!.\n"); + /* Set the core reset. */ + status = ql_read_xgmac_reg(qdev, GLOBAL_CFG, &data); + if (status) + goto end; + data |= GLOBAL_CFG_RESET; + status = ql_write_xgmac_reg(qdev, GLOBAL_CFG, data); + if (status) + goto end; + + /* Clear the core reset and turn on jumbo for receiver. */ + data &= ~GLOBAL_CFG_RESET; /* Clear core reset. */ + data |= GLOBAL_CFG_JUMBO; /* Turn on jumbo. */ + data |= GLOBAL_CFG_TX_STAT_EN; + data |= GLOBAL_CFG_RX_STAT_EN; + status = ql_write_xgmac_reg(qdev, GLOBAL_CFG, data); + if (status) + goto end; + + /* Enable transmitter, and clear it's reset. */ + status = ql_read_xgmac_reg(qdev, TX_CFG, &data); + if (status) + goto end; + data &= ~TX_CFG_RESET; /* Clear the TX MAC reset. */ + data |= TX_CFG_EN; /* Enable the transmitter. */ + status = ql_write_xgmac_reg(qdev, TX_CFG, data); + if (status) + goto end; + + /* Enable receiver and clear it's reset. */ + status = ql_read_xgmac_reg(qdev, RX_CFG, &data); + if (status) + goto end; + data &= ~RX_CFG_RESET; /* Clear the RX MAC reset. */ + data |= RX_CFG_EN; /* Enable the receiver. */ + status = ql_write_xgmac_reg(qdev, RX_CFG, data); + if (status) + goto end; + + /* Turn on jumbo. */ + status = + ql_write_xgmac_reg(qdev, MAC_TX_PARAMS, MAC_TX_PARAMS_JUMBO | (0x2580 << 16)); + if (status) + goto end; + status = + ql_write_xgmac_reg(qdev, MAC_RX_PARAMS, 0x2580); + if (status) + goto end; + + /* Signal to the world that the port is enabled. */ + ql_write32(qdev, STS, ((qdev->port_init << 16) | qdev->port_init)); +end: + ql_sem_unlock(qdev, qdev->xg_sem_mask); + return status; +} + +/* Get the next large buffer. */ +struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring) +{ + struct bq_desc *lbq_desc = &rx_ring->lbq[rx_ring->lbq_curr_idx]; + rx_ring->lbq_curr_idx++; + if (rx_ring->lbq_curr_idx == rx_ring->lbq_len) + rx_ring->lbq_curr_idx = 0; + rx_ring->lbq_free_cnt++; + return lbq_desc; +} + +/* Get the next small buffer. */ +struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring) +{ + struct bq_desc *sbq_desc = &rx_ring->sbq[rx_ring->sbq_curr_idx]; + rx_ring->sbq_curr_idx++; + if (rx_ring->sbq_curr_idx == rx_ring->sbq_len) + rx_ring->sbq_curr_idx = 0; + rx_ring->sbq_free_cnt++; + return sbq_desc; +} + +/* Update an rx ring index. */ +static void ql_update_cq(struct rx_ring *rx_ring) +{ + rx_ring->cnsmr_idx++; + rx_ring->curr_entry++; + if (unlikely(rx_ring->cnsmr_idx == rx_ring->cq_len)) { + rx_ring->cnsmr_idx = 0; + rx_ring->curr_entry = rx_ring->cq_base; + } +} + +static void ql_write_cq_idx(struct rx_ring *rx_ring) +{ + ql_write_db_reg(rx_ring->cnsmr_idx, rx_ring->cnsmr_idx_db_reg); +} + +/* Process (refill) a large buffer queue. */ +static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) +{ + int clean_idx = rx_ring->lbq_clean_idx; + struct bq_desc *lbq_desc; + struct bq_element *bq; + u64 map; + int i; + + while (rx_ring->lbq_free_cnt > 16) { + for (i = 0; i < 16; i++) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "lbq: try cleaning clean_idx = %d.\n", + clean_idx); + lbq_desc = &rx_ring->lbq[clean_idx]; + bq = lbq_desc->bq; + if (lbq_desc->p.lbq_page == NULL) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "lbq: getting new page for index %d.\n", + lbq_desc->index); + lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC); + if (lbq_desc->p.lbq_page == NULL) { + QPRINTK(qdev, RX_STATUS, ERR, + "Couldn't get a page.\n"); + return; + } + map = pci_map_page(qdev->pdev, + lbq_desc->p.lbq_page, + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(qdev->pdev, map)) { + QPRINTK(qdev, RX_STATUS, ERR, + "PCI mapping failed.\n"); + return; + } + pci_unmap_addr_set(lbq_desc, mapaddr, map); + pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE); + bq->addr_lo = /*lbq_desc->addr_lo = */ + cpu_to_le32(map); + bq->addr_hi = /*lbq_desc->addr_hi = */ + cpu_to_le32(map >> 32); + } + clean_idx++; + if (clean_idx == rx_ring->lbq_len) + clean_idx = 0; + } + + rx_ring->lbq_clean_idx = clean_idx; + rx_ring->lbq_prod_idx += 16; + if (rx_ring->lbq_prod_idx == rx_ring->lbq_len) + rx_ring->lbq_prod_idx = 0; + QPRINTK(qdev, RX_STATUS, DEBUG, + "lbq: updating prod idx = %d.\n", + rx_ring->lbq_prod_idx); + ql_write_db_reg(rx_ring->lbq_prod_idx, + rx_ring->lbq_prod_idx_db_reg); + rx_ring->lbq_free_cnt -= 16; + } +} + +/* Process (refill) a small buffer queue. */ +static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) +{ + int clean_idx = rx_ring->sbq_clean_idx; + struct bq_desc *sbq_desc; + struct bq_element *bq; + u64 map; + int i; + + while (rx_ring->sbq_free_cnt > 16) { + for (i = 0; i < 16; i++) { + sbq_desc = &rx_ring->sbq[clean_idx]; + QPRINTK(qdev, RX_STATUS, DEBUG, + "sbq: try cleaning clean_idx = %d.\n", + clean_idx); + bq = sbq_desc->bq; + if (sbq_desc->p.skb == NULL) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "sbq: getting new skb for index %d.\n", + sbq_desc->index); + sbq_desc->p.skb = + netdev_alloc_skb(qdev->ndev, + rx_ring->sbq_buf_size); + if (sbq_desc->p.skb == NULL) { + QPRINTK(qdev, PROBE, ERR, + "Couldn't get an skb.\n"); + rx_ring->sbq_clean_idx = clean_idx; + return; + } + skb_reserve(sbq_desc->p.skb, QLGE_SB_PAD); + map = pci_map_single(qdev->pdev, + sbq_desc->p.skb->data, + rx_ring->sbq_buf_size / + 2, PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(sbq_desc, mapaddr, map); + pci_unmap_len_set(sbq_desc, maplen, + rx_ring->sbq_buf_size / 2); + bq->addr_lo = cpu_to_le32(map); + bq->addr_hi = cpu_to_le32(map >> 32); + } + + clean_idx++; + if (clean_idx == rx_ring->sbq_len) + clean_idx = 0; + } + rx_ring->sbq_clean_idx = clean_idx; + rx_ring->sbq_prod_idx += 16; + if (rx_ring->sbq_prod_idx == rx_ring->sbq_len) + rx_ring->sbq_prod_idx = 0; + QPRINTK(qdev, RX_STATUS, DEBUG, + "sbq: updating prod idx = %d.\n", + rx_ring->sbq_prod_idx); + ql_write_db_reg(rx_ring->sbq_prod_idx, + rx_ring->sbq_prod_idx_db_reg); + + rx_ring->sbq_free_cnt -= 16; + } +} + +static void ql_update_buffer_queues(struct ql_adapter *qdev, + struct rx_ring *rx_ring) +{ + ql_update_sbq(qdev, rx_ring); + ql_update_lbq(qdev, rx_ring); +} + +/* Unmaps tx buffers. Can be called from send() if a pci mapping + * fails at some stage, or from the interrupt when a tx completes. + */ +static void ql_unmap_send(struct ql_adapter *qdev, + struct tx_ring_desc *tx_ring_desc, int mapped) +{ + int i; + for (i = 0; i < mapped; i++) { + if (i == 0 || (i == 7 && mapped > 7)) { + /* + * Unmap the skb->data area, or the + * external sglist (AKA the Outbound + * Address List (OAL)). + * If its the zeroeth element, then it's + * the skb->data area. If it's the 7th + * element and there is more than 6 frags, + * then its an OAL. + */ + if (i == 7) { + QPRINTK(qdev, TX_DONE, DEBUG, + "unmapping OAL area.\n"); + } + pci_unmap_single(qdev->pdev, + pci_unmap_addr(&tx_ring_desc->map[i], + mapaddr), + pci_unmap_len(&tx_ring_desc->map[i], + maplen), + PCI_DMA_TODEVICE); + } else { + QPRINTK(qdev, TX_DONE, DEBUG, "unmapping frag %d.\n", + i); + pci_unmap_page(qdev->pdev, + pci_unmap_addr(&tx_ring_desc->map[i], + mapaddr), + pci_unmap_len(&tx_ring_desc->map[i], + maplen), PCI_DMA_TODEVICE); + } + } + +} + +/* Map the buffers for this transmit. This will return + * NETDEV_TX_BUSY or NETDEV_TX_OK based on success. + */ +static int ql_map_send(struct ql_adapter *qdev, + struct ob_mac_iocb_req *mac_iocb_ptr, + struct sk_buff *skb, struct tx_ring_desc *tx_ring_desc) +{ + int len = skb_headlen(skb); + dma_addr_t map; + int frag_idx, err, map_idx = 0; + struct tx_buf_desc *tbd = mac_iocb_ptr->tbd; + int frag_cnt = skb_shinfo(skb)->nr_frags; + + if (frag_cnt) { + QPRINTK(qdev, TX_QUEUED, DEBUG, "frag_cnt = %d.\n", frag_cnt); + } + /* + * Map the skb buffer first. + */ + map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE); + + err = pci_dma_mapping_error(qdev->pdev, map); + if (err) { + QPRINTK(qdev, TX_QUEUED, ERR, + "PCI mapping failed with error: %d\n", err); + + return NETDEV_TX_BUSY; + } + + tbd->len = cpu_to_le32(len); + tbd->addr = cpu_to_le64(map); + pci_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, map); + pci_unmap_len_set(&tx_ring_desc->map[map_idx], maplen, len); + map_idx++; + + /* + * This loop fills the remainder of the 8 address descriptors + * in the IOCB. If there are more than 7 fragments, then the + * eighth address desc will point to an external list (OAL). + * When this happens, the remainder of the frags will be stored + * in this list. + */ + for (frag_idx = 0; frag_idx < frag_cnt; frag_idx++, map_idx++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_idx]; + tbd++; + if (frag_idx == 6 && frag_cnt > 7) { + /* Let's tack on an sglist. + * Our control block will now + * look like this: + * iocb->seg[0] = skb->data + * iocb->seg[1] = frag[0] + * iocb->seg[2] = frag[1] + * iocb->seg[3] = frag[2] + * iocb->seg[4] = frag[3] + * iocb->seg[5] = frag[4] + * iocb->seg[6] = frag[5] + * iocb->seg[7] = ptr to OAL (external sglist) + * oal->seg[0] = frag[6] + * oal->seg[1] = frag[7] + * oal->seg[2] = frag[8] + * oal->seg[3] = frag[9] + * oal->seg[4] = frag[10] + * etc... + */ + /* Tack on the OAL in the eighth segment of IOCB. */ + map = pci_map_single(qdev->pdev, &tx_ring_desc->oal, + sizeof(struct oal), + PCI_DMA_TODEVICE); + err = pci_dma_mapping_error(qdev->pdev, map); + if (err) { + QPRINTK(qdev, TX_QUEUED, ERR, + "PCI mapping outbound address list with error: %d\n", + err); + goto map_error; + } + + tbd->addr = cpu_to_le64(map); + /* + * The length is the number of fragments + * that remain to be mapped times the length + * of our sglist (OAL). + */ + tbd->len = + cpu_to_le32((sizeof(struct tx_buf_desc) * + (frag_cnt - frag_idx)) | TX_DESC_C); + pci_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, + map); + pci_unmap_len_set(&tx_ring_desc->map[map_idx], maplen, + sizeof(struct oal)); + tbd = (struct tx_buf_desc *)&tx_ring_desc->oal; + map_idx++; + } + + map = + pci_map_page(qdev->pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + + err = pci_dma_mapping_error(qdev->pdev, map); + if (err) { + QPRINTK(qdev, TX_QUEUED, ERR, + "PCI mapping frags failed with error: %d.\n", + err); + goto map_error; + } + + tbd->addr = cpu_to_le64(map); + tbd->len = cpu_to_le32(frag->size); + pci_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, map); + pci_unmap_len_set(&tx_ring_desc->map[map_idx], maplen, + frag->size); + + } + /* Save the number of segments we've mapped. */ + tx_ring_desc->map_cnt = map_idx; + /* Terminate the last segment. */ + tbd->len = cpu_to_le32(le32_to_cpu(tbd->len) | TX_DESC_E); + return NETDEV_TX_OK; + +map_error: + /* + * If the first frag mapping failed, then i will be zero. + * This causes the unmap of the skb->data area. Otherwise + * we pass in the number of frags that mapped successfully + * so they can be umapped. + */ + ql_unmap_send(qdev, tx_ring_desc, map_idx); + return NETDEV_TX_BUSY; +} + +void ql_realign_skb(struct sk_buff *skb, int len) +{ + void *temp_addr = skb->data; + + /* Undo the skb_reserve(skb,32) we did before + * giving to hardware, and realign data on + * a 2-byte boundary. + */ + skb->data -= QLGE_SB_PAD - NET_IP_ALIGN; + skb->tail -= QLGE_SB_PAD - NET_IP_ALIGN; + skb_copy_to_linear_data(skb, temp_addr, + (unsigned int)len); +} + +/* + * This function builds an skb for the given inbound + * completion. It will be rewritten for readability in the near + * future, but for not it works well. + */ +static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, + struct rx_ring *rx_ring, + struct ib_mac_iocb_rsp *ib_mac_rsp) +{ + struct bq_desc *lbq_desc; + struct bq_desc *sbq_desc; + struct sk_buff *skb = NULL; + u32 length = le32_to_cpu(ib_mac_rsp->data_len); + u32 hdr_len = le32_to_cpu(ib_mac_rsp->hdr_len); + + /* + * Handle the header buffer if present. + */ + if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV && + ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) { + QPRINTK(qdev, RX_STATUS, DEBUG, "Header of %d bytes in small buffer.\n", hdr_len); + /* + * Headers fit nicely into a small buffer. + */ + sbq_desc = ql_get_curr_sbuf(rx_ring); + pci_unmap_single(qdev->pdev, + pci_unmap_addr(sbq_desc, mapaddr), + pci_unmap_len(sbq_desc, maplen), + PCI_DMA_FROMDEVICE); + skb = sbq_desc->p.skb; + ql_realign_skb(skb, hdr_len); + skb_put(skb, hdr_len); + sbq_desc->p.skb = NULL; + } + + /* + * Handle the data buffer(s). + */ + if (unlikely(!length)) { /* Is there data too? */ + QPRINTK(qdev, RX_STATUS, DEBUG, + "No Data buffer in this packet.\n"); + return skb; + } + + if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS) { + if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "Headers in small, data of %d bytes in small, combine them.\n", length); + /* + * Data is less than small buffer size so it's + * stuffed in a small buffer. + * For this case we append the data + * from the "data" small buffer to the "header" small + * buffer. + */ + sbq_desc = ql_get_curr_sbuf(rx_ring); + pci_dma_sync_single_for_cpu(qdev->pdev, + pci_unmap_addr + (sbq_desc, mapaddr), + pci_unmap_len + (sbq_desc, maplen), + PCI_DMA_FROMDEVICE); + memcpy(skb_put(skb, length), + sbq_desc->p.skb->data, length); + pci_dma_sync_single_for_device(qdev->pdev, + pci_unmap_addr + (sbq_desc, + mapaddr), + pci_unmap_len + (sbq_desc, + maplen), + PCI_DMA_FROMDEVICE); + } else { + QPRINTK(qdev, RX_STATUS, DEBUG, + "%d bytes in a single small buffer.\n", length); + sbq_desc = ql_get_curr_sbuf(rx_ring); + skb = sbq_desc->p.skb; + ql_realign_skb(skb, length); + skb_put(skb, length); + pci_unmap_single(qdev->pdev, + pci_unmap_addr(sbq_desc, + mapaddr), + pci_unmap_len(sbq_desc, + maplen), + PCI_DMA_FROMDEVICE); + sbq_desc->p.skb = NULL; + } + } else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) { + if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "Header in small, %d bytes in large. Chain large to small!\n", length); + /* + * The data is in a single large buffer. We + * chain it to the header buffer's skb and let + * it rip. + */ + lbq_desc = ql_get_curr_lbuf(rx_ring); + pci_unmap_page(qdev->pdev, + pci_unmap_addr(lbq_desc, + mapaddr), + pci_unmap_len(lbq_desc, maplen), + PCI_DMA_FROMDEVICE); + QPRINTK(qdev, RX_STATUS, DEBUG, + "Chaining page to skb.\n"); + skb_fill_page_desc(skb, 0, lbq_desc->p.lbq_page, + 0, length); + skb->len += length; + skb->data_len += length; + skb->truesize += length; + lbq_desc->p.lbq_page = NULL; + } else { + /* + * The headers and data are in a single large buffer. We + * copy it to a new skb and let it go. This can happen with + * jumbo mtu on a non-TCP/UDP frame. + */ + lbq_desc = ql_get_curr_lbuf(rx_ring); + skb = netdev_alloc_skb(qdev->ndev, length); + if (skb == NULL) { + QPRINTK(qdev, PROBE, DEBUG, + "No skb available, drop the packet.\n"); + return NULL; + } + skb_reserve(skb, NET_IP_ALIGN); + QPRINTK(qdev, RX_STATUS, DEBUG, + "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", length); + skb_fill_page_desc(skb, 0, lbq_desc->p.lbq_page, + 0, length); + skb->len += length; + skb->data_len += length; + skb->truesize += length; + length -= length; + lbq_desc->p.lbq_page = NULL; + __pskb_pull_tail(skb, + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? + VLAN_ETH_HLEN : ETH_HLEN); + } + } else { + /* + * The data is in a chain of large buffers + * pointed to by a small buffer. We loop + * thru and chain them to the our small header + * buffer's skb. + * frags: There are 18 max frags and our small + * buffer will hold 32 of them. The thing is, + * we'll use 3 max for our 9000 byte jumbo + * frames. If the MTU goes up we could + * eventually be in trouble. + */ + int size, offset, i = 0; + struct bq_element *bq, bq_array[8]; + sbq_desc = ql_get_curr_sbuf(rx_ring); + pci_unmap_single(qdev->pdev, + pci_unmap_addr(sbq_desc, mapaddr), + pci_unmap_len(sbq_desc, maplen), + PCI_DMA_FROMDEVICE); + if (!(ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS)) { + /* + * This is an non TCP/UDP IP frame, so + * the headers aren't split into a small + * buffer. We have to use the small buffer + * that contains our sg list as our skb to + * send upstairs. Copy the sg list here to + * a local buffer and use it to find the + * pages to chain. + */ + QPRINTK(qdev, RX_STATUS, DEBUG, + "%d bytes of headers & data in chain of large.\n", length); + skb = sbq_desc->p.skb; + bq = &bq_array[0]; + memcpy(bq, skb->data, sizeof(bq_array)); + sbq_desc->p.skb = NULL; + skb_reserve(skb, NET_IP_ALIGN); + } else { + QPRINTK(qdev, RX_STATUS, DEBUG, + "Headers in small, %d bytes of data in chain of large.\n", length); + bq = (struct bq_element *)sbq_desc->p.skb->data; + } + while (length > 0) { + lbq_desc = ql_get_curr_lbuf(rx_ring); + if ((bq->addr_lo & ~BQ_MASK) != lbq_desc->bq->addr_lo) { + QPRINTK(qdev, RX_STATUS, ERR, + "Panic!!! bad large buffer address, expected 0x%.08x, got 0x%.08x.\n", + lbq_desc->bq->addr_lo, bq->addr_lo); + return NULL; + } + pci_unmap_page(qdev->pdev, + pci_unmap_addr(lbq_desc, + mapaddr), + pci_unmap_len(lbq_desc, + maplen), + PCI_DMA_FROMDEVICE); + size = (length < PAGE_SIZE) ? length : PAGE_SIZE; + offset = 0; + + QPRINTK(qdev, RX_STATUS, DEBUG, + "Adding page %d to skb for %d bytes.\n", + i, size); + skb_fill_page_desc(skb, i, lbq_desc->p.lbq_page, + offset, size); + skb->len += size; + skb->data_len += size; + skb->truesize += size; + length -= size; + lbq_desc->p.lbq_page = NULL; + bq++; + i++; + } + __pskb_pull_tail(skb, (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? + VLAN_ETH_HLEN : ETH_HLEN); + } + return skb; +} + +/* Process an inbound completion from an rx ring. */ +static void ql_process_mac_rx_intr(struct ql_adapter *qdev, + struct rx_ring *rx_ring, + struct ib_mac_iocb_rsp *ib_mac_rsp) +{ + struct net_device *ndev = qdev->ndev; + struct sk_buff *skb = NULL; + + QL_DUMP_IB_MAC_RSP(ib_mac_rsp); + + skb = ql_build_rx_skb(qdev, rx_ring, ib_mac_rsp); + if (unlikely(!skb)) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "No skb available, drop packet.\n"); + return; + } + + prefetch(skb->data); + skb->dev = ndev; + if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) { + QPRINTK(qdev, RX_STATUS, DEBUG, "%s%s%s Multicast.\n", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_REG ? "Registered" : "", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : ""); + } + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) { + QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n"); + } + if (ib_mac_rsp->flags1 & (IB_MAC_IOCB_RSP_IE | IB_MAC_IOCB_RSP_TE)) { + QPRINTK(qdev, RX_STATUS, ERR, + "Bad checksum for this %s packet.\n", + ((ib_mac_rsp-> + flags2 & IB_MAC_IOCB_RSP_T) ? "TCP" : "UDP")); + skb->ip_summed = CHECKSUM_NONE; + } else if (qdev->rx_csum && + ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) || + ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && + !(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_NU)))) { + QPRINTK(qdev, RX_STATUS, DEBUG, "RX checksum done!\n"); + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + qdev->stats.rx_packets++; + qdev->stats.rx_bytes += skb->len; + skb->protocol = eth_type_trans(skb, ndev); + if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "Passing a VLAN packet upstream.\n"); + vlan_hwaccel_rx(skb, qdev->vlgrp, + le16_to_cpu(ib_mac_rsp->vlan_id)); + } else { + QPRINTK(qdev, RX_STATUS, DEBUG, + "Passing a normal packet upstream.\n"); + netif_rx(skb); + } + ndev->last_rx = jiffies; +} + +/* Process an outbound completion from an rx ring. */ +static void ql_process_mac_tx_intr(struct ql_adapter *qdev, + struct ob_mac_iocb_rsp *mac_rsp) +{ + struct tx_ring *tx_ring; + struct tx_ring_desc *tx_ring_desc; + + QL_DUMP_OB_MAC_RSP(mac_rsp); + tx_ring = &qdev->tx_ring[mac_rsp->txq_idx]; + tx_ring_desc = &tx_ring->q[mac_rsp->tid]; + ql_unmap_send(qdev, tx_ring_desc, tx_ring_desc->map_cnt); + qdev->stats.tx_bytes += tx_ring_desc->map_cnt; + qdev->stats.tx_packets++; + dev_kfree_skb(tx_ring_desc->skb); + tx_ring_desc->skb = NULL; + + if (unlikely(mac_rsp->flags1 & (OB_MAC_IOCB_RSP_E | + OB_MAC_IOCB_RSP_S | + OB_MAC_IOCB_RSP_L | + OB_MAC_IOCB_RSP_P | OB_MAC_IOCB_RSP_B))) { + if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_E) { + QPRINTK(qdev, TX_DONE, WARNING, + "Total descriptor length did not match transfer length.\n"); + } + if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_S) { + QPRINTK(qdev, TX_DONE, WARNING, + "Frame too short to be legal, not sent.\n"); + } + if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_L) { + QPRINTK(qdev, TX_DONE, WARNING, + "Frame too long, but sent anyway.\n"); + } + if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_B) { + QPRINTK(qdev, TX_DONE, WARNING, + "PCI backplane error. Frame not sent.\n"); + } + } + atomic_inc(&tx_ring->tx_count); +} + +/* Fire up a handler to reset the MPI processor. */ +void ql_queue_fw_error(struct ql_adapter *qdev) +{ + netif_stop_queue(qdev->ndev); + netif_carrier_off(qdev->ndev); + queue_delayed_work(qdev->workqueue, &qdev->mpi_reset_work, 0); +} + +void ql_queue_asic_error(struct ql_adapter *qdev) +{ + netif_stop_queue(qdev->ndev); + netif_carrier_off(qdev->ndev); + ql_disable_interrupts(qdev); + queue_delayed_work(qdev->workqueue, &qdev->asic_reset_work, 0); +} + +static void ql_process_chip_ae_intr(struct ql_adapter *qdev, + struct ib_ae_iocb_rsp *ib_ae_rsp) +{ + switch (ib_ae_rsp->event) { + case MGMT_ERR_EVENT: + QPRINTK(qdev, RX_ERR, ERR, + "Management Processor Fatal Error.\n"); + ql_queue_fw_error(qdev); + return; + + case CAM_LOOKUP_ERR_EVENT: + QPRINTK(qdev, LINK, ERR, + "Multiple CAM hits lookup occurred.\n"); + QPRINTK(qdev, DRV, ERR, "This event shouldn't occur.\n"); + ql_queue_asic_error(qdev); + return; + + case SOFT_ECC_ERROR_EVENT: + QPRINTK(qdev, RX_ERR, ERR, "Soft ECC error detected.\n"); + ql_queue_asic_error(qdev); + break; + + case PCI_ERR_ANON_BUF_RD: + QPRINTK(qdev, RX_ERR, ERR, + "PCI error occurred when reading anonymous buffers from rx_ring %d.\n", + ib_ae_rsp->q_id); + ql_queue_asic_error(qdev); + break; + + default: + QPRINTK(qdev, DRV, ERR, "Unexpected event %d.\n", + ib_ae_rsp->event); + ql_queue_asic_error(qdev); + break; + } +} + +static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring) +{ + struct ql_adapter *qdev = rx_ring->qdev; + u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg); + struct ob_mac_iocb_rsp *net_rsp = NULL; + int count = 0; + + /* While there are entries in the completion queue. */ + while (prod != rx_ring->cnsmr_idx) { + + QPRINTK(qdev, RX_STATUS, DEBUG, + "cq_id = %d, prod = %d, cnsmr = %d.\n.", rx_ring->cq_id, + prod, rx_ring->cnsmr_idx); + + net_rsp = (struct ob_mac_iocb_rsp *)rx_ring->curr_entry; + rmb(); + switch (net_rsp->opcode) { + + case OPCODE_OB_MAC_TSO_IOCB: + case OPCODE_OB_MAC_IOCB: + ql_process_mac_tx_intr(qdev, net_rsp); + break; + default: + QPRINTK(qdev, RX_STATUS, DEBUG, + "Hit default case, not handled! dropping the packet, opcode = %x.\n", + net_rsp->opcode); + } + count++; + ql_update_cq(rx_ring); + prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg); + } + ql_write_cq_idx(rx_ring); + if (netif_queue_stopped(qdev->ndev) && net_rsp != NULL) { + struct tx_ring *tx_ring = &qdev->tx_ring[net_rsp->txq_idx]; + if (atomic_read(&tx_ring->queue_stopped) && + (atomic_read(&tx_ring->tx_count) > (tx_ring->wq_len / 4))) + /* + * The queue got stopped because the tx_ring was full. + * Wake it up, because it's now at least 25% empty. + */ + netif_wake_queue(qdev->ndev); + } + + return count; +} + +static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget) +{ + struct ql_adapter *qdev = rx_ring->qdev; + u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg); + struct ql_net_rsp_iocb *net_rsp; + int count = 0; + + /* While there are entries in the completion queue. */ + while (prod != rx_ring->cnsmr_idx) { + + QPRINTK(qdev, RX_STATUS, DEBUG, + "cq_id = %d, prod = %d, cnsmr = %d.\n.", rx_ring->cq_id, + prod, rx_ring->cnsmr_idx); + + net_rsp = rx_ring->curr_entry; + rmb(); + switch (net_rsp->opcode) { + case OPCODE_IB_MAC_IOCB: + ql_process_mac_rx_intr(qdev, rx_ring, + (struct ib_mac_iocb_rsp *) + net_rsp); + break; + + case OPCODE_IB_AE_IOCB: + ql_process_chip_ae_intr(qdev, (struct ib_ae_iocb_rsp *) + net_rsp); + break; + default: + { + QPRINTK(qdev, RX_STATUS, DEBUG, + "Hit default case, not handled! dropping the packet, opcode = %x.\n", + net_rsp->opcode); + } + } + count++; + ql_update_cq(rx_ring); + prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg); + if (count == budget) + break; + } + ql_update_buffer_queues(qdev, rx_ring); + ql_write_cq_idx(rx_ring); + return count; +} + +static int ql_napi_poll_msix(struct napi_struct *napi, int budget) +{ + struct rx_ring *rx_ring = container_of(napi, struct rx_ring, napi); + struct ql_adapter *qdev = rx_ring->qdev; + int work_done = ql_clean_inbound_rx_ring(rx_ring, budget); + + QPRINTK(qdev, RX_STATUS, DEBUG, "Enter, NAPI POLL cq_id = %d.\n", + rx_ring->cq_id); + + if (work_done < budget) { + __netif_rx_complete(qdev->ndev, napi); + ql_enable_completion_interrupt(qdev, rx_ring->irq); + } + return work_done; +} + +static void ql_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + + qdev->vlgrp = grp; + if (grp) { + QPRINTK(qdev, IFUP, DEBUG, "Turning on VLAN in NIC_RCV_CFG.\n"); + ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK | + NIC_RCV_CFG_VLAN_MATCH_AND_NON); + } else { + QPRINTK(qdev, IFUP, DEBUG, + "Turning off VLAN in NIC_RCV_CFG.\n"); + ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK); + } +} + +static void ql_vlan_rx_add_vid(struct net_device *ndev, u16 vid) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + u32 enable_bit = MAC_ADDR_E; + + spin_lock(&qdev->hw_lock); + if (ql_set_mac_addr_reg + (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) { + QPRINTK(qdev, IFUP, ERR, "Failed to init vlan address.\n"); + } + spin_unlock(&qdev->hw_lock); +} + +static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + u32 enable_bit = 0; + + spin_lock(&qdev->hw_lock); + if (ql_set_mac_addr_reg + (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) { + QPRINTK(qdev, IFUP, ERR, "Failed to clear vlan address.\n"); + } + spin_unlock(&qdev->hw_lock); + +} + +/* Worker thread to process a given rx_ring that is dedicated + * to outbound completions. + */ +static void ql_tx_clean(struct work_struct *work) +{ + struct rx_ring *rx_ring = + container_of(work, struct rx_ring, rx_work.work); + ql_clean_outbound_rx_ring(rx_ring); + ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq); + +} + +/* Worker thread to process a given rx_ring that is dedicated + * to inbound completions. + */ +static void ql_rx_clean(struct work_struct *work) +{ + struct rx_ring *rx_ring = + container_of(work, struct rx_ring, rx_work.work); + ql_clean_inbound_rx_ring(rx_ring, 64); + ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq); +} + +/* MSI-X Multiple Vector Interrupt Handler for outbound completions. */ +static irqreturn_t qlge_msix_tx_isr(int irq, void *dev_id) +{ + struct rx_ring *rx_ring = dev_id; + queue_delayed_work_on(rx_ring->cpu, rx_ring->qdev->q_workqueue, + &rx_ring->rx_work, 0); + return IRQ_HANDLED; +} + +/* MSI-X Multiple Vector Interrupt Handler for inbound completions. */ +static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id) +{ + struct rx_ring *rx_ring = dev_id; + struct ql_adapter *qdev = rx_ring->qdev; + netif_rx_schedule(qdev->ndev, &rx_ring->napi); + return IRQ_HANDLED; +} + +/* We check here to see if we're already handling a legacy + * interrupt. If we are, then it must belong to another + * chip with which we're sharing the interrupt line. + */ +int ql_legacy_check(struct ql_adapter *qdev) +{ + int err; + spin_lock(&qdev->legacy_lock); + err = atomic_read(&qdev->intr_context[0].irq_cnt); + spin_unlock(&qdev->legacy_lock); + return err; +} + +/* This handles a fatal error, MPI activity, and the default + * rx_ring in an MSI-X multiple vector environment. + * In MSI/Legacy environment it also process the rest of + * the rx_rings. + */ +static irqreturn_t qlge_isr(int irq, void *dev_id) +{ + struct rx_ring *rx_ring = dev_id; + struct ql_adapter *qdev = rx_ring->qdev; + struct intr_context *intr_context = &qdev->intr_context[0]; + u32 var; + int i; + int work_done = 0; + + if (qdev->legacy_check && qdev->legacy_check(qdev)) { + QPRINTK(qdev, INTR, INFO, "Already busy, not our interrupt.\n"); + return IRQ_NONE; /* Not our interrupt */ + } + + var = ql_read32(qdev, STS); + + /* + * Check for fatal error. + */ + if (var & STS_FE) { + ql_queue_asic_error(qdev); + QPRINTK(qdev, INTR, ERR, "Got fatal error, STS = %x.\n", var); + var = ql_read32(qdev, ERR_STS); + QPRINTK(qdev, INTR, ERR, + "Resetting chip. Error Status Register = 0x%x\n", var); + return IRQ_HANDLED; + } + + /* + * Check MPI processor activity. + */ + if (var & STS_PI) { + /* + * We've got an async event or mailbox completion. + * Handle it and clear the source of the interrupt. + */ + QPRINTK(qdev, INTR, ERR, "Got MPI processor interrupt.\n"); + ql_disable_completion_interrupt(qdev, intr_context->intr); + queue_delayed_work_on(smp_processor_id(), qdev->workqueue, + &qdev->mpi_work, 0); + work_done++; + } + + /* + * Check the default queue and wake handler if active. + */ + rx_ring = &qdev->rx_ring[0]; + if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) { + QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[0].\n"); + ql_disable_completion_interrupt(qdev, intr_context->intr); + queue_delayed_work_on(smp_processor_id(), qdev->q_workqueue, + &rx_ring->rx_work, 0); + work_done++; + } + + if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) { + /* + * Start the DPC for each active queue. + */ + for (i = 1; i < qdev->rx_ring_count; i++) { + rx_ring = &qdev->rx_ring[i]; + if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != + rx_ring->cnsmr_idx) { + QPRINTK(qdev, INTR, INFO, + "Waking handler for rx_ring[%d].\n", i); + ql_disable_completion_interrupt(qdev, + intr_context-> + intr); + if (i < qdev->rss_ring_first_cq_id) + queue_delayed_work_on(rx_ring->cpu, + qdev->q_workqueue, + &rx_ring->rx_work, + 0); + else + netif_rx_schedule(qdev->ndev, + &rx_ring->napi); + work_done++; + } + } + } + return work_done ? IRQ_HANDLED : IRQ_NONE; +} + +static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr) +{ + + if (skb_is_gso(skb)) { + int err; + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) + return err; + } + + mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB; + mac_iocb_ptr->flags3 |= OB_MAC_TSO_IOCB_IC; + mac_iocb_ptr->frame_len = cpu_to_le32((u32) skb->len); + mac_iocb_ptr->total_hdrs_len = + cpu_to_le16(skb_transport_offset(skb) + tcp_hdrlen(skb)); + mac_iocb_ptr->net_trans_offset = + cpu_to_le16(skb_network_offset(skb) | + skb_transport_offset(skb) + << OB_MAC_TRANSPORT_HDR_SHIFT); + mac_iocb_ptr->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); + mac_iocb_ptr->flags2 |= OB_MAC_TSO_IOCB_LSO; + if (likely(skb->protocol == htons(ETH_P_IP))) { + struct iphdr *iph = ip_hdr(skb); + iph->check = 0; + mac_iocb_ptr->flags1 |= OB_MAC_TSO_IOCB_IP4; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, + 0); + } else if (skb->protocol == htons(ETH_P_IPV6)) { + mac_iocb_ptr->flags1 |= OB_MAC_TSO_IOCB_IP6; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0); + } + return 1; + } + return 0; +} + +static void ql_hw_csum_setup(struct sk_buff *skb, + struct ob_mac_tso_iocb_req *mac_iocb_ptr) +{ + int len; + struct iphdr *iph = ip_hdr(skb); + u16 *check; + mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB; + mac_iocb_ptr->frame_len = cpu_to_le32((u32) skb->len); + mac_iocb_ptr->net_trans_offset = + cpu_to_le16(skb_network_offset(skb) | + skb_transport_offset(skb) << OB_MAC_TRANSPORT_HDR_SHIFT); + + mac_iocb_ptr->flags1 |= OB_MAC_TSO_IOCB_IP4; + len = (ntohs(iph->tot_len) - (iph->ihl << 2)); + if (likely(iph->protocol == IPPROTO_TCP)) { + check = &(tcp_hdr(skb)->check); + mac_iocb_ptr->flags2 |= OB_MAC_TSO_IOCB_TC; + mac_iocb_ptr->total_hdrs_len = + cpu_to_le16(skb_transport_offset(skb) + + (tcp_hdr(skb)->doff << 2)); + } else { + check = &(udp_hdr(skb)->check); + mac_iocb_ptr->flags2 |= OB_MAC_TSO_IOCB_UC; + mac_iocb_ptr->total_hdrs_len = + cpu_to_le16(skb_transport_offset(skb) + + sizeof(struct udphdr)); + } + *check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, len, iph->protocol, 0); +} + +static int qlge_send(struct sk_buff *skb, struct net_device *ndev) +{ + struct tx_ring_desc *tx_ring_desc; + struct ob_mac_iocb_req *mac_iocb_ptr; + struct ql_adapter *qdev = netdev_priv(ndev); + int tso; + struct tx_ring *tx_ring; + u32 tx_ring_idx = (u32) QL_TXQ_IDX(qdev, skb); + + tx_ring = &qdev->tx_ring[tx_ring_idx]; + + if (unlikely(atomic_read(&tx_ring->tx_count) < 2)) { + QPRINTK(qdev, TX_QUEUED, INFO, + "%s: shutting down tx queue %d du to lack of resources.\n", + __func__, tx_ring_idx); + netif_stop_queue(ndev); + atomic_inc(&tx_ring->queue_stopped); + return NETDEV_TX_BUSY; + } + tx_ring_desc = &tx_ring->q[tx_ring->prod_idx]; + mac_iocb_ptr = tx_ring_desc->queue_entry; + memset((void *)mac_iocb_ptr, 0, sizeof(mac_iocb_ptr)); + if (ql_map_send(qdev, mac_iocb_ptr, skb, tx_ring_desc) != NETDEV_TX_OK) { + QPRINTK(qdev, TX_QUEUED, ERR, "Could not map the segments.\n"); + return NETDEV_TX_BUSY; + } + + mac_iocb_ptr->opcode = OPCODE_OB_MAC_IOCB; + mac_iocb_ptr->tid = tx_ring_desc->index; + /* We use the upper 32-bits to store the tx queue for this IO. + * When we get the completion we can use it to establish the context. + */ + mac_iocb_ptr->txq_idx = tx_ring_idx; + tx_ring_desc->skb = skb; + + mac_iocb_ptr->frame_len = cpu_to_le16((u16) skb->len); + + if (qdev->vlgrp && vlan_tx_tag_present(skb)) { + QPRINTK(qdev, TX_QUEUED, DEBUG, "Adding a vlan tag %d.\n", + vlan_tx_tag_get(skb)); + mac_iocb_ptr->flags3 |= OB_MAC_IOCB_V; + mac_iocb_ptr->vlan_tci = cpu_to_le16(vlan_tx_tag_get(skb)); + } + tso = ql_tso(skb, (struct ob_mac_tso_iocb_req *)mac_iocb_ptr); + if (tso < 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } else if (unlikely(!tso) && (skb->ip_summed == CHECKSUM_PARTIAL)) { + ql_hw_csum_setup(skb, + (struct ob_mac_tso_iocb_req *)mac_iocb_ptr); + } + QL_DUMP_OB_MAC_IOCB(mac_iocb_ptr); + tx_ring->prod_idx++; + if (tx_ring->prod_idx == tx_ring->wq_len) + tx_ring->prod_idx = 0; + wmb(); + + ql_write_db_reg(tx_ring->prod_idx, tx_ring->prod_idx_db_reg); + ndev->trans_start = jiffies; + QPRINTK(qdev, TX_QUEUED, DEBUG, "tx queued, slot %d, len %d\n", + tx_ring->prod_idx, skb->len); + + atomic_dec(&tx_ring->tx_count); + return NETDEV_TX_OK; +} + +static void ql_free_shadow_space(struct ql_adapter *qdev) +{ + if (qdev->rx_ring_shadow_reg_area) { + pci_free_consistent(qdev->pdev, + PAGE_SIZE, + qdev->rx_ring_shadow_reg_area, + qdev->rx_ring_shadow_reg_dma); + qdev->rx_ring_shadow_reg_area = NULL; + } + if (qdev->tx_ring_shadow_reg_area) { + pci_free_consistent(qdev->pdev, + PAGE_SIZE, + qdev->tx_ring_shadow_reg_area, + qdev->tx_ring_shadow_reg_dma); + qdev->tx_ring_shadow_reg_area = NULL; + } +} + +static int ql_alloc_shadow_space(struct ql_adapter *qdev) +{ + qdev->rx_ring_shadow_reg_area = + pci_alloc_consistent(qdev->pdev, + PAGE_SIZE, &qdev->rx_ring_shadow_reg_dma); + if (qdev->rx_ring_shadow_reg_area == NULL) { + QPRINTK(qdev, IFUP, ERR, + "Allocation of RX shadow space failed.\n"); + return -ENOMEM; + } + qdev->tx_ring_shadow_reg_area = + pci_alloc_consistent(qdev->pdev, PAGE_SIZE, + &qdev->tx_ring_shadow_reg_dma); + if (qdev->tx_ring_shadow_reg_area == NULL) { + QPRINTK(qdev, IFUP, ERR, + "Allocation of TX shadow space failed.\n"); + goto err_wqp_sh_area; + } + return 0; + +err_wqp_sh_area: + pci_free_consistent(qdev->pdev, + PAGE_SIZE, + qdev->rx_ring_shadow_reg_area, + qdev->rx_ring_shadow_reg_dma); + return -ENOMEM; +} + +static void ql_init_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring) +{ + struct tx_ring_desc *tx_ring_desc; + int i; + struct ob_mac_iocb_req *mac_iocb_ptr; + + mac_iocb_ptr = tx_ring->wq_base; + tx_ring_desc = tx_ring->q; + for (i = 0; i < tx_ring->wq_len; i++) { + tx_ring_desc->index = i; + tx_ring_desc->skb = NULL; + tx_ring_desc->queue_entry = mac_iocb_ptr; + mac_iocb_ptr++; + tx_ring_desc++; + } + atomic_set(&tx_ring->tx_count, tx_ring->wq_len); + atomic_set(&tx_ring->queue_stopped, 0); +} + +static void ql_free_tx_resources(struct ql_adapter *qdev, + struct tx_ring *tx_ring) +{ + if (tx_ring->wq_base) { + pci_free_consistent(qdev->pdev, tx_ring->wq_size, + tx_ring->wq_base, tx_ring->wq_base_dma); + tx_ring->wq_base = NULL; + } + kfree(tx_ring->q); + tx_ring->q = NULL; +} + +static int ql_alloc_tx_resources(struct ql_adapter *qdev, + struct tx_ring *tx_ring) +{ + tx_ring->wq_base = + pci_alloc_consistent(qdev->pdev, tx_ring->wq_size, + &tx_ring->wq_base_dma); + + if ((tx_ring->wq_base == NULL) + || tx_ring->wq_base_dma & (tx_ring->wq_size - 1)) { + QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n"); + return -ENOMEM; + } + tx_ring->q = + kmalloc(tx_ring->wq_len * sizeof(struct tx_ring_desc), GFP_KERNEL); + if (tx_ring->q == NULL) + goto err; + + return 0; +err: + pci_free_consistent(qdev->pdev, tx_ring->wq_size, + tx_ring->wq_base, tx_ring->wq_base_dma); + return -ENOMEM; +} + +void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) +{ + int i; + struct bq_desc *lbq_desc; + + for (i = 0; i < rx_ring->lbq_len; i++) { + lbq_desc = &rx_ring->lbq[i]; + if (lbq_desc->p.lbq_page) { + pci_unmap_page(qdev->pdev, + pci_unmap_addr(lbq_desc, mapaddr), + pci_unmap_len(lbq_desc, maplen), + PCI_DMA_FROMDEVICE); + + put_page(lbq_desc->p.lbq_page); + lbq_desc->p.lbq_page = NULL; + } + lbq_desc->bq->addr_lo = 0; + lbq_desc->bq->addr_hi = 0; + } +} + +/* + * Allocate and map a page for each element of the lbq. + */ +static int ql_alloc_lbq_buffers(struct ql_adapter *qdev, + struct rx_ring *rx_ring) +{ + int i; + struct bq_desc *lbq_desc; + u64 map; + struct bq_element *bq = rx_ring->lbq_base; + + for (i = 0; i < rx_ring->lbq_len; i++) { + lbq_desc = &rx_ring->lbq[i]; + memset(lbq_desc, 0, sizeof(lbq_desc)); + lbq_desc->bq = bq; + lbq_desc->index = i; + lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC); + if (unlikely(!lbq_desc->p.lbq_page)) { + QPRINTK(qdev, IFUP, ERR, "failed alloc_page().\n"); + goto mem_error; + } else { + map = pci_map_page(qdev->pdev, + lbq_desc->p.lbq_page, + 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(qdev->pdev, map)) { + QPRINTK(qdev, IFUP, ERR, + "PCI mapping failed.\n"); + goto mem_error; + } + pci_unmap_addr_set(lbq_desc, mapaddr, map); + pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE); + bq->addr_lo = cpu_to_le32(map); + bq->addr_hi = cpu_to_le32(map >> 32); + } + bq++; + } + return 0; +mem_error: + ql_free_lbq_buffers(qdev, rx_ring); + return -ENOMEM; +} + +void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) +{ + int i; + struct bq_desc *sbq_desc; + + for (i = 0; i < rx_ring->sbq_len; i++) { + sbq_desc = &rx_ring->sbq[i]; + if (sbq_desc == NULL) { + QPRINTK(qdev, IFUP, ERR, "sbq_desc %d is NULL.\n", i); + return; + } + if (sbq_desc->p.skb) { + pci_unmap_single(qdev->pdev, + pci_unmap_addr(sbq_desc, mapaddr), + pci_unmap_len(sbq_desc, maplen), + PCI_DMA_FROMDEVICE); + dev_kfree_skb(sbq_desc->p.skb); + sbq_desc->p.skb = NULL; + } + if (sbq_desc->bq == NULL) { + QPRINTK(qdev, IFUP, ERR, "sbq_desc->bq %d is NULL.\n", + i); + return; + } + sbq_desc->bq->addr_lo = 0; + sbq_desc->bq->addr_hi = 0; + } +} + +/* Allocate and map an skb for each element of the sbq. */ +static int ql_alloc_sbq_buffers(struct ql_adapter *qdev, + struct rx_ring *rx_ring) +{ + int i; + struct bq_desc *sbq_desc; + struct sk_buff *skb; + u64 map; + struct bq_element *bq = rx_ring->sbq_base; + + for (i = 0; i < rx_ring->sbq_len; i++) { + sbq_desc = &rx_ring->sbq[i]; + memset(sbq_desc, 0, sizeof(sbq_desc)); + sbq_desc->index = i; + sbq_desc->bq = bq; + skb = netdev_alloc_skb(qdev->ndev, rx_ring->sbq_buf_size); + if (unlikely(!skb)) { + /* Better luck next round */ + QPRINTK(qdev, IFUP, ERR, + "small buff alloc failed for %d bytes at index %d.\n", + rx_ring->sbq_buf_size, i); + goto mem_err; + } + skb_reserve(skb, QLGE_SB_PAD); + sbq_desc->p.skb = skb; + /* + * Map only half the buffer. Because the + * other half may get some data copied to it + * when the completion arrives. + */ + map = pci_map_single(qdev->pdev, + skb->data, + rx_ring->sbq_buf_size / 2, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(qdev->pdev, map)) { + QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n"); + goto mem_err; + } + pci_unmap_addr_set(sbq_desc, mapaddr, map); + pci_unmap_len_set(sbq_desc, maplen, rx_ring->sbq_buf_size / 2); + bq->addr_lo = /*sbq_desc->addr_lo = */ + cpu_to_le32(map); + bq->addr_hi = /*sbq_desc->addr_hi = */ + cpu_to_le32(map >> 32); + bq++; + } + return 0; +mem_err: + ql_free_sbq_buffers(qdev, rx_ring); + return -ENOMEM; +} + +static void ql_free_rx_resources(struct ql_adapter *qdev, + struct rx_ring *rx_ring) +{ + if (rx_ring->sbq_len) + ql_free_sbq_buffers(qdev, rx_ring); + if (rx_ring->lbq_len) + ql_free_lbq_buffers(qdev, rx_ring); + + /* Free the small buffer queue. */ + if (rx_ring->sbq_base) { + pci_free_consistent(qdev->pdev, + rx_ring->sbq_size, + rx_ring->sbq_base, rx_ring->sbq_base_dma); + rx_ring->sbq_base = NULL; + } + + /* Free the small buffer queue control blocks. */ + kfree(rx_ring->sbq); + rx_ring->sbq = NULL; + + /* Free the large buffer queue. */ + if (rx_ring->lbq_base) { + pci_free_consistent(qdev->pdev, + rx_ring->lbq_size, + rx_ring->lbq_base, rx_ring->lbq_base_dma); + rx_ring->lbq_base = NULL; + } + + /* Free the large buffer queue control blocks. */ + kfree(rx_ring->lbq); + rx_ring->lbq = NULL; + + /* Free the rx queue. */ + if (rx_ring->cq_base) { + pci_free_consistent(qdev->pdev, + rx_ring->cq_size, + rx_ring->cq_base, rx_ring->cq_base_dma); + rx_ring->cq_base = NULL; + } +} + +/* Allocate queues and buffers for this completions queue based + * on the values in the parameter structure. */ +static int ql_alloc_rx_resources(struct ql_adapter *qdev, + struct rx_ring *rx_ring) +{ + + /* + * Allocate the completion queue for this rx_ring. + */ + rx_ring->cq_base = + pci_alloc_consistent(qdev->pdev, rx_ring->cq_size, + &rx_ring->cq_base_dma); + + if (rx_ring->cq_base == NULL) { + QPRINTK(qdev, IFUP, ERR, "rx_ring alloc failed.\n"); + return -ENOMEM; + } + + if (rx_ring->sbq_len) { + /* + * Allocate small buffer queue. + */ + rx_ring->sbq_base = + pci_alloc_consistent(qdev->pdev, rx_ring->sbq_size, + &rx_ring->sbq_base_dma); + + if (rx_ring->sbq_base == NULL) { + QPRINTK(qdev, IFUP, ERR, + "Small buffer queue allocation failed.\n"); + goto err_mem; + } + + /* + * Allocate small buffer queue control blocks. + */ + rx_ring->sbq = + kmalloc(rx_ring->sbq_len * sizeof(struct bq_desc), + GFP_KERNEL); + if (rx_ring->sbq == NULL) { + QPRINTK(qdev, IFUP, ERR, + "Small buffer queue control block allocation failed.\n"); + goto err_mem; + } + + if (ql_alloc_sbq_buffers(qdev, rx_ring)) { + QPRINTK(qdev, IFUP, ERR, + "Small buffer allocation failed.\n"); + goto err_mem; + } + } + + if (rx_ring->lbq_len) { + /* + * Allocate large buffer queue. + */ + rx_ring->lbq_base = + pci_alloc_consistent(qdev->pdev, rx_ring->lbq_size, + &rx_ring->lbq_base_dma); + + if (rx_ring->lbq_base == NULL) { + QPRINTK(qdev, IFUP, ERR, + "Large buffer queue allocation failed.\n"); + goto err_mem; + } + /* + * Allocate large buffer queue control blocks. + */ + rx_ring->lbq = + kmalloc(rx_ring->lbq_len * sizeof(struct bq_desc), + GFP_KERNEL); + if (rx_ring->lbq == NULL) { + QPRINTK(qdev, IFUP, ERR, + "Large buffer queue control block allocation failed.\n"); + goto err_mem; + } + + /* + * Allocate the buffers. + */ + if (ql_alloc_lbq_buffers(qdev, rx_ring)) { + QPRINTK(qdev, IFUP, ERR, + "Large buffer allocation failed.\n"); + goto err_mem; + } + } + + return 0; + +err_mem: + ql_free_rx_resources(qdev, rx_ring); + return -ENOMEM; +} + +static void ql_tx_ring_clean(struct ql_adapter *qdev) +{ + struct tx_ring *tx_ring; + struct tx_ring_desc *tx_ring_desc; + int i, j; + + /* + * Loop through all queues and free + * any resources. + */ + for (j = 0; j < qdev->tx_ring_count; j++) { + tx_ring = &qdev->tx_ring[j]; + for (i = 0; i < tx_ring->wq_len; i++) { + tx_ring_desc = &tx_ring->q[i]; + if (tx_ring_desc && tx_ring_desc->skb) { + QPRINTK(qdev, IFDOWN, ERR, + "Freeing lost SKB %p, from queue %d, index %d.\n", + tx_ring_desc->skb, j, + tx_ring_desc->index); + ql_unmap_send(qdev, tx_ring_desc, + tx_ring_desc->map_cnt); + dev_kfree_skb(tx_ring_desc->skb); + tx_ring_desc->skb = NULL; + } + } + } +} + +static void ql_free_ring_cb(struct ql_adapter *qdev) +{ + kfree(qdev->ring_mem); +} + +static int ql_alloc_ring_cb(struct ql_adapter *qdev) +{ + /* Allocate space for tx/rx ring control blocks. */ + qdev->ring_mem_size = + (qdev->tx_ring_count * sizeof(struct tx_ring)) + + (qdev->rx_ring_count * sizeof(struct rx_ring)); + qdev->ring_mem = kmalloc(qdev->ring_mem_size, GFP_KERNEL); + if (qdev->ring_mem == NULL) { + return -ENOMEM; + } else { + qdev->rx_ring = qdev->ring_mem; + qdev->tx_ring = qdev->ring_mem + + (qdev->rx_ring_count * sizeof(struct rx_ring)); + } + return 0; +} + +static void ql_free_mem_resources(struct ql_adapter *qdev) +{ + int i; + + for (i = 0; i < qdev->tx_ring_count; i++) + ql_free_tx_resources(qdev, &qdev->tx_ring[i]); + for (i = 0; i < qdev->rx_ring_count; i++) + ql_free_rx_resources(qdev, &qdev->rx_ring[i]); + ql_free_shadow_space(qdev); +} + +static int ql_alloc_mem_resources(struct ql_adapter *qdev) +{ + int i; + + /* Allocate space for our shadow registers and such. */ + if (ql_alloc_shadow_space(qdev)) + return -ENOMEM; + + for (i = 0; i < qdev->rx_ring_count; i++) { + if (ql_alloc_rx_resources(qdev, &qdev->rx_ring[i]) != 0) { + QPRINTK(qdev, IFUP, ERR, + "RX resource allocation failed.\n"); + goto err_mem; + } + } + /* Allocate tx queue resources */ + for (i = 0; i < qdev->tx_ring_count; i++) { + if (ql_alloc_tx_resources(qdev, &qdev->tx_ring[i]) != 0) { + QPRINTK(qdev, IFUP, ERR, + "TX resource allocation failed.\n"); + goto err_mem; + } + } + return 0; + +err_mem: + ql_free_mem_resources(qdev); + return -ENOMEM; +} + +/* Set up the rx ring control block and pass it to the chip. + * The control block is defined as + * "Completion Queue Initialization Control Block", or cqicb. + */ +static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) +{ + struct cqicb *cqicb = &rx_ring->cqicb; + void *shadow_reg = qdev->rx_ring_shadow_reg_area + + (rx_ring->cq_id * sizeof(u64) * 4); + u64 shadow_reg_dma = qdev->rx_ring_shadow_reg_dma + + (rx_ring->cq_id * sizeof(u64) * 4); + void __iomem *doorbell_area = + qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id)); + int err = 0; + u16 bq_len; + + /* Set up the shadow registers for this ring. */ + rx_ring->prod_idx_sh_reg = shadow_reg; + rx_ring->prod_idx_sh_reg_dma = shadow_reg_dma; + shadow_reg += sizeof(u64); + shadow_reg_dma += sizeof(u64); + rx_ring->lbq_base_indirect = shadow_reg; + rx_ring->lbq_base_indirect_dma = shadow_reg_dma; + shadow_reg += sizeof(u64); + shadow_reg_dma += sizeof(u64); + rx_ring->sbq_base_indirect = shadow_reg; + rx_ring->sbq_base_indirect_dma = shadow_reg_dma; + + /* PCI doorbell mem area + 0x00 for consumer index register */ + rx_ring->cnsmr_idx_db_reg = (u32 *) doorbell_area; + rx_ring->cnsmr_idx = 0; + rx_ring->curr_entry = rx_ring->cq_base; + + /* PCI doorbell mem area + 0x04 for valid register */ + rx_ring->valid_db_reg = doorbell_area + 0x04; + + /* PCI doorbell mem area + 0x18 for large buffer consumer */ + rx_ring->lbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x18); + + /* PCI doorbell mem area + 0x1c */ + rx_ring->sbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x1c); + + memset((void *)cqicb, 0, sizeof(struct cqicb)); + cqicb->msix_vect = rx_ring->irq; + + cqicb->len = cpu_to_le16(rx_ring->cq_len | LEN_V | LEN_CPP_CONT); + + cqicb->addr_lo = cpu_to_le32(rx_ring->cq_base_dma); + cqicb->addr_hi = cpu_to_le32((u64) rx_ring->cq_base_dma >> 32); + + cqicb->prod_idx_addr_lo = cpu_to_le32(rx_ring->prod_idx_sh_reg_dma); + cqicb->prod_idx_addr_hi = + cpu_to_le32((u64) rx_ring->prod_idx_sh_reg_dma >> 32); + + /* + * Set up the control block load flags. + */ + cqicb->flags = FLAGS_LC | /* Load queue base address */ + FLAGS_LV | /* Load MSI-X vector */ + FLAGS_LI; /* Load irq delay values */ + if (rx_ring->lbq_len) { + cqicb->flags |= FLAGS_LL; /* Load lbq values */ + *((u64 *) rx_ring->lbq_base_indirect) = rx_ring->lbq_base_dma; + cqicb->lbq_addr_lo = + cpu_to_le32(rx_ring->lbq_base_indirect_dma); + cqicb->lbq_addr_hi = + cpu_to_le32((u64) rx_ring->lbq_base_indirect_dma >> 32); + cqicb->lbq_buf_size = cpu_to_le32(rx_ring->lbq_buf_size); + bq_len = (u16) rx_ring->lbq_len; + cqicb->lbq_len = cpu_to_le16(bq_len); + rx_ring->lbq_prod_idx = rx_ring->lbq_len - 16; + rx_ring->lbq_curr_idx = 0; + rx_ring->lbq_clean_idx = rx_ring->lbq_prod_idx; + rx_ring->lbq_free_cnt = 16; + } + if (rx_ring->sbq_len) { + cqicb->flags |= FLAGS_LS; /* Load sbq values */ + *((u64 *) rx_ring->sbq_base_indirect) = rx_ring->sbq_base_dma; + cqicb->sbq_addr_lo = + cpu_to_le32(rx_ring->sbq_base_indirect_dma); + cqicb->sbq_addr_hi = + cpu_to_le32((u64) rx_ring->sbq_base_indirect_dma >> 32); + cqicb->sbq_buf_size = + cpu_to_le16(((rx_ring->sbq_buf_size / 2) + 8) & 0xfffffff8); + bq_len = (u16) rx_ring->sbq_len; + cqicb->sbq_len = cpu_to_le16(bq_len); + rx_ring->sbq_prod_idx = rx_ring->sbq_len - 16; + rx_ring->sbq_curr_idx = 0; + rx_ring->sbq_clean_idx = rx_ring->sbq_prod_idx; + rx_ring->sbq_free_cnt = 16; + } + switch (rx_ring->type) { + case TX_Q: + /* If there's only one interrupt, then we use + * worker threads to process the outbound + * completion handling rx_rings. We do this so + * they can be run on multiple CPUs. There is + * room to play with this more where we would only + * run in a worker if there are more than x number + * of outbound completions on the queue and more + * than one queue active. Some threshold that + * would indicate a benefit in spite of the cost + * of a context switch. + * If there's more than one interrupt, then the + * outbound completions are processed in the ISR. + */ + if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) + INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean); + else { + /* With all debug warnings on we see a WARN_ON message + * when we free the skb in the interrupt context. + */ + INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean); + } + cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs); + cqicb->pkt_delay = cpu_to_le16(qdev->tx_max_coalesced_frames); + break; + case DEFAULT_Q: + INIT_DELAYED_WORK(&rx_ring->rx_work, ql_rx_clean); + cqicb->irq_delay = 0; + cqicb->pkt_delay = 0; + break; + case RX_Q: + /* Inbound completion handling rx_rings run in + * separate NAPI contexts. + */ + netif_napi_add(qdev->ndev, &rx_ring->napi, ql_napi_poll_msix, + 64); + cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs); + cqicb->pkt_delay = cpu_to_le16(qdev->rx_max_coalesced_frames); + break; + default: + QPRINTK(qdev, IFUP, DEBUG, "Invalid rx_ring->type = %d.\n", + rx_ring->type); + } + QPRINTK(qdev, IFUP, INFO, "Initializing rx work queue.\n"); + err = ql_write_cfg(qdev, cqicb, sizeof(struct cqicb), + CFG_LCQ, rx_ring->cq_id); + if (err) { + QPRINTK(qdev, IFUP, ERR, "Failed to load CQICB.\n"); + return err; + } + QPRINTK(qdev, IFUP, INFO, "Successfully loaded CQICB.\n"); + /* + * Advance the producer index for the buffer queues. + */ + wmb(); + if (rx_ring->lbq_len) + ql_write_db_reg(rx_ring->lbq_prod_idx, + rx_ring->lbq_prod_idx_db_reg); + if (rx_ring->sbq_len) + ql_write_db_reg(rx_ring->sbq_prod_idx, + rx_ring->sbq_prod_idx_db_reg); + return err; +} + +static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring) +{ + struct wqicb *wqicb = (struct wqicb *)tx_ring; + void __iomem *doorbell_area = + qdev->doorbell_area + (DB_PAGE_SIZE * tx_ring->wq_id); + void *shadow_reg = qdev->tx_ring_shadow_reg_area + + (tx_ring->wq_id * sizeof(u64)); + u64 shadow_reg_dma = qdev->tx_ring_shadow_reg_dma + + (tx_ring->wq_id * sizeof(u64)); + int err = 0; + + /* + * Assign doorbell registers for this tx_ring. + */ + /* TX PCI doorbell mem area for tx producer index */ + tx_ring->prod_idx_db_reg = (u32 *) doorbell_area; + tx_ring->prod_idx = 0; + /* TX PCI doorbell mem area + 0x04 */ + tx_ring->valid_db_reg = doorbell_area + 0x04; + + /* + * Assign shadow registers for this tx_ring. + */ + tx_ring->cnsmr_idx_sh_reg = shadow_reg; + tx_ring->cnsmr_idx_sh_reg_dma = shadow_reg_dma; + + wqicb->len = cpu_to_le16(tx_ring->wq_len | Q_LEN_V | Q_LEN_CPP_CONT); + wqicb->flags = cpu_to_le16(Q_FLAGS_LC | + Q_FLAGS_LB | Q_FLAGS_LI | Q_FLAGS_LO); + wqicb->cq_id_rss = cpu_to_le16(tx_ring->cq_id); + wqicb->rid = 0; + wqicb->addr_lo = cpu_to_le32(tx_ring->wq_base_dma); + wqicb->addr_hi = cpu_to_le32((u64) tx_ring->wq_base_dma >> 32); + + wqicb->cnsmr_idx_addr_lo = cpu_to_le32(tx_ring->cnsmr_idx_sh_reg_dma); + wqicb->cnsmr_idx_addr_hi = + cpu_to_le32((u64) tx_ring->cnsmr_idx_sh_reg_dma >> 32); + + ql_init_tx_ring(qdev, tx_ring); + + err = ql_write_cfg(qdev, wqicb, sizeof(wqicb), CFG_LRQ, + (u16) tx_ring->wq_id); + if (err) { + QPRINTK(qdev, IFUP, ERR, "Failed to load tx_ring.\n"); + return err; + } + QPRINTK(qdev, IFUP, INFO, "Successfully loaded WQICB.\n"); + return err; +} + +static void ql_disable_msix(struct ql_adapter *qdev) +{ + if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) { + pci_disable_msix(qdev->pdev); + clear_bit(QL_MSIX_ENABLED, &qdev->flags); + kfree(qdev->msi_x_entry); + qdev->msi_x_entry = NULL; + } else if (test_bit(QL_MSI_ENABLED, &qdev->flags)) { + pci_disable_msi(qdev->pdev); + clear_bit(QL_MSI_ENABLED, &qdev->flags); + } +} + +static void ql_enable_msix(struct ql_adapter *qdev) +{ + int i; + + qdev->intr_count = 1; + /* Get the MSIX vectors. */ + if (irq_type == MSIX_IRQ) { + /* Try to alloc space for the msix struct, + * if it fails then go to MSI/legacy. + */ + qdev->msi_x_entry = kcalloc(qdev->rx_ring_count, + sizeof(struct msix_entry), + GFP_KERNEL); + if (!qdev->msi_x_entry) { + irq_type = MSI_IRQ; + goto msi; + } + + for (i = 0; i < qdev->rx_ring_count; i++) + qdev->msi_x_entry[i].entry = i; + + if (!pci_enable_msix + (qdev->pdev, qdev->msi_x_entry, qdev->rx_ring_count)) { + set_bit(QL_MSIX_ENABLED, &qdev->flags); + qdev->intr_count = qdev->rx_ring_count; + QPRINTK(qdev, IFUP, INFO, + "MSI-X Enabled, got %d vectors.\n", + qdev->intr_count); + return; + } else { + kfree(qdev->msi_x_entry); + qdev->msi_x_entry = NULL; + QPRINTK(qdev, IFUP, WARNING, + "MSI-X Enable failed, trying MSI.\n"); + irq_type = MSI_IRQ; + } + } +msi: + if (irq_type == MSI_IRQ) { + if (!pci_enable_msi(qdev->pdev)) { + set_bit(QL_MSI_ENABLED, &qdev->flags); + QPRINTK(qdev, IFUP, INFO, + "Running with MSI interrupts.\n"); + return; + } + } + irq_type = LEG_IRQ; + spin_lock_init(&qdev->legacy_lock); + qdev->legacy_check = ql_legacy_check; + QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n"); +} + +/* + * Here we build the intr_context structures based on + * our rx_ring count and intr vector count. + * The intr_context structure is used to hook each vector + * to possibly different handlers. + */ +static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) +{ + int i = 0; + struct intr_context *intr_context = &qdev->intr_context[0]; + + ql_enable_msix(qdev); + + if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) { + /* Each rx_ring has it's + * own intr_context since we have separate + * vectors for each queue. + * This only true when MSI-X is enabled. + */ + for (i = 0; i < qdev->intr_count; i++, intr_context++) { + qdev->rx_ring[i].irq = i; + intr_context->intr = i; + intr_context->qdev = qdev; + /* + * We set up each vectors enable/disable/read bits so + * there's no bit/mask calculations in the critical path. + */ + intr_context->intr_en_mask = + INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | + INTR_EN_TYPE_ENABLE | INTR_EN_IHD_MASK | INTR_EN_IHD + | i; + intr_context->intr_dis_mask = + INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | + INTR_EN_TYPE_DISABLE | INTR_EN_IHD_MASK | + INTR_EN_IHD | i; + intr_context->intr_read_mask = + INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | + INTR_EN_TYPE_READ | INTR_EN_IHD_MASK | INTR_EN_IHD | + i; + + if (i == 0) { + /* + * Default queue handles bcast/mcast plus + * async events. Needs buffers. + */ + intr_context->handler = qlge_isr; + sprintf(intr_context->name, "%s-default-queue", + qdev->ndev->name); + } else if (i < qdev->rss_ring_first_cq_id) { + /* + * Outbound queue is for outbound completions only. + */ + intr_context->handler = qlge_msix_tx_isr; + sprintf(intr_context->name, "%s-txq-%d", + qdev->ndev->name, i); + } else { + /* + * Inbound queues handle unicast frames only. + */ + intr_context->handler = qlge_msix_rx_isr; + sprintf(intr_context->name, "%s-rxq-%d", + qdev->ndev->name, i); + } + } + } else { + /* + * All rx_rings use the same intr_context since + * there is only one vector. + */ + intr_context->intr = 0; + intr_context->qdev = qdev; + /* + * We set up each vectors enable/disable/read bits so + * there's no bit/mask calculations in the critical path. + */ + intr_context->intr_en_mask = + INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | INTR_EN_TYPE_ENABLE; + intr_context->intr_dis_mask = + INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | + INTR_EN_TYPE_DISABLE; + intr_context->intr_read_mask = + INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | INTR_EN_TYPE_READ; + /* + * Single interrupt means one handler for all rings. + */ + intr_context->handler = qlge_isr; + sprintf(intr_context->name, "%s-single_irq", qdev->ndev->name); + for (i = 0; i < qdev->rx_ring_count; i++) + qdev->rx_ring[i].irq = 0; + } +} + +static void ql_free_irq(struct ql_adapter *qdev) +{ + int i; + struct intr_context *intr_context = &qdev->intr_context[0]; + + for (i = 0; i < qdev->intr_count; i++, intr_context++) { + if (intr_context->hooked) { + if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) { + free_irq(qdev->msi_x_entry[i].vector, + &qdev->rx_ring[i]); + QPRINTK(qdev, IFDOWN, ERR, + "freeing msix interrupt %d.\n", i); + } else { + free_irq(qdev->pdev->irq, &qdev->rx_ring[0]); + QPRINTK(qdev, IFDOWN, ERR, + "freeing msi interrupt %d.\n", i); + } + } + } + ql_disable_msix(qdev); +} + +static int ql_request_irq(struct ql_adapter *qdev) +{ + int i; + int status = 0; + struct pci_dev *pdev = qdev->pdev; + struct intr_context *intr_context = &qdev->intr_context[0]; + + ql_resolve_queues_to_irqs(qdev); + + for (i = 0; i < qdev->intr_count; i++, intr_context++) { + atomic_set(&intr_context->irq_cnt, 0); + if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) { + status = request_irq(qdev->msi_x_entry[i].vector, + intr_context->handler, + 0, + intr_context->name, + &qdev->rx_ring[i]); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed request for MSIX interrupt %d.\n", + i); + goto err_irq; + } else { + QPRINTK(qdev, IFUP, INFO, + "Hooked intr %d, queue type %s%s%s, with name %s.\n", + i, + qdev->rx_ring[i].type == + DEFAULT_Q ? "DEFAULT_Q" : "", + qdev->rx_ring[i].type == + TX_Q ? "TX_Q" : "", + qdev->rx_ring[i].type == + RX_Q ? "RX_Q" : "", intr_context->name); + } + } else { + QPRINTK(qdev, IFUP, DEBUG, + "trying msi or legacy interrupts.\n"); + QPRINTK(qdev, IFUP, DEBUG, + "%s: irq = %d.\n", __func__, pdev->irq); + QPRINTK(qdev, IFUP, DEBUG, + "%s: context->name = %s.\n", __func__, + intr_context->name); + QPRINTK(qdev, IFUP, DEBUG, + "%s: dev_id = 0x%p.\n", __func__, + &qdev->rx_ring[0]); + status = + request_irq(pdev->irq, qlge_isr, + test_bit(QL_MSI_ENABLED, + &qdev-> + flags) ? 0 : IRQF_SHARED, + intr_context->name, &qdev->rx_ring[0]); + if (status) + goto err_irq; + + QPRINTK(qdev, IFUP, ERR, + "Hooked intr %d, queue type %s%s%s, with name %s.\n", + i, + qdev->rx_ring[0].type == + DEFAULT_Q ? "DEFAULT_Q" : "", + qdev->rx_ring[0].type == TX_Q ? "TX_Q" : "", + qdev->rx_ring[0].type == RX_Q ? "RX_Q" : "", + intr_context->name); + } + intr_context->hooked = 1; + } + return status; +err_irq: + QPRINTK(qdev, IFUP, ERR, "Failed to get the interrupts!!!/n"); + ql_free_irq(qdev); + return status; +} + +static int ql_start_rss(struct ql_adapter *qdev) +{ + struct ricb *ricb = &qdev->ricb; + int status = 0; + int i; + u8 *hash_id = (u8 *) ricb->hash_cq_id; + + memset((void *)ricb, 0, sizeof(ricb)); + + ricb->base_cq = qdev->rss_ring_first_cq_id | RSS_L4K; + ricb->flags = + (RSS_L6K | RSS_LI | RSS_LB | RSS_LM | RSS_RI4 | RSS_RI6 | RSS_RT4 | + RSS_RT6); + ricb->mask = cpu_to_le16(qdev->rss_ring_count - 1); + + /* + * Fill out the Indirection Table. + */ + for (i = 0; i < 32; i++) + hash_id[i] = i & 1; + + /* + * Random values for the IPv6 and IPv4 Hash Keys. + */ + get_random_bytes((void *)&ricb->ipv6_hash_key[0], 40); + get_random_bytes((void *)&ricb->ipv4_hash_key[0], 16); + + QPRINTK(qdev, IFUP, INFO, "Initializing RSS.\n"); + + status = ql_write_cfg(qdev, ricb, sizeof(ricb), CFG_LR, 0); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Failed to load RICB.\n"); + return status; + } + QPRINTK(qdev, IFUP, INFO, "Successfully loaded RICB.\n"); + return status; +} + +/* Initialize the frame-to-queue routing. */ +static int ql_route_initialize(struct ql_adapter *qdev) +{ + int status = 0; + int i; + + /* Clear all the entries in the routing table. */ + for (i = 0; i < 16; i++) { + status = ql_set_routing_reg(qdev, i, 0, 0); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to init routing register for CAM packets.\n"); + return status; + } + } + + status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to init routing register for error packets.\n"); + return status; + } + status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to init routing register for broadcast packets.\n"); + return status; + } + /* If we have more than one inbound queue, then turn on RSS in the + * routing block. + */ + if (qdev->rss_ring_count > 1) { + status = ql_set_routing_reg(qdev, RT_IDX_RSS_MATCH_SLOT, + RT_IDX_RSS_MATCH, 1); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to init routing register for MATCH RSS packets.\n"); + return status; + } + } + + status = ql_set_routing_reg(qdev, RT_IDX_CAM_HIT_SLOT, + RT_IDX_CAM_HIT, 1); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to init routing register for CAM packets.\n"); + return status; + } + return status; +} + +static int ql_adapter_initialize(struct ql_adapter *qdev) +{ + u32 value, mask; + int i; + int status = 0; + + /* + * Set up the System register to halt on errors. + */ + value = SYS_EFE | SYS_FAE; + mask = value << 16; + ql_write32(qdev, SYS, mask | value); + + /* Set the default queue. */ + value = NIC_RCV_CFG_DFQ; + mask = NIC_RCV_CFG_DFQ_MASK; + ql_write32(qdev, NIC_RCV_CFG, (mask | value)); + + /* Set the MPI interrupt to enabled. */ + ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI); + + /* Enable the function, set pagesize, enable error checking. */ + value = FSC_FE | FSC_EPC_INBOUND | FSC_EPC_OUTBOUND | + FSC_EC | FSC_VM_PAGE_4K | FSC_SH; + + /* Set/clear header splitting. */ + mask = FSC_VM_PAGESIZE_MASK | + FSC_DBL_MASK | FSC_DBRST_MASK | (value << 16); + ql_write32(qdev, FSC, mask | value); + + ql_write32(qdev, SPLT_HDR, SPLT_HDR_EP | + min(SMALL_BUFFER_SIZE, MAX_SPLIT_SIZE)); + + /* Start up the rx queues. */ + for (i = 0; i < qdev->rx_ring_count; i++) { + status = ql_start_rx_ring(qdev, &qdev->rx_ring[i]); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to start rx ring[%d].\n", i); + return status; + } + } + + /* If there is more than one inbound completion queue + * then download a RICB to configure RSS. + */ + if (qdev->rss_ring_count > 1) { + status = ql_start_rss(qdev); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Failed to start RSS.\n"); + return status; + } + } + + /* Start up the tx queues. */ + for (i = 0; i < qdev->tx_ring_count; i++) { + status = ql_start_tx_ring(qdev, &qdev->tx_ring[i]); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to start tx ring[%d].\n", i); + return status; + } + } + + status = ql_port_initialize(qdev); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n"); + return status; + } + + status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr, + MAC_ADDR_TYPE_CAM_MAC, qdev->func); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n"); + return status; + } + + status = ql_route_initialize(qdev); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n"); + return status; + } + + /* Start NAPI for the RSS queues. */ + for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) { + QPRINTK(qdev, IFUP, INFO, "Enabling NAPI for rx_ring[%d].\n", + i); + napi_enable(&qdev->rx_ring[i].napi); + } + + return status; +} + +/* Issue soft reset to chip. */ +static int ql_adapter_reset(struct ql_adapter *qdev) +{ + u32 value; + int max_wait_time; + int status = 0; + int resetCnt = 0; + +#define MAX_RESET_CNT 1 +issueReset: + resetCnt++; + QPRINTK(qdev, IFDOWN, DEBUG, "Issue soft reset to chip.\n"); + ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR); + /* Wait for reset to complete. */ + max_wait_time = 3; + QPRINTK(qdev, IFDOWN, DEBUG, "Wait %d seconds for reset to complete.\n", + max_wait_time); + do { + value = ql_read32(qdev, RST_FO); + if ((value & RST_FO_FR) == 0) + break; + + ssleep(1); + } while ((--max_wait_time)); + if (value & RST_FO_FR) { + QPRINTK(qdev, IFDOWN, ERR, + "Stuck in SoftReset: FSC_SR:0x%08x\n", value); + if (resetCnt < MAX_RESET_CNT) + goto issueReset; + } + if (max_wait_time == 0) { + status = -ETIMEDOUT; + QPRINTK(qdev, IFDOWN, ERR, + "ETIMEOUT!!! errored out of resetting the chip!\n"); + } + + return status; +} + +static void ql_display_dev_info(struct net_device *ndev) +{ + struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); + + QPRINTK(qdev, PROBE, INFO, + "Function #%d, NIC Roll %d, NIC Rev = %d, " + "XG Roll = %d, XG Rev = %d.\n", + qdev->func, + qdev->chip_rev_id & 0x0000000f, + qdev->chip_rev_id >> 4 & 0x0000000f, + qdev->chip_rev_id >> 8 & 0x0000000f, + qdev->chip_rev_id >> 12 & 0x0000000f); + QPRINTK(qdev, PROBE, INFO, + "MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->dev_addr[0], ndev->dev_addr[1], + ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], + ndev->dev_addr[5]); +} + +static int ql_adapter_down(struct ql_adapter *qdev) +{ + struct net_device *ndev = qdev->ndev; + int i, status = 0; + struct rx_ring *rx_ring; + + netif_stop_queue(ndev); + netif_carrier_off(ndev); + + cancel_delayed_work_sync(&qdev->asic_reset_work); + cancel_delayed_work_sync(&qdev->mpi_reset_work); + cancel_delayed_work_sync(&qdev->mpi_work); + + /* The default queue at index 0 is always processed in + * a workqueue. + */ + cancel_delayed_work_sync(&qdev->rx_ring[0].rx_work); + + /* The rest of the rx_rings are processed in + * a workqueue only if it's a single interrupt + * environment (MSI/Legacy). + */ + for (i = 1; i > qdev->rx_ring_count; i++) { + rx_ring = &qdev->rx_ring[i]; + /* Only the RSS rings use NAPI on multi irq + * environment. Outbound completion processing + * is done in interrupt context. + */ + if (i >= qdev->rss_ring_first_cq_id) { + napi_disable(&rx_ring->napi); + } else { + cancel_delayed_work_sync(&rx_ring->rx_work); + } + } + + clear_bit(QL_ADAPTER_UP, &qdev->flags); + + ql_disable_interrupts(qdev); + + ql_tx_ring_clean(qdev); + + spin_lock(&qdev->hw_lock); + status = ql_adapter_reset(qdev); + if (status) + QPRINTK(qdev, IFDOWN, ERR, "reset(func #%d) FAILED!\n", + qdev->func); + spin_unlock(&qdev->hw_lock); + return status; +} + +static int ql_adapter_up(struct ql_adapter *qdev) +{ + int err = 0; + + spin_lock(&qdev->hw_lock); + err = ql_adapter_initialize(qdev); + if (err) { + QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n"); + spin_unlock(&qdev->hw_lock); + goto err_init; + } + spin_unlock(&qdev->hw_lock); + set_bit(QL_ADAPTER_UP, &qdev->flags); + ql_enable_interrupts(qdev); + ql_enable_all_completion_interrupts(qdev); + if ((ql_read32(qdev, STS) & qdev->port_init)) { + netif_carrier_on(qdev->ndev); + netif_start_queue(qdev->ndev); + } + + return 0; +err_init: + ql_adapter_reset(qdev); + return err; +} + +static int ql_cycle_adapter(struct ql_adapter *qdev) +{ + int status; + + status = ql_adapter_down(qdev); + if (status) + goto error; + + status = ql_adapter_up(qdev); + if (status) + goto error; + + return status; +error: + QPRINTK(qdev, IFUP, ALERT, + "Driver up/down cycle failed, closing device\n"); + rtnl_lock(); + dev_close(qdev->ndev); + rtnl_unlock(); + return status; +} + +static void ql_release_adapter_resources(struct ql_adapter *qdev) +{ + ql_free_mem_resources(qdev); + ql_free_irq(qdev); +} + +static int ql_get_adapter_resources(struct ql_adapter *qdev) +{ + int status = 0; + + if (ql_alloc_mem_resources(qdev)) { + QPRINTK(qdev, IFUP, ERR, "Unable to allocate memory.\n"); + return -ENOMEM; + } + status = ql_request_irq(qdev); + if (status) + goto err_irq; + return status; +err_irq: + ql_free_mem_resources(qdev); + return status; +} + +static int qlge_close(struct net_device *ndev) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + + /* + * Wait for device to recover from a reset. + * (Rarely happens, but possible.) + */ + while (!test_bit(QL_ADAPTER_UP, &qdev->flags)) + msleep(1); + ql_adapter_down(qdev); + ql_release_adapter_resources(qdev); + ql_free_ring_cb(qdev); + return 0; +} + +static int ql_configure_rings(struct ql_adapter *qdev) +{ + int i; + struct rx_ring *rx_ring; + struct tx_ring *tx_ring; + int cpu_cnt = num_online_cpus(); + + /* + * For each processor present we allocate one + * rx_ring for outbound completions, and one + * rx_ring for inbound completions. Plus there is + * always the one default queue. For the CPU + * counts we end up with the following rx_rings: + * rx_ring count = + * one default queue + + * (CPU count * outbound completion rx_ring) + + * (CPU count * inbound (RSS) completion rx_ring) + * To keep it simple we limit the total number of + * queues to < 32, so we truncate CPU to 8. + * This limitation can be removed when requested. + */ + + if (cpu_cnt > 8) + cpu_cnt = 8; + + /* + * rx_ring[0] is always the default queue. + */ + /* Allocate outbound completion ring for each CPU. */ + qdev->tx_ring_count = cpu_cnt; + /* Allocate inbound completion (RSS) ring for each CPU. */ + qdev->rss_ring_count = cpu_cnt; + /* cq_id for the first inbound ring handler. */ + qdev->rss_ring_first_cq_id = cpu_cnt + 1; + /* + * qdev->rx_ring_count: + * Total number of rx_rings. This includes the one + * default queue, a number of outbound completion + * handler rx_rings, and the number of inbound + * completion handler rx_rings. + */ + qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1; + + if (ql_alloc_ring_cb(qdev)) + return -ENOMEM; + + for (i = 0; i < qdev->tx_ring_count; i++) { + tx_ring = &qdev->tx_ring[i]; + memset((void *)tx_ring, 0, sizeof(tx_ring)); + tx_ring->qdev = qdev; + tx_ring->wq_id = i; + tx_ring->wq_len = qdev->tx_ring_size; + tx_ring->wq_size = + tx_ring->wq_len * sizeof(struct ob_mac_iocb_req); + + /* + * The completion queue ID for the tx rings start + * immediately after the default Q ID, which is zero. + */ + tx_ring->cq_id = i + 1; + } + + for (i = 0; i < qdev->rx_ring_count; i++) { + rx_ring = &qdev->rx_ring[i]; + memset((void *)rx_ring, 0, sizeof(rx_ring)); + rx_ring->qdev = qdev; + rx_ring->cq_id = i; + rx_ring->cpu = i % cpu_cnt; /* CPU to run handler on. */ + if (i == 0) { /* Default queue at index 0. */ + /* + * Default queue handles bcast/mcast plus + * async events. Needs buffers. + */ + rx_ring->cq_len = qdev->rx_ring_size; + rx_ring->cq_size = + rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); + rx_ring->lbq_len = NUM_LARGE_BUFFERS; + rx_ring->lbq_size = + rx_ring->lbq_len * sizeof(struct bq_element); + rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE; + rx_ring->sbq_len = NUM_SMALL_BUFFERS; + rx_ring->sbq_size = + rx_ring->sbq_len * sizeof(struct bq_element); + rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2; + rx_ring->type = DEFAULT_Q; + } else if (i < qdev->rss_ring_first_cq_id) { + /* + * Outbound queue handles outbound completions only. + */ + /* outbound cq is same size as tx_ring it services. */ + rx_ring->cq_len = qdev->tx_ring_size; + rx_ring->cq_size = + rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); + rx_ring->lbq_len = 0; + rx_ring->lbq_size = 0; + rx_ring->lbq_buf_size = 0; + rx_ring->sbq_len = 0; + rx_ring->sbq_size = 0; + rx_ring->sbq_buf_size = 0; + rx_ring->type = TX_Q; + } else { /* Inbound completions (RSS) queues */ + /* + * Inbound queues handle unicast frames only. + */ + rx_ring->cq_len = qdev->rx_ring_size; + rx_ring->cq_size = + rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); + rx_ring->lbq_len = NUM_LARGE_BUFFERS; + rx_ring->lbq_size = + rx_ring->lbq_len * sizeof(struct bq_element); + rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE; + rx_ring->sbq_len = NUM_SMALL_BUFFERS; + rx_ring->sbq_size = + rx_ring->sbq_len * sizeof(struct bq_element); + rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2; + rx_ring->type = RX_Q; + } + } + return 0; +} + +static int qlge_open(struct net_device *ndev) +{ + int err = 0; + struct ql_adapter *qdev = netdev_priv(ndev); + + err = ql_configure_rings(qdev); + if (err) + return err; + + err = ql_get_adapter_resources(qdev); + if (err) + goto error_up; + + err = ql_adapter_up(qdev); + if (err) + goto error_up; + + return err; + +error_up: + ql_release_adapter_resources(qdev); + ql_free_ring_cb(qdev); + return err; +} + +static int qlge_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + + if (ndev->mtu == 1500 && new_mtu == 9000) { + QPRINTK(qdev, IFUP, ERR, "Changing to jumbo MTU.\n"); + } else if (ndev->mtu == 9000 && new_mtu == 1500) { + QPRINTK(qdev, IFUP, ERR, "Changing to normal MTU.\n"); + } else if ((ndev->mtu == 1500 && new_mtu == 1500) || + (ndev->mtu == 9000 && new_mtu == 9000)) { + return 0; + } else + return -EINVAL; + ndev->mtu = new_mtu; + return 0; +} + +static struct net_device_stats *qlge_get_stats(struct net_device + *ndev) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + return &qdev->stats; +} + +static void qlge_set_multicast_list(struct net_device *ndev) +{ + struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); + struct dev_mc_list *mc_ptr; + int i; + + spin_lock(&qdev->hw_lock); + /* + * Set or clear promiscuous mode if a + * transition is taking place. + */ + if (ndev->flags & IFF_PROMISC) { + if (!test_bit(QL_PROMISCUOUS, &qdev->flags)) { + if (ql_set_routing_reg + (qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 1)) { + QPRINTK(qdev, HW, ERR, + "Failed to set promiscous mode.\n"); + } else { + set_bit(QL_PROMISCUOUS, &qdev->flags); + } + } + } else { + if (test_bit(QL_PROMISCUOUS, &qdev->flags)) { + if (ql_set_routing_reg + (qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 0)) { + QPRINTK(qdev, HW, ERR, + "Failed to clear promiscous mode.\n"); + } else { + clear_bit(QL_PROMISCUOUS, &qdev->flags); + } + } + } + + /* + * Set or clear all multicast mode if a + * transition is taking place. + */ + if ((ndev->flags & IFF_ALLMULTI) || + (ndev->mc_count > MAX_MULTICAST_ENTRIES)) { + if (!test_bit(QL_ALLMULTI, &qdev->flags)) { + if (ql_set_routing_reg + (qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 1)) { + QPRINTK(qdev, HW, ERR, + "Failed to set all-multi mode.\n"); + } else { + set_bit(QL_ALLMULTI, &qdev->flags); + } + } + } else { + if (test_bit(QL_ALLMULTI, &qdev->flags)) { + if (ql_set_routing_reg + (qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 0)) { + QPRINTK(qdev, HW, ERR, + "Failed to clear all-multi mode.\n"); + } else { + clear_bit(QL_ALLMULTI, &qdev->flags); + } + } + } + + if (ndev->mc_count) { + for (i = 0, mc_ptr = ndev->mc_list; mc_ptr; + i++, mc_ptr = mc_ptr->next) + if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr, + MAC_ADDR_TYPE_MULTI_MAC, i)) { + QPRINTK(qdev, HW, ERR, + "Failed to loadmulticast address.\n"); + goto exit; + } + if (ql_set_routing_reg + (qdev, RT_IDX_MCAST_MATCH_SLOT, RT_IDX_MCAST_MATCH, 1)) { + QPRINTK(qdev, HW, ERR, + "Failed to set multicast match mode.\n"); + } else { + set_bit(QL_ALLMULTI, &qdev->flags); + } + } +exit: + spin_unlock(&qdev->hw_lock); +} + +static int qlge_set_mac_address(struct net_device *ndev, void *p) +{ + struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); + struct sockaddr *addr = p; + + if (netif_running(ndev)) + return -EBUSY; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); + + spin_lock(&qdev->hw_lock); + if (ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr, + MAC_ADDR_TYPE_CAM_MAC, qdev->func)) {/* Unicast */ + QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n"); + return -1; + } + spin_unlock(&qdev->hw_lock); + + return 0; +} + +static void qlge_tx_timeout(struct net_device *ndev) +{ + struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); + queue_delayed_work(qdev->workqueue, &qdev->asic_reset_work, 0); +} + +static void ql_asic_reset_work(struct work_struct *work) +{ + struct ql_adapter *qdev = + container_of(work, struct ql_adapter, asic_reset_work.work); + ql_cycle_adapter(qdev); +} + +static void ql_get_board_info(struct ql_adapter *qdev) +{ + qdev->func = + (ql_read32(qdev, STS) & STS_FUNC_ID_MASK) >> STS_FUNC_ID_SHIFT; + if (qdev->func) { + qdev->xg_sem_mask = SEM_XGMAC1_MASK; + qdev->port_link_up = STS_PL1; + qdev->port_init = STS_PI1; + qdev->mailbox_in = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC2_MBI; + qdev->mailbox_out = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC2_MBO; + } else { + qdev->xg_sem_mask = SEM_XGMAC0_MASK; + qdev->port_link_up = STS_PL0; + qdev->port_init = STS_PI0; + qdev->mailbox_in = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC0_MBI; + qdev->mailbox_out = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC0_MBO; + } + qdev->chip_rev_id = ql_read32(qdev, REV_ID); +} + +static void ql_release_all(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + struct ql_adapter *qdev = netdev_priv(ndev); + + if (qdev->workqueue) { + destroy_workqueue(qdev->workqueue); + qdev->workqueue = NULL; + } + if (qdev->q_workqueue) { + destroy_workqueue(qdev->q_workqueue); + qdev->q_workqueue = NULL; + } + if (qdev->reg_base) + iounmap((void *)qdev->reg_base); + if (qdev->doorbell_area) + iounmap(qdev->doorbell_area); + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); +} + +static int __devinit ql_init_device(struct pci_dev *pdev, + struct net_device *ndev, int cards_found) +{ + struct ql_adapter *qdev = netdev_priv(ndev); + int pos, err = 0; + u16 val16; + + memset((void *)qdev, 0, sizeof(qdev)); + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "PCI device enable failed.\n"); + return err; + } + + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (pos <= 0) { + dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, " + "aborting.\n"); + goto err_out; + } else { + pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16); + val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN; + val16 |= (PCI_EXP_DEVCTL_CERE | + PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); + pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16); + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + dev_err(&pdev->dev, "PCI region request failed.\n"); + goto err_out; + } + + pci_set_master(pdev); + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { + set_bit(QL_DMA64, &qdev->flags); + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + } else { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + } + + if (err) { + dev_err(&pdev->dev, "No usable DMA configuration.\n"); + goto err_out; + } + + pci_set_drvdata(pdev, ndev); + qdev->reg_base = + ioremap_nocache(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + if (!qdev->reg_base) { + dev_err(&pdev->dev, "Register mapping failed.\n"); + err = -ENOMEM; + goto err_out; + } + + qdev->doorbell_area_size = pci_resource_len(pdev, 3); + qdev->doorbell_area = + ioremap_nocache(pci_resource_start(pdev, 3), + pci_resource_len(pdev, 3)); + if (!qdev->doorbell_area) { + dev_err(&pdev->dev, "Doorbell register mapping failed.\n"); + err = -ENOMEM; + goto err_out; + } + + ql_get_board_info(qdev); + qdev->ndev = ndev; + qdev->pdev = pdev; + qdev->msg_enable = netif_msg_init(debug, default_msg); + spin_lock_init(&qdev->hw_lock); + spin_lock_init(&qdev->stats_lock); + + /* make sure the EEPROM is good */ + err = ql_get_flash_params(qdev); + if (err) { + dev_err(&pdev->dev, "Invalid FLASH.\n"); + goto err_out; + } + + if (!is_valid_ether_addr(qdev->flash.mac_addr)) + goto err_out; + + memcpy(ndev->dev_addr, qdev->flash.mac_addr, ndev->addr_len); + memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); + + /* Set up the default ring sizes. */ + qdev->tx_ring_size = NUM_TX_RING_ENTRIES; + qdev->rx_ring_size = NUM_RX_RING_ENTRIES; + + /* Set up the coalescing parameters. */ + qdev->rx_coalesce_usecs = DFLT_COALESCE_WAIT; + qdev->tx_coalesce_usecs = DFLT_COALESCE_WAIT; + qdev->rx_max_coalesced_frames = DFLT_INTER_FRAME_WAIT; + qdev->tx_max_coalesced_frames = DFLT_INTER_FRAME_WAIT; + + /* + * Set up the operating parameters. + */ + qdev->rx_csum = 1; + + qdev->q_workqueue = create_workqueue(ndev->name); + 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); + INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work); + + if (!cards_found) { + dev_info(&pdev->dev, "%s\n", DRV_STRING); + dev_info(&pdev->dev, "Driver name: %s, Version: %s.\n", + DRV_NAME, DRV_VERSION); + } + return 0; +err_out: + ql_release_all(pdev); + pci_disable_device(pdev); + return err; +} + +static int __devinit qlge_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_entry) +{ + struct net_device *ndev = NULL; + struct ql_adapter *qdev = NULL; + static int cards_found = 0; + int err = 0; + + ndev = alloc_etherdev(sizeof(struct ql_adapter)); + if (!ndev) + return -ENOMEM; + + err = ql_init_device(pdev, ndev, cards_found); + if (err < 0) { + free_netdev(ndev); + return err; + } + + 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); + + if (test_bit(QL_DMA64, &qdev->flags)) + ndev->features |= NETIF_F_HIGHDMA; + + /* + * Set up net_device structure. + */ + ndev->tx_queue_len = qdev->tx_ring_size; + ndev->irq = pdev->irq; + ndev->open = qlge_open; + ndev->stop = qlge_close; + ndev->hard_start_xmit = qlge_send; + SET_ETHTOOL_OPS(ndev, &qlge_ethtool_ops); + ndev->change_mtu = qlge_change_mtu; + ndev->get_stats = qlge_get_stats; + ndev->set_multicast_list = qlge_set_multicast_list; + ndev->set_mac_address = qlge_set_mac_address; + ndev->tx_timeout = qlge_tx_timeout; + ndev->watchdog_timeo = 10 * HZ; + ndev->vlan_rx_register = ql_vlan_rx_register; + ndev->vlan_rx_add_vid = ql_vlan_rx_add_vid; + ndev->vlan_rx_kill_vid = ql_vlan_rx_kill_vid; + err = register_netdev(ndev); + if (err) { + dev_err(&pdev->dev, "net device registration failed.\n"); + ql_release_all(pdev); + pci_disable_device(pdev); + return err; + } + netif_carrier_off(ndev); + netif_stop_queue(ndev); + ql_display_dev_info(ndev); + cards_found++; + return 0; +} + +static void __devexit qlge_remove(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + unregister_netdev(ndev); + ql_release_all(pdev); + pci_disable_device(pdev); + free_netdev(ndev); +} + +/* + * This callback is called by the PCI subsystem whenever + * a PCI bus error is detected. + */ +static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev, + enum pci_channel_state state) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + struct ql_adapter *qdev = netdev_priv(ndev); + + if (netif_running(ndev)) + ql_adapter_down(qdev); + + pci_disable_device(pdev); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/* + * This callback is called after the PCI buss has been reset. + * Basically, this tries to restart the card from scratch. + * This is a shortened version of the device probe/discovery code, + * it resembles the first-half of the () routine. + */ +static pci_ers_result_t qlge_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + struct ql_adapter *qdev = netdev_priv(ndev); + + if (pci_enable_device(pdev)) { + QPRINTK(qdev, IFUP, ERR, + "Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + + netif_carrier_off(ndev); + netif_stop_queue(ndev); + ql_adapter_reset(qdev); + + /* Make sure the EEPROM is good */ + memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); + + if (!is_valid_ether_addr(ndev->perm_addr)) { + QPRINTK(qdev, IFUP, ERR, "After reset, invalid MAC address.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + return PCI_ERS_RESULT_RECOVERED; +} + +static void qlge_io_resume(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + struct ql_adapter *qdev = netdev_priv(ndev); + + pci_set_master(pdev); + + if (netif_running(ndev)) { + if (ql_adapter_up(qdev)) { + QPRINTK(qdev, IFUP, ERR, + "Device initialization failed after reset.\n"); + return; + } + } + + netif_device_attach(ndev); +} + +static struct pci_error_handlers qlge_err_handler = { + .error_detected = qlge_io_error_detected, + .slot_reset = qlge_io_slot_reset, + .resume = qlge_io_resume, +}; + +static int qlge_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + struct ql_adapter *qdev = netdev_priv(ndev); + int err; + + netif_device_detach(ndev); + + if (netif_running(ndev)) { + err = ql_adapter_down(qdev); + if (!err) + return err; + } + + err = pci_save_state(pdev); + if (err) + return err; + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +#ifdef CONFIG_PM +static int qlge_resume(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + struct ql_adapter *qdev = netdev_priv(ndev); + int err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pci_enable_device(pdev); + if (err) { + QPRINTK(qdev, IFUP, ERR, "Cannot enable PCI device from suspend\n"); + return err; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + if (netif_running(ndev)) { + err = ql_adapter_up(qdev); + if (err) + return err; + } + + netif_device_attach(ndev); + + return 0; +} +#endif /* CONFIG_PM */ + +static void qlge_shutdown(struct pci_dev *pdev) +{ + qlge_suspend(pdev, PMSG_SUSPEND); +} + +static struct pci_driver qlge_driver = { + .name = DRV_NAME, + .id_table = qlge_pci_tbl, + .probe = qlge_probe, + .remove = __devexit_p(qlge_remove), +#ifdef CONFIG_PM + .suspend = qlge_suspend, + .resume = qlge_resume, +#endif + .shutdown = qlge_shutdown, + .err_handler = &qlge_err_handler +}; + +static int __init qlge_init_module(void) +{ + return pci_register_driver(&qlge_driver); +} + +static void __exit qlge_exit(void) +{ + pci_unregister_driver(&qlge_driver); +} + +module_init(qlge_init_module); +module_exit(qlge_exit); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c new file mode 100644 index 00000000000..24fe344bcf1 --- /dev/null +++ b/drivers/net/qlge/qlge_mpi.c @@ -0,0 +1,150 @@ +#include "qlge.h" + +static int ql_read_mbox_reg(struct ql_adapter *qdev, u32 reg, u32 *data) +{ + int status; + /* wait for reg to come ready */ + status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR); + if (status) + goto exit; + /* set up for reg read */ + ql_write32(qdev, PROC_ADDR, reg | PROC_ADDR_R); + /* wait for reg to come ready */ + status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR); + if (status) + goto exit; + /* get the data */ + *data = ql_read32(qdev, PROC_DATA); +exit: + return status; +} + +int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) +{ + int i, status; + + status = ql_sem_spinlock(qdev, SEM_PROC_REG_MASK); + if (status) + return -EBUSY; + for (i = 0; i < mbcp->out_count; i++) { + status = + ql_read_mbox_reg(qdev, qdev->mailbox_out + i, + &mbcp->mbox_out[i]); + if (status) { + QPRINTK(qdev, DRV, ERR, "Failed mailbox read.\n"); + break; + } + } + ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */ + return status; +} + +static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) +{ + mbcp->out_count = 2; + + if (ql_get_mb_sts(qdev, mbcp)) + goto exit; + + qdev->link_status = mbcp->mbox_out[1]; + QPRINTK(qdev, DRV, ERR, "Link Up.\n"); + QPRINTK(qdev, DRV, INFO, "Link Status = 0x%.08x.\n", mbcp->mbox_out[1]); + if (!netif_carrier_ok(qdev->ndev)) { + QPRINTK(qdev, LINK, INFO, "Link is Up.\n"); + netif_carrier_on(qdev->ndev); + netif_wake_queue(qdev->ndev); + } +exit: + /* Clear the MPI firmware status. */ + ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); +} + +static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp) +{ + mbcp->out_count = 3; + + if (ql_get_mb_sts(qdev, mbcp)) { + QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n"); + goto exit; + } + + if (netif_carrier_ok(qdev->ndev)) { + QPRINTK(qdev, LINK, INFO, "Link is Down.\n"); + netif_carrier_off(qdev->ndev); + netif_stop_queue(qdev->ndev); + } + QPRINTK(qdev, DRV, ERR, "Link Down.\n"); + QPRINTK(qdev, DRV, ERR, "Link Status = 0x%.08x.\n", mbcp->mbox_out[1]); +exit: + /* Clear the MPI firmware status. */ + ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); +} + +static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp) +{ + mbcp->out_count = 2; + + if (ql_get_mb_sts(qdev, mbcp)) { + QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n"); + goto exit; + } + QPRINTK(qdev, DRV, ERR, "Firmware initialized!\n"); + QPRINTK(qdev, DRV, ERR, "Firmware status = 0x%.08x.\n", + mbcp->mbox_out[0]); + QPRINTK(qdev, DRV, ERR, "Firmware Revision = 0x%.08x.\n", + mbcp->mbox_out[1]); +exit: + /* Clear the MPI firmware status. */ + ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); +} + +void ql_mpi_work(struct work_struct *work) +{ + struct ql_adapter *qdev = + container_of(work, struct ql_adapter, mpi_work.work); + struct mbox_params mbc; + struct mbox_params *mbcp = &mbc; + mbcp->out_count = 1; + + while (ql_read32(qdev, STS) & STS_PI) { + if (ql_get_mb_sts(qdev, mbcp)) { + QPRINTK(qdev, DRV, ERR, + "Could not read MPI, resetting ASIC!\n"); + ql_queue_asic_error(qdev); + } + + switch (mbcp->mbox_out[0]) { + case AEN_LINK_UP: + ql_link_up(qdev, mbcp); + break; + case AEN_LINK_DOWN: + ql_link_down(qdev, mbcp); + break; + case AEN_FW_INIT_DONE: + ql_init_fw_done(qdev, mbcp); + break; + case MB_CMD_STS_GOOD: + break; + case AEN_FW_INIT_FAIL: + case AEN_SYS_ERR: + case MB_CMD_STS_ERR: + ql_queue_fw_error(qdev); + default: + /* Clear the MPI firmware status. */ + ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); + break; + } + } + ql_enable_completion_interrupt(qdev, 0); +} + +void ql_mpi_reset_work(struct work_struct *work) +{ + struct ql_adapter *qdev = + container_of(work, struct ql_adapter, mpi_reset_work.work); + QPRINTK(qdev, DRV, ERR, + "Enter, qdev = %p..\n", qdev); + ql_write32(qdev, CSR, CSR_CMD_SET_RST); + msleep(50); + ql_write32(qdev, CSR, CSR_CMD_CLR_RST); +} diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 5d86281d936..34fe7ef8e5e 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -265,7 +265,7 @@ static void r6040_free_txbufs(struct net_device *dev) le32_to_cpu(lp->tx_insert_ptr->buf), MAX_BUF_SIZE, PCI_DMA_TODEVICE); dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); - lp->rx_insert_ptr->skb_ptr = NULL; + lp->tx_insert_ptr->skb_ptr = NULL; } lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp; } @@ -370,7 +370,7 @@ static void r6040_init_mac_regs(struct net_device *dev) /* Reset internal state machine */ iowrite16(2, ioaddr + MAC_SM); iowrite16(0, ioaddr + MAC_SM); - udelay(5000); + mdelay(5); /* MAC Bus Control Register */ iowrite16(MBCR_DEFAULT, ioaddr + MBCR); @@ -806,7 +806,7 @@ static void r6040_mac_address(struct net_device *dev) iowrite16(0x01, ioaddr + MCR1); /* Reset MAC */ iowrite16(2, ioaddr + MAC_SM); /* Reset internal state machine */ iowrite16(0, ioaddr + MAC_SM); - udelay(5000); + mdelay(5); /* Restore MAC Address */ adrp = (u16 *) dev->dev_addr; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 0f6f9747d25..c821da21d8e 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -36,7 +36,7 @@ #define assert(expr) \ if (!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr,__FILE__,__func__,__LINE__); \ } #define dprintk(fmt, args...) \ do { printk(KERN_DEBUG PFX fmt, ## args); } while (0) @@ -61,6 +61,7 @@ static const int multicast_filter_limit = 32; /* MAC address length */ #define MAC_ADDR_LEN 6 +#define MAX_READ_REQUEST_SHIFT 12 #define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */ #define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ @@ -95,6 +96,10 @@ enum mac_version { RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe + RTL_GIGA_MAC_VER_07 = 0x07, // 8102e + RTL_GIGA_MAC_VER_08 = 0x08, // 8102e + RTL_GIGA_MAC_VER_09 = 0x09, // 8102e + RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb @@ -104,7 +109,12 @@ enum mac_version { RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP RTL_GIGA_MAC_VER_19 = 0x13, // 8168C - RTL_GIGA_MAC_VER_20 = 0x14 // 8168C + RTL_GIGA_MAC_VER_20 = 0x14, // 8168C + RTL_GIGA_MAC_VER_21 = 0x15, // 8168C + RTL_GIGA_MAC_VER_22 = 0x16, // 8168C + RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP + RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP + RTL_GIGA_MAC_VER_25 = 0x19 // 8168D }; #define _R(NAME,MAC,MASK) \ @@ -121,6 +131,10 @@ static const struct { _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 @@ -130,7 +144,12 @@ static const struct { _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_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 }; #undef _R @@ -196,9 +215,6 @@ enum rtl_registers { Config5 = 0x56, MultiIntr = 0x5c, PHYAR = 0x60, - TBICSR = 0x64, - TBI_ANAR = 0x68, - TBI_LPAR = 0x6a, PHYstatus = 0x6c, RxMaxSize = 0xda, CPlusCmd = 0xe0, @@ -212,6 +228,32 @@ enum rtl_registers { FuncForceEvent = 0xfc, }; +enum rtl8110_registers { + TBICSR = 0x64, + TBI_ANAR = 0x68, + TBI_LPAR = 0x6a, +}; + +enum rtl8168_8101_registers { + CSIDR = 0x64, + CSIAR = 0x68, +#define CSIAR_FLAG 0x80000000 +#define CSIAR_WRITE_CMD 0x80000000 +#define CSIAR_BYTE_ENABLE 0x0f +#define CSIAR_BYTE_ENABLE_SHIFT 12 +#define CSIAR_ADDR_MASK 0x0fff + + EPHYAR = 0x80, +#define EPHYAR_FLAG 0x80000000 +#define EPHYAR_WRITE_CMD 0x80000000 +#define EPHYAR_REG_MASK 0x1f +#define EPHYAR_REG_SHIFT 16 +#define EPHYAR_DATA_MASK 0xffff + DBG_REG = 0xd1, +#define FIX_NAK_1 (1 << 4) +#define FIX_NAK_2 (1 << 3) +}; + enum rtl_register_content { /* InterruptStatusBits */ SYSErr = 0x8000, @@ -265,7 +307,13 @@ enum rtl_register_content { TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ /* Config1 register p.24 */ + LEDS1 = (1 << 7), + LEDS0 = (1 << 6), MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ + Speed_down = (1 << 4), + MEMMAP = (1 << 3), + IOMAP = (1 << 2), + VPD = (1 << 1), PMEnable = (1 << 0), /* Power Management Enable */ /* Config2 register p. 25 */ @@ -275,6 +323,7 @@ enum rtl_register_content { /* Config3 register p.25 */ MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ + Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */ /* Config5 register p.27 */ BWF = (1 << 6), /* Accept Broadcast wakeup frame */ @@ -292,7 +341,16 @@ enum rtl_register_content { TBINwComplete = 0x01000000, /* CPlusCmd p.31 */ - PktCntrDisable = (1 << 7), // 8168 + EnableBist = (1 << 15), // 8168 8101 + Mac_dbgo_oe = (1 << 14), // 8168 8101 + Normal_mode = (1 << 13), // unused + Force_half_dup = (1 << 12), // 8168 8101 + Force_rxflow_en = (1 << 11), // 8168 8101 + Force_txflow_en = (1 << 10), // 8168 8101 + Cxpl_dbg_sel = (1 << 9), // 8168 8101 + ASF = (1 << 8), // 8168 8101 + PktCntrDisable = (1 << 7), // 8168 8101 + Mac_dbgo_sel = 0x001c, // 8168 RxVlan = (1 << 6), RxChkSum = (1 << 5), PCIDAC = (1 << 4), @@ -370,8 +428,9 @@ struct ring_info { }; enum features { - RTL_FEATURE_WOL = (1 << 0), - RTL_FEATURE_MSI = (1 << 1), + RTL_FEATURE_WOL = (1 << 0), + RTL_FEATURE_MSI = (1 << 1), + RTL_FEATURE_GMII = (1 << 2), }; struct rtl8169_private { @@ -406,13 +465,16 @@ struct rtl8169_private { struct vlan_group *vlgrp; #endif int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex); - void (*get_settings)(struct net_device *, struct ethtool_cmd *); + int (*get_settings)(struct net_device *, struct ethtool_cmd *); void (*phy_reset_enable)(void __iomem *); void (*hw_start)(struct net_device *); unsigned int (*phy_reset_pending)(void __iomem *); unsigned int (*link_ok)(void __iomem *); + int pcie_cap; struct delayed_work task; unsigned features; + + struct mii_if_info mii; }; MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); @@ -482,6 +544,94 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr) return value; } +static void mdio_patch(void __iomem *ioaddr, int reg_addr, int value) +{ + mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value); +} + +static void rtl_mdio_write(struct net_device *dev, int phy_id, int location, + int val) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + + mdio_write(ioaddr, location, val); +} + +static int rtl_mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + + return mdio_read(ioaddr, location); +} + +static void rtl_ephy_write(void __iomem *ioaddr, int reg_addr, int value) +{ + unsigned int i; + + RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) | + (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); + + for (i = 0; i < 100; i++) { + if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG)) + break; + udelay(10); + } +} + +static u16 rtl_ephy_read(void __iomem *ioaddr, int reg_addr) +{ + u16 value = 0xffff; + unsigned int i; + + RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); + + for (i = 0; i < 100; i++) { + if (RTL_R32(EPHYAR) & EPHYAR_FLAG) { + value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK; + break; + } + udelay(10); + } + + return value; +} + +static void rtl_csi_write(void __iomem *ioaddr, int addr, int value) +{ + unsigned int i; + + RTL_W32(CSIDR, value); + RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); + + for (i = 0; i < 100; i++) { + if (!(RTL_R32(CSIAR) & CSIAR_FLAG)) + break; + udelay(10); + } +} + +static u32 rtl_csi_read(void __iomem *ioaddr, int addr) +{ + u32 value = ~0x00; + unsigned int i; + + RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); + + for (i = 0; i < 100; i++) { + if (RTL_R32(CSIAR) & CSIAR_FLAG) { + value = RTL_R32(CSIDR); + break; + } + udelay(10); + } + + return value; +} + static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr) { RTL_W16(IntrMask, 0x0000); @@ -619,6 +769,7 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) tp->features |= RTL_FEATURE_WOL; else tp->features &= ~RTL_FEATURE_WOL; + device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts); spin_unlock_irq(&tp->lock); @@ -705,8 +856,12 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, } } - /* The 8100e/8101e do Fast Ethernet only. */ - if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || + /* The 8100e/8101e/8102e do Fast Ethernet only. */ + if ((tp->mac_version == RTL_GIGA_MAC_VER_07) || + (tp->mac_version == RTL_GIGA_MAC_VER_08) || + (tp->mac_version == RTL_GIGA_MAC_VER_09) || + (tp->mac_version == RTL_GIGA_MAC_VER_10) || + (tp->mac_version == RTL_GIGA_MAC_VER_13) || (tp->mac_version == RTL_GIGA_MAC_VER_14) || (tp->mac_version == RTL_GIGA_MAC_VER_15) || (tp->mac_version == RTL_GIGA_MAC_VER_16)) { @@ -720,9 +875,13 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - if ((tp->mac_version == RTL_GIGA_MAC_VER_12) || - (tp->mac_version == RTL_GIGA_MAC_VER_17)) { - /* Vendor specific (0x1f) and reserved (0x0e) MII registers. */ + if ((tp->mac_version == RTL_GIGA_MAC_VER_11) || + (tp->mac_version == RTL_GIGA_MAC_VER_12) || + (tp->mac_version >= RTL_GIGA_MAC_VER_17)) { + /* + * Wake up the PHY. + * Vendor specific (0x1f) and reserved (0x0e) MII registers. + */ mdio_write(ioaddr, 0x1f, 0x0000); mdio_write(ioaddr, 0x0e, 0x0000); } @@ -850,7 +1009,7 @@ static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, #endif -static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) +static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; @@ -867,65 +1026,29 @@ static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) cmd->speed = SPEED_1000; cmd->duplex = DUPLEX_FULL; /* Always set */ + + return 0; } -static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd) +static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd) { struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; - u8 status; - - cmd->supported = SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_TP; - - cmd->autoneg = 1; - cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg; - - if (tp->phy_auto_nego_reg & ADVERTISE_10HALF) - cmd->advertising |= ADVERTISED_10baseT_Half; - if (tp->phy_auto_nego_reg & ADVERTISE_10FULL) - cmd->advertising |= ADVERTISED_10baseT_Full; - if (tp->phy_auto_nego_reg & ADVERTISE_100HALF) - cmd->advertising |= ADVERTISED_100baseT_Half; - if (tp->phy_auto_nego_reg & ADVERTISE_100FULL) - cmd->advertising |= ADVERTISED_100baseT_Full; - if (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL) - cmd->advertising |= ADVERTISED_1000baseT_Full; - - status = RTL_R8(PHYstatus); - - if (status & _1000bpsF) - cmd->speed = SPEED_1000; - else if (status & _100bps) - cmd->speed = SPEED_100; - else if (status & _10bps) - cmd->speed = SPEED_10; - - if (status & TxFlowCtrl) - cmd->advertising |= ADVERTISED_Asym_Pause; - if (status & RxFlowCtrl) - cmd->advertising |= ADVERTISED_Pause; - - cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ? - DUPLEX_FULL : DUPLEX_HALF; + + return mii_ethtool_gset(&tp->mii, cmd); } static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct rtl8169_private *tp = netdev_priv(dev); unsigned long flags; + int rc; spin_lock_irqsave(&tp->lock, flags); - tp->get_settings(dev, cmd); + rc = tp->get_settings(dev, cmd); spin_unlock_irqrestore(&tp->lock, flags); - return 0; + return rc; } static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs, @@ -1103,11 +1226,19 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, u32 val; int mac_version; } mac_info[] = { - /* 8168B family. */ - { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, + /* 8168D family. */ + { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_25 }, + + /* 8168C family. */ + { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 }, + { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 }, + { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, + { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 }, { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 }, { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 }, - { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_20 }, + { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 }, + { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 }, + { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 }, /* 8168B family. */ { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 }, @@ -1116,8 +1247,17 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, /* 8101 family. */ + { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 }, + { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 }, + { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 }, + { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 }, + { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 }, + { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 }, { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 }, + { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 }, { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 }, + { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 }, + { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 }, { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 }, /* FIXME: where did these entries come from ? -- FR */ { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 }, @@ -1228,7 +1368,31 @@ static void rtl8169sb_hw_phy_config(void __iomem *ioaddr) rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } -static void rtl8168cp_hw_phy_config(void __iomem *ioaddr) +static void rtl8168bb_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x10, 0xf41b }, + { 0x1f, 0x0000 } + }; + + mdio_write(ioaddr, 0x1f, 0x0001); + mdio_patch(ioaddr, 0x16, 1 << 0); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + +static void rtl8168bef_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x10, 0xf41b }, + { 0x1f, 0x0000 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + +static void rtl8168cp_1_hw_phy_config(void __iomem *ioaddr) { struct phy_reg phy_reg_init[] = { { 0x1f, 0x0000 }, @@ -1241,7 +1405,22 @@ static void rtl8168cp_hw_phy_config(void __iomem *ioaddr) rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } -static void rtl8168c_hw_phy_config(void __iomem *ioaddr) +static void rtl8168cp_2_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x1d, 0x3d98 }, + { 0x1f, 0x0000 } + }; + + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + +static void rtl8168c_1_hw_phy_config(void __iomem *ioaddr) { struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, @@ -1257,25 +1436,157 @@ static void rtl8168c_hw_phy_config(void __iomem *ioaddr) { 0x1f, 0x0003 }, { 0x12, 0xc096 }, { 0x16, 0x000a }, - { 0x1f, 0x0000 } + { 0x1f, 0x0000 }, + { 0x1f, 0x0000 }, + { 0x09, 0x2000 }, + { 0x09, 0x0000 } }; rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + mdio_write(ioaddr, 0x1f, 0x0000); } -static void rtl8168cx_hw_phy_config(void __iomem *ioaddr) +static void rtl8168c_2_hw_phy_config(void __iomem *ioaddr) { struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0000 }, + { 0x1f, 0x0001 }, { 0x12, 0x2300 }, + { 0x03, 0x802f }, + { 0x02, 0x4f02 }, + { 0x01, 0x0409 }, + { 0x00, 0xf099 }, + { 0x04, 0x9800 }, + { 0x04, 0x9000 }, + { 0x1d, 0x3d98 }, + { 0x1f, 0x0002 }, + { 0x0c, 0x7eb8 }, + { 0x06, 0x0761 }, { 0x1f, 0x0003 }, { 0x16, 0x0f0a }, - { 0x1f, 0x0000 }, + { 0x1f, 0x0000 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + mdio_patch(ioaddr, 0x16, 1 << 0); + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8168c_3_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x12, 0x2300 }, + { 0x1d, 0x3d98 }, { 0x1f, 0x0002 }, { 0x0c, 0x7eb8 }, + { 0x06, 0x5461 }, + { 0x1f, 0x0003 }, + { 0x16, 0x0f0a }, + { 0x1f, 0x0000 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + mdio_patch(ioaddr, 0x16, 1 << 0); + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr) +{ + rtl8168c_3_hw_phy_config(ioaddr); +} + +static void rtl8168d_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init_0[] = { + { 0x1f, 0x0001 }, + { 0x09, 0x2770 }, + { 0x08, 0x04d0 }, + { 0x0b, 0xad15 }, + { 0x0c, 0x5bf0 }, + { 0x1c, 0xf101 }, + { 0x1f, 0x0003 }, + { 0x14, 0x94d7 }, + { 0x12, 0xf4d6 }, + { 0x09, 0xca0f }, + { 0x1f, 0x0002 }, + { 0x0b, 0x0b10 }, + { 0x0c, 0xd1f7 }, + { 0x1f, 0x0002 }, + { 0x06, 0x5461 }, + { 0x1f, 0x0002 }, + { 0x05, 0x6662 }, + { 0x1f, 0x0000 }, + { 0x14, 0x0060 }, + { 0x1f, 0x0000 }, + { 0x0d, 0xf8a0 }, + { 0x1f, 0x0005 }, + { 0x05, 0xffc2 } + }; + + rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0)); + + if (mdio_read(ioaddr, 0x06) == 0xc400) { + struct phy_reg phy_reg_init_1[] = { + { 0x1f, 0x0005 }, + { 0x01, 0x0300 }, + { 0x1f, 0x0000 }, + { 0x11, 0x401c }, + { 0x16, 0x4100 }, + { 0x1f, 0x0005 }, + { 0x07, 0x0010 }, + { 0x05, 0x83dc }, + { 0x06, 0x087d }, + { 0x05, 0x8300 }, + { 0x06, 0x0101 }, + { 0x06, 0x05f8 }, + { 0x06, 0xf9fa }, + { 0x06, 0xfbef }, + { 0x06, 0x79e2 }, + { 0x06, 0x835f }, + { 0x06, 0xe0f8 }, + { 0x06, 0x9ae1 }, + { 0x06, 0xf89b }, + { 0x06, 0xef31 }, + { 0x06, 0x3b65 }, + { 0x06, 0xaa07 }, + { 0x06, 0x81e4 }, + { 0x06, 0xf89a }, + { 0x06, 0xe5f8 }, + { 0x06, 0x9baf }, + { 0x06, 0x06ae }, + { 0x05, 0x83dc }, + { 0x06, 0x8300 }, + }; + + rtl_phy_write(ioaddr, phy_reg_init_1, + ARRAY_SIZE(phy_reg_init_1)); + } + + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8102e_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0003 }, + { 0x08, 0x441d }, + { 0x01, 0x9100 }, { 0x1f, 0x0000 } }; + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_patch(ioaddr, 0x11, 1 << 12); + mdio_patch(ioaddr, 0x19, 1 << 13); + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } @@ -1296,15 +1607,43 @@ static void rtl_hw_phy_config(struct net_device *dev) case RTL_GIGA_MAC_VER_04: rtl8169sb_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_07: + case RTL_GIGA_MAC_VER_08: + case RTL_GIGA_MAC_VER_09: + rtl8102e_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_11: + rtl8168bb_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_12: + rtl8168bef_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_17: + rtl8168bef_hw_phy_config(ioaddr); + break; case RTL_GIGA_MAC_VER_18: - rtl8168cp_hw_phy_config(ioaddr); + rtl8168cp_1_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_19: - rtl8168c_hw_phy_config(ioaddr); + rtl8168c_1_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_20: - rtl8168cx_hw_phy_config(ioaddr); + rtl8168c_2_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_21: + rtl8168c_3_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_22: + rtl8168c_4_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_23: + case RTL_GIGA_MAC_VER_24: + rtl8168cp_2_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_25: + rtl8168d_hw_phy_config(ioaddr); + break; + default: break; } @@ -1513,7 +1852,7 @@ static const struct rtl_cfg_info { unsigned int align; u16 intr_event; u16 napi_event; - unsigned msi; + unsigned features; } rtl_cfg_infos [] = { [RTL_CFG_0] = { .hw_start = rtl_hw_start_8169, @@ -1522,7 +1861,7 @@ static const struct rtl_cfg_info { .intr_event = SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, - .msi = 0 + .features = RTL_FEATURE_GMII }, [RTL_CFG_1] = { .hw_start = rtl_hw_start_8168, @@ -1531,7 +1870,7 @@ static const struct rtl_cfg_info { .intr_event = SYSErr | LinkChg | RxOverflow | TxErr | TxOK | RxOK | RxErr, .napi_event = TxErr | TxOK | RxOK | RxOverflow, - .msi = RTL_FEATURE_MSI + .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI }, [RTL_CFG_2] = { .hw_start = rtl_hw_start_8101, @@ -1540,7 +1879,7 @@ static const struct rtl_cfg_info { .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, - .msi = RTL_FEATURE_MSI + .features = RTL_FEATURE_MSI } }; @@ -1552,7 +1891,7 @@ static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr, u8 cfg2; cfg2 = RTL_R8(Config2) & ~MSIEnable; - if (cfg->msi) { + if (cfg->features & RTL_FEATURE_MSI) { if (pci_enable_msi(pdev)) { dev_info(&pdev->dev, "no MSI. Back to INTx.\n"); } else { @@ -1572,12 +1911,81 @@ static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp) } } +static int rtl_eeprom_read(struct pci_dev *pdev, int cap, int addr, __le32 *val) +{ + int ret, count = 100; + u16 status = 0; + u32 value; + + ret = pci_write_config_word(pdev, cap + PCI_VPD_ADDR, addr); + if (ret < 0) + return ret; + + do { + udelay(10); + ret = pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &status); + if (ret < 0) + return ret; + } while (!(status & PCI_VPD_ADDR_F) && --count); + + if (!(status & PCI_VPD_ADDR_F)) + return -ETIMEDOUT; + + ret = pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &value); + if (ret < 0) + return ret; + + *val = cpu_to_le32(value); + + return 0; +} + +static void rtl_init_mac_address(struct rtl8169_private *tp, + void __iomem *ioaddr) +{ + struct pci_dev *pdev = tp->pci_dev; + u8 cfg1; + int vpd_cap; + u8 mac[8]; + DECLARE_MAC_BUF(buf); + + cfg1 = RTL_R8(Config1); + if (!(cfg1 & VPD)) { + dprintk("VPD access not enabled, enabling\n"); + RTL_W8(Cfg9346, Cfg9346_Unlock); + RTL_W8(Config1, cfg1 | VPD); + RTL_W8(Cfg9346, Cfg9346_Lock); + } + + vpd_cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); + if (!vpd_cap) + return; + + /* MAC address is stored in EEPROM at offset 0x0e + * Realtek says: "The VPD address does not have to be a DWORD-aligned + * address as defined in the PCI 2.2 Specifications, but the VPD data + * is always consecutive 4-byte data starting from the VPD address + * specified." + */ + if (rtl_eeprom_read(pdev, vpd_cap, 0x000e, (__le32*)&mac[0]) < 0 || + rtl_eeprom_read(pdev, vpd_cap, 0x0012, (__le32*)&mac[4]) < 0) { + dprintk("Reading MAC address from EEPROM failed\n"); + return; + } + + dprintk("MAC address found in EEPROM: %s\n", print_mac(buf, mac)); + + /* Write MAC address */ + rtl_rar_set(tp, mac); +} + static int __devinit rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; const unsigned int region = cfg->region; struct rtl8169_private *tp; + struct mii_if_info *mii; struct net_device *dev; void __iomem *ioaddr; unsigned int i; @@ -1602,6 +2010,14 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->pci_dev = pdev; tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); + mii = &tp->mii; + mii->dev = dev; + mii->mdio_read = rtl_mdio_read; + mii->mdio_write = rtl_mdio_write; + mii->phy_id_mask = 0x1f; + mii->reg_num_mask = 0x1f; + mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII); + /* enable device (incl. PCI PM wakeup and hotplug setup) */ rc = pci_enable_device(pdev); if (rc < 0) { @@ -1670,6 +2086,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_res_4; } + tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!tp->pcie_cap && netif_msg_probe(tp)) + dev_info(&pdev->dev, "no PCI Express capability\n"); + /* Unneeded ? Don't mess with Mrs. Murphy. */ rtl8169_irq_mask_and_ack(ioaddr); @@ -1706,6 +2126,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(Config1, RTL_R8(Config1) | PMEnable); RTL_W8(Config5, RTL_R8(Config5) & PMEStatus); + if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0) + tp->features |= RTL_FEATURE_WOL; + if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0) + tp->features |= RTL_FEATURE_WOL; tp->features |= rtl_try_msi(pdev, ioaddr, cfg); RTL_W8(Cfg9346, Cfg9346_Lock); @@ -1728,7 +2152,13 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->do_ioctl = rtl8169_ioctl; } - /* Get MAC address. FIXME: read EEPROM */ + spin_lock_init(&tp->lock); + + tp->mmio_addr = ioaddr; + + rtl_init_mac_address(tp, ioaddr); + + /* Get MAC address */ for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); @@ -1758,7 +2188,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) #endif tp->intr_mask = 0xffff; - tp->mmio_addr = ioaddr; tp->align = cfg->align; tp->hw_start = cfg->hw_start; tp->intr_event = cfg->intr_event; @@ -1768,8 +2197,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->timer.data = (unsigned long) dev; tp->timer.function = rtl8169_phy_timer; - spin_lock_init(&tp->lock); - rc = register_netdev(dev); if (rc < 0) goto err_out_msi_5; @@ -1791,6 +2218,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } rtl8169_init_phy(dev, tp); + device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL); out: return rc; @@ -2061,12 +2489,209 @@ static void rtl_hw_start_8169(struct net_device *dev) RTL_W16(IntrMask, tp->intr_event); } +static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + int cap = tp->pcie_cap; + + if (cap) { + u16 ctl; + + pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl); + ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force; + pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl); + } +} + +static void rtl_csi_access_enable(void __iomem *ioaddr) +{ + u32 csi; + + csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff; + rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000); +} + +struct ephy_info { + unsigned int offset; + u16 mask; + u16 bits; +}; + +static void rtl_ephy_init(void __iomem *ioaddr, struct ephy_info *e, int len) +{ + u16 w; + + while (len-- > 0) { + w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits; + rtl_ephy_write(ioaddr, e->offset, w); + e++; + } +} + +static void rtl_disable_clock_request(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + int cap = tp->pcie_cap; + + if (cap) { + u16 ctl; + + pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl); + ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN; + pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl); + } +} + +#define R8168_CPCMD_QUIRK_MASK (\ + EnableBist | \ + Mac_dbgo_oe | \ + Force_half_dup | \ + Force_rxflow_en | \ + Force_txflow_en | \ + Cxpl_dbg_sel | \ + ASF | \ + PktCntrDisable | \ + Mac_dbgo_sel) + +static void rtl_hw_start_8168bb(void __iomem *ioaddr, struct pci_dev *pdev) +{ + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); + + rtl_tx_performance_tweak(pdev, + (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN); +} + +static void rtl_hw_start_8168bef(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_hw_start_8168bb(ioaddr, pdev); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0)); +} + +static void __rtl_hw_start_8168cp(void __iomem *ioaddr, struct pci_dev *pdev) +{ + RTL_W8(Config1, RTL_R8(Config1) | Speed_down); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + rtl_disable_clock_request(pdev); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev) +{ + static struct ephy_info e_info_8168cp[] = { + { 0x01, 0, 0x0001 }, + { 0x02, 0x0800, 0x1000 }, + { 0x03, 0, 0x0042 }, + { 0x06, 0x0080, 0x0000 }, + { 0x07, 0, 0x2000 } + }; + + rtl_csi_access_enable(ioaddr); + + rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp)); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168cp_2(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_csi_access_enable(ioaddr); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168cp_3(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_csi_access_enable(ioaddr); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + /* Magic. */ + RTL_W8(DBG_REG, 0x20); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168c_1(void __iomem *ioaddr, struct pci_dev *pdev) +{ + static struct ephy_info e_info_8168c_1[] = { + { 0x02, 0x0800, 0x1000 }, + { 0x03, 0, 0x0002 }, + { 0x06, 0x0080, 0x0000 } + }; + + rtl_csi_access_enable(ioaddr); + + RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2); + + rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1)); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168c_2(void __iomem *ioaddr, struct pci_dev *pdev) +{ + static struct ephy_info e_info_8168c_2[] = { + { 0x01, 0, 0x0001 }, + { 0x03, 0x0400, 0x0220 } + }; + + rtl_csi_access_enable(ioaddr); + + rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2)); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168c_3(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_hw_start_8168c_2(ioaddr, pdev); +} + +static void rtl_hw_start_8168c_4(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_csi_access_enable(ioaddr); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_csi_access_enable(ioaddr); + + rtl_disable_clock_request(pdev); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + static void rtl_hw_start_8168(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; struct pci_dev *pdev = tp->pci_dev; - u8 ctl; RTL_W8(Cfg9346, Cfg9346_Unlock); @@ -2074,17 +2699,10 @@ static void rtl_hw_start_8168(struct net_device *dev) rtl_set_rx_max_size(ioaddr); - rtl_set_rx_tx_config_registers(tp); - tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1; RTL_W16(CPlusCmd, tp->cp_cmd); - /* Tx performance tweak. */ - pci_read_config_byte(pdev, 0x69, &ctl); - ctl = (ctl & ~0x70) | 0x50; - pci_write_config_byte(pdev, 0x69, ctl); - RTL_W16(IntrMitigate, 0x5151); /* Work around for RxFIFO overflow. */ @@ -2095,21 +2713,134 @@ static void rtl_hw_start_8168(struct net_device *dev) rtl_set_rx_tx_desc_registers(tp, ioaddr); - RTL_W8(Cfg9346, Cfg9346_Lock); + rtl_set_rx_mode(dev); + + RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | + (InterFrameGap << TxInterFrameGapShift)); RTL_R8(IntrMask); - RTL_W32(RxMissed, 0); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_11: + rtl_hw_start_8168bb(ioaddr, pdev); + break; - rtl_set_rx_mode(dev); + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + rtl_hw_start_8168bef(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_18: + rtl_hw_start_8168cp_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_19: + rtl_hw_start_8168c_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_20: + rtl_hw_start_8168c_2(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_21: + rtl_hw_start_8168c_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_22: + rtl_hw_start_8168c_4(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_23: + rtl_hw_start_8168cp_2(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_24: + rtl_hw_start_8168cp_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_25: + rtl_hw_start_8168d(ioaddr, pdev); + break; + + default: + printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n", + dev->name, tp->mac_version); + break; + } RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + RTL_W8(Cfg9346, Cfg9346_Lock); + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); RTL_W16(IntrMask, tp->intr_event); } +#define R810X_CPCMD_QUIRK_MASK (\ + EnableBist | \ + Mac_dbgo_oe | \ + Force_half_dup | \ + Force_half_dup | \ + Force_txflow_en | \ + Cxpl_dbg_sel | \ + ASF | \ + PktCntrDisable | \ + PCIDAC | \ + PCIMulRW) + +static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev) +{ + static struct ephy_info e_info_8102e_1[] = { + { 0x01, 0, 0x6e65 }, + { 0x02, 0, 0x091f }, + { 0x03, 0, 0xc2f9 }, + { 0x06, 0, 0xafb5 }, + { 0x07, 0, 0x0e00 }, + { 0x19, 0, 0xec80 }, + { 0x01, 0, 0x2e65 }, + { 0x01, 0, 0x6e65 } + }; + u8 cfg1; + + rtl_csi_access_enable(ioaddr); + + RTL_W8(DBG_REG, FIX_NAK_1); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(Config1, + LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable); + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + cfg1 = RTL_R8(Config1); + if ((cfg1 & LEDS0) && (cfg1 & LEDS1)) + RTL_W8(Config1, cfg1 & ~LEDS0); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); + + rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1)); +} + +static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_csi_access_enable(ioaddr); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable); + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8102e_3(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_hw_start_8102e_2(ioaddr, pdev); + + rtl_ephy_write(ioaddr, 0x03, 0xc2f9); +} + static void rtl_hw_start_8101(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -2118,8 +2849,26 @@ static void rtl_hw_start_8101(struct net_device *dev) if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || (tp->mac_version == RTL_GIGA_MAC_VER_16)) { - pci_write_config_word(pdev, 0x68, 0x00); - pci_write_config_word(pdev, 0x69, 0x08); + int cap = tp->pcie_cap; + + if (cap) { + pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_NOSNOOP_EN); + } + } + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_07: + rtl_hw_start_8102e_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_08: + rtl_hw_start_8102e_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_09: + rtl_hw_start_8102e_2(ioaddr, pdev); + break; } RTL_W8(Cfg9346, Cfg9346_Unlock); @@ -2143,8 +2892,6 @@ static void rtl_hw_start_8101(struct net_device *dev) RTL_R8(IntrMask); - RTL_W32(RxMissed, 0); - rtl_set_rx_mode(dev); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); @@ -2922,6 +3669,17 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) return work_done; } +static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (tp->mac_version > RTL_GIGA_MAC_VER_06) + return; + + dev->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff); + RTL_W32(RxMissed, 0); +} + static void rtl8169_down(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -2939,9 +3697,7 @@ core_down: rtl8169_asic_down(ioaddr); - /* Update the error counts. */ - dev->stats.rx_missed_errors += RTL_R32(RxMissed); - RTL_W32(RxMissed, 0); + rtl8169_rx_missed(dev, ioaddr); spin_unlock_irq(&tp->lock); @@ -3063,8 +3819,7 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev) if (netif_running(dev)) { spin_lock_irqsave(&tp->lock, flags); - dev->stats.rx_missed_errors += RTL_R32(RxMissed); - RTL_W32(RxMissed, 0); + rtl8169_rx_missed(dev, ioaddr); spin_unlock_irqrestore(&tp->lock, flags); } @@ -3089,8 +3844,7 @@ static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) rtl8169_asic_down(ioaddr); - dev->stats.rx_missed_errors += RTL_R32(RxMissed); - RTL_W32(RxMissed, 0); + rtl8169_rx_missed(dev, ioaddr); spin_unlock_irq(&tp->lock); @@ -3121,6 +3875,11 @@ out: return 0; } +static void rtl_shutdown(struct pci_dev *pdev) +{ + rtl8169_suspend(pdev, PMSG_SUSPEND); +} + #endif /* CONFIG_PM */ static struct pci_driver rtl8169_pci_driver = { @@ -3131,6 +3890,7 @@ static struct pci_driver rtl8169_pci_driver = { #ifdef CONFIG_PM .suspend = rtl8169_suspend, .resume = rtl8169_resume, + .shutdown = rtl_shutdown, #endif }; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index a2b073097e5..6a1375f9cbb 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -371,9 +371,6 @@ static void s2io_vlan_rx_register(struct net_device *dev, flags[i]); } -/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */ -static int vlan_strip_flag; - /* Unregister the vlan */ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) { @@ -2303,7 +2300,7 @@ static int start_nic(struct s2io_nic *nic) val64 = readq(&bar0->rx_pa_cfg); val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG; writeq(val64, &bar0->rx_pa_cfg); - vlan_strip_flag = 0; + nic->vlan_strip_flag = 0; } /* @@ -3136,7 +3133,7 @@ static void tx_intr_handler(struct fifo_info *fifo_data) if (skb == NULL) { spin_unlock_irqrestore(&fifo_data->tx_lock, flags); DBG_PRINT(ERR_DBG, "%s: Null skb ", - __FUNCTION__); + __func__); DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); return; } @@ -3496,7 +3493,7 @@ static void s2io_reset(struct s2io_nic * sp) unsigned long long mem_alloc_cnt, mem_free_cnt, watchdog_cnt; DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n", - __FUNCTION__, sp->dev->name); + __func__, sp->dev->name); /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd)); @@ -3518,7 +3515,7 @@ static void s2io_reset(struct s2io_nic * sp) } if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) { - DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__); + DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __func__); } pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd); @@ -3768,7 +3765,7 @@ static void restore_xmsi_data(struct s2io_nic *nic) val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6)); writeq(val64, &bar0->xmsi_access); if (wait_for_msix_trans(nic, msix_index)) { - DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); + DBG_PRINT(ERR_DBG, "failed in %s\n", __func__); continue; } } @@ -3789,7 +3786,7 @@ static void store_xmsi_data(struct s2io_nic *nic) val64 = (s2BIT(15) | vBIT(msix_index, 26, 6)); writeq(val64, &bar0->xmsi_access); if (wait_for_msix_trans(nic, msix_index)) { - DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); + DBG_PRINT(ERR_DBG, "failed in %s\n", __func__); continue; } addr = readq(&bar0->xmsi_address); @@ -3812,7 +3809,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) GFP_KERNEL); if (!nic->entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ - __FUNCTION__); + __func__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; return -ENOMEM; } @@ -3826,7 +3823,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) GFP_KERNEL); if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", - __FUNCTION__); + __func__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; kfree(nic->entries); nic->mac_control.stats_info->sw_stat.mem_freed @@ -5010,7 +5007,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 = readq(&bar0->rx_pa_cfg); val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG; writeq(val64, &bar0->rx_pa_cfg); - vlan_strip_flag = 0; + sp->vlan_strip_flag = 0; } val64 = readq(&bar0->mac_cfg); @@ -5032,7 +5029,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 = readq(&bar0->rx_pa_cfg); val64 |= RX_PA_CFG_STRIP_VLAN_TAG; writeq(val64, &bar0->rx_pa_cfg); - vlan_strip_flag = 1; + sp->vlan_strip_flag = 1; } val64 = readq(&bar0->mac_cfg); @@ -6746,7 +6743,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) ret = s2io_card_up(sp); if (ret) { DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", - __FUNCTION__); + __func__); return ret; } s2io_wake_all_tx_queue(sp); @@ -7530,7 +7527,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) default: DBG_PRINT(ERR_DBG, "%s: Samadhana!!\n", - __FUNCTION__); + __func__); BUG(); } } @@ -7781,7 +7778,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) return -ENOMEM; } if ((ret = pci_request_regions(pdev, s2io_driver_name))) { - DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", __FUNCTION__, ret); + DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", __func__, ret); pci_disable_device(pdev); return -ENODEV; } @@ -7998,7 +7995,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_verify_pci_mode(sp); if (mode < 0) { - DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__); + DBG_PRINT(ERR_DBG, "%s: ", __func__); DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n"); ret = -EBADSLT; goto set_swap_failed; @@ -8175,8 +8172,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) break; } if (sp->config.multiq) { - for (i = 0; i < sp->config.tx_fifo_num; i++) - mac_control->fifos[i].multiq = config->multiq; + for (i = 0; i < sp->config.tx_fifo_num; i++) + mac_control->fifos[i].multiq = config->multiq; DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n", dev->name); } else @@ -8206,6 +8203,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Initialize device name */ sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name); + if (vlan_tag_strip) + sp->vlan_strip_flag = 1; + else + sp->vlan_strip_flag = 0; + /* * Make Link state as off at this point, when the Link change * interrupt comes the state will be automatically changed to @@ -8299,7 +8301,7 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) { DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n", - __FUNCTION__); + __func__); return -1; } @@ -8311,7 +8313,7 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, * If vlan stripping is disabled and the frame is VLAN tagged, * shift the offset by the VLAN header size bytes. */ - if ((!vlan_strip_flag) && + if ((!sp->vlan_strip_flag) && (rxdp->Control_1 & RXD_FRAME_VLAN_TAG)) ip_off += HEADER_VLAN_SIZE; } else { @@ -8330,7 +8332,7 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, static int check_for_socket_match(struct lro *lro, struct iphdr *ip, struct tcphdr *tcp) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) || (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest)) return -1; @@ -8345,7 +8347,7 @@ static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp) static void initiate_new_session(struct lro *lro, u8 *l2h, struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len, u16 vlan_tag) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); lro->l2h = l2h; lro->iph = ip; lro->tcph = tcp; @@ -8375,7 +8377,7 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) struct tcphdr *tcp = lro->tcph; __sum16 nchk; struct stat_block *statinfo = sp->mac_control.stats_info; - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); /* Update L3 header */ ip->tot_len = htons(lro->total_len); @@ -8403,7 +8405,7 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) static void aggregate_new_rx(struct lro *lro, struct iphdr *ip, struct tcphdr *tcp, u32 l4_pyld) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); lro->total_len += l4_pyld; lro->frags_len += l4_pyld; lro->tcp_next_seq += l4_pyld; @@ -8427,7 +8429,7 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, { u8 *ptr; - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); if (!tcp_pyld_len) { /* Runt frame or a pure ack */ @@ -8509,7 +8511,7 @@ s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) { DBG_PRINT(INFO_DBG, "%s:Out of order. expected " - "0x%x, actual 0x%x\n", __FUNCTION__, + "0x%x, actual 0x%x\n", __func__, (*lro)->tcp_next_seq, ntohl(tcph->seq)); @@ -8549,7 +8551,7 @@ s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, if (ret == 0) { /* sessions exceeded */ DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n", - __FUNCTION__); + __func__); *lro = NULL; return ret; } @@ -8571,7 +8573,7 @@ s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, break; default: DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n", - __FUNCTION__); + __func__); break; } @@ -8592,7 +8594,7 @@ static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag) skb->protocol = eth_type_trans(skb, dev); if (sp->vlgrp && vlan_tag - && (vlan_strip_flag)) { + && (sp->vlan_strip_flag)) { /* Queueing the vlan frame to the upper layer */ if (sp->config.napi) vlan_hwaccel_receive_skb(skb, sp->vlgrp, vlan_tag); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 6722a2f7d09..55cb943f23f 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -962,6 +962,7 @@ struct s2io_nic { int task_flag; unsigned long long start_time; struct vlan_group *vlgrp; + int vlan_strip_flag; #define MSIX_FLG 0xA5 int num_entries; struct msix_entry *entries; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index fe41e4ec21e..2615d46e6e5 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -256,7 +256,7 @@ struct sbmac_softc { struct net_device *sbm_dev; /* pointer to linux device */ struct napi_struct napi; struct phy_device *phy_dev; /* the associated PHY device */ - struct mii_bus mii_bus; /* the MII bus */ + struct mii_bus *mii_bus; /* the MII bus */ int phy_irq[PHY_MAX_ADDR]; spinlock_t sbm_lock; /* spin lock */ int sbm_devflags; /* current device flags */ @@ -2069,9 +2069,10 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance) static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); + unsigned long flags; /* lock eth irq */ - spin_lock_irq (&sc->sbm_lock); + spin_lock_irqsave(&sc->sbm_lock, flags); /* * Put the buffer on the transmit ring. If we @@ -2081,14 +2082,14 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) { /* XXX save skb that we could not send */ netif_stop_queue(dev); - spin_unlock_irq(&sc->sbm_lock); + spin_unlock_irqrestore(&sc->sbm_lock, flags); return 1; } dev->trans_start = jiffies; - spin_unlock_irq (&sc->sbm_lock); + spin_unlock_irqrestore(&sc->sbm_lock, flags); return 0; } @@ -2347,10 +2348,17 @@ static int sbmac_init(struct platform_device *pldev, long long base) /* This is needed for PASS2 for Rx H/W checksum feature */ sbmac_set_iphdr_offset(sc); + sc->mii_bus = mdiobus_alloc(); + if (sc->mii_bus == NULL) { + sbmac_uninitctx(sc); + return -ENOMEM; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR "%s.%d: unable to register netdev\n", sbmac_string, idx); + mdiobus_free(sc->mii_bus); sbmac_uninitctx(sc); return err; } @@ -2368,17 +2376,17 @@ static int sbmac_init(struct platform_device *pldev, long long base) pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n", dev->name, base, print_mac(mac, eaddr)); - sc->mii_bus.name = sbmac_mdio_string; - snprintf(sc->mii_bus.id, MII_BUS_ID_SIZE, "%x", idx); - sc->mii_bus.priv = sc; - sc->mii_bus.read = sbmac_mii_read; - sc->mii_bus.write = sbmac_mii_write; - sc->mii_bus.irq = sc->phy_irq; + sc->mii_bus->name = sbmac_mdio_string; + snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx); + sc->mii_bus->priv = sc; + sc->mii_bus->read = sbmac_mii_read; + sc->mii_bus->write = sbmac_mii_write; + sc->mii_bus->irq = sc->phy_irq; for (i = 0; i < PHY_MAX_ADDR; ++i) - sc->mii_bus.irq[i] = SBMAC_PHY_INT; + sc->mii_bus->irq[i] = SBMAC_PHY_INT; - sc->mii_bus.dev = &pldev->dev; - dev_set_drvdata(&pldev->dev, &sc->mii_bus); + sc->mii_bus->parent = &pldev->dev; + dev_set_drvdata(&pldev->dev, sc->mii_bus); return 0; } @@ -2409,7 +2417,7 @@ static int sbmac_open(struct net_device *dev) /* * Probe PHY address */ - err = mdiobus_register(&sc->mii_bus); + err = mdiobus_register(sc->mii_bus); if (err) { printk(KERN_ERR "%s: unable to register MDIO bus\n", dev->name); @@ -2446,7 +2454,7 @@ static int sbmac_open(struct net_device *dev) return 0; out_unregister: - mdiobus_unregister(&sc->mii_bus); + mdiobus_unregister(sc->mii_bus); out_unirq: free_irq(dev->irq, dev); @@ -2462,7 +2470,7 @@ static int sbmac_mii_probe(struct net_device *dev) int i; for (i = 0; i < PHY_MAX_ADDR; i++) { - phy_dev = sc->mii_bus.phy_map[i]; + phy_dev = sc->mii_bus->phy_map[i]; if (phy_dev) break; } @@ -2568,14 +2576,15 @@ static void sbmac_mii_poll(struct net_device *dev) static void sbmac_tx_timeout (struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); + unsigned long flags; - spin_lock_irq (&sc->sbm_lock); + spin_lock_irqsave(&sc->sbm_lock, flags); dev->trans_start = jiffies; dev->stats.tx_errors++; - spin_unlock_irq (&sc->sbm_lock); + spin_unlock_irqrestore(&sc->sbm_lock, flags); printk (KERN_WARNING "%s: Transmit timed out\n",dev->name); } @@ -2639,7 +2648,7 @@ static int sbmac_close(struct net_device *dev) phy_disconnect(sc->phy_dev); sc->phy_dev = NULL; - mdiobus_unregister(&sc->mii_bus); + mdiobus_unregister(sc->mii_bus); free_irq(dev->irq, dev); @@ -2748,6 +2757,7 @@ static int __exit sbmac_remove(struct platform_device *pldev) unregister_netdev(dev); sbmac_uninitctx(sc); + mdiobus_free(sc->mii_bus); iounmap(sc->sbm_base); free_netdev(dev); diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h index 2c79d27404e..d95c2182801 100644 --- a/drivers/net/sfc/bitfield.h +++ b/drivers/net/sfc/bitfield.h @@ -52,9 +52,9 @@ * * The maximum width mask that can be generated is 64 bits. */ -#define EFX_MASK64(field) \ - (EFX_WIDTH(field) == 64 ? ~((u64) 0) : \ - (((((u64) 1) << EFX_WIDTH(field))) - 1)) +#define EFX_MASK64(width) \ + ((width) == 64 ? ~((u64) 0) : \ + (((((u64) 1) << (width))) - 1)) /* Mask equal in width to the specified field. * @@ -63,9 +63,9 @@ * The maximum width mask that can be generated is 32 bits. Use * EFX_MASK64 for higher width fields. */ -#define EFX_MASK32(field) \ - (EFX_WIDTH(field) == 32 ? ~((u32) 0) : \ - (((((u32) 1) << EFX_WIDTH(field))) - 1)) +#define EFX_MASK32(width) \ + ((width) == 32 ? ~((u32) 0) : \ + (((((u32) 1) << (width))) - 1)) /* A doubleword (i.e. 4 byte) datatype - little-endian in HW */ typedef union efx_dword { @@ -138,44 +138,49 @@ typedef union efx_oword { EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high) #define EFX_EXTRACT_OWORD64(oword, low, high) \ - (EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) | \ - EFX_EXTRACT64((oword).u64[1], 64, 127, low, high)) + ((EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) | \ + EFX_EXTRACT64((oword).u64[1], 64, 127, low, high)) & \ + EFX_MASK64(high + 1 - low)) #define EFX_EXTRACT_QWORD64(qword, low, high) \ - EFX_EXTRACT64((qword).u64[0], 0, 63, low, high) + (EFX_EXTRACT64((qword).u64[0], 0, 63, low, high) & \ + EFX_MASK64(high + 1 - low)) #define EFX_EXTRACT_OWORD32(oword, low, high) \ - (EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) | \ - EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) | \ - EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) | \ - EFX_EXTRACT32((oword).u32[3], 96, 127, low, high)) + ((EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) | \ + EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) | \ + EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) | \ + EFX_EXTRACT32((oword).u32[3], 96, 127, low, high)) & \ + EFX_MASK32(high + 1 - low)) #define EFX_EXTRACT_QWORD32(qword, low, high) \ - (EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) | \ - EFX_EXTRACT32((qword).u32[1], 32, 63, low, high)) + ((EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) | \ + EFX_EXTRACT32((qword).u32[1], 32, 63, low, high)) & \ + EFX_MASK32(high + 1 - low)) -#define EFX_EXTRACT_DWORD(dword, low, high) \ - EFX_EXTRACT32((dword).u32[0], 0, 31, low, high) +#define EFX_EXTRACT_DWORD(dword, low, high) \ + (EFX_EXTRACT32((dword).u32[0], 0, 31, low, high) & \ + EFX_MASK32(high + 1 - low)) -#define EFX_OWORD_FIELD64(oword, field) \ - (EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ - & EFX_MASK64(field)) +#define EFX_OWORD_FIELD64(oword, field) \ + EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field)) -#define EFX_QWORD_FIELD64(qword, field) \ - (EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ - & EFX_MASK64(field)) +#define EFX_QWORD_FIELD64(qword, field) \ + EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field)) -#define EFX_OWORD_FIELD32(oword, field) \ - (EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ - & EFX_MASK32(field)) +#define EFX_OWORD_FIELD32(oword, field) \ + EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field)) -#define EFX_QWORD_FIELD32(qword, field) \ - (EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ - & EFX_MASK32(field)) +#define EFX_QWORD_FIELD32(qword, field) \ + EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field)) -#define EFX_DWORD_FIELD(dword, field) \ - (EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ - & EFX_MASK32(field)) +#define EFX_DWORD_FIELD(dword, field) \ + EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field)) #define EFX_OWORD_IS_ZERO64(oword) \ (((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0) @@ -411,69 +416,102 @@ typedef union efx_oword { * for read-modify-write operations. * */ - #define EFX_INVERT_OWORD(oword) do { \ (oword).u64[0] = ~((oword).u64[0]); \ (oword).u64[1] = ~((oword).u64[1]); \ } while (0) -#define EFX_INSERT_FIELD64(...) \ - cpu_to_le64(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__)) +#define EFX_AND_OWORD(oword, from, mask) \ + do { \ + (oword).u64[0] = (from).u64[0] & (mask).u64[0]; \ + (oword).u64[1] = (from).u64[1] & (mask).u64[1]; \ + } while (0) + +#define EFX_OR_OWORD(oword, from, mask) \ + do { \ + (oword).u64[0] = (from).u64[0] | (mask).u64[0]; \ + (oword).u64[1] = (from).u64[1] | (mask).u64[1]; \ + } while (0) -#define EFX_INSERT_FIELD32(...) \ - cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__)) +#define EFX_INSERT64(min, max, low, high, value) \ + cpu_to_le64(EFX_INSERT_NATIVE(min, max, low, high, value)) -#define EFX_INPLACE_MASK64(min, max, field) \ - EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field)) +#define EFX_INSERT32(min, max, low, high, value) \ + cpu_to_le32(EFX_INSERT_NATIVE(min, max, low, high, value)) -#define EFX_INPLACE_MASK32(min, max, field) \ - EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field)) +#define EFX_INPLACE_MASK64(min, max, low, high) \ + EFX_INSERT64(min, max, low, high, EFX_MASK64(high + 1 - low)) -#define EFX_SET_OWORD_FIELD64(oword, field, value) do { \ +#define EFX_INPLACE_MASK32(min, max, low, high) \ + EFX_INSERT32(min, max, low, high, EFX_MASK32(high + 1 - low)) + +#define EFX_SET_OWORD64(oword, low, high, value) do { \ (oword).u64[0] = (((oword).u64[0] \ - & ~EFX_INPLACE_MASK64(0, 63, field)) \ - | EFX_INSERT_FIELD64(0, 63, field, value)); \ + & ~EFX_INPLACE_MASK64(0, 63, low, high)) \ + | EFX_INSERT64(0, 63, low, high, value)); \ (oword).u64[1] = (((oword).u64[1] \ - & ~EFX_INPLACE_MASK64(64, 127, field)) \ - | EFX_INSERT_FIELD64(64, 127, field, value)); \ + & ~EFX_INPLACE_MASK64(64, 127, low, high)) \ + | EFX_INSERT64(64, 127, low, high, value)); \ } while (0) -#define EFX_SET_QWORD_FIELD64(qword, field, value) do { \ +#define EFX_SET_QWORD64(qword, low, high, value) do { \ (qword).u64[0] = (((qword).u64[0] \ - & ~EFX_INPLACE_MASK64(0, 63, field)) \ - | EFX_INSERT_FIELD64(0, 63, field, value)); \ + & ~EFX_INPLACE_MASK64(0, 63, low, high)) \ + | EFX_INSERT64(0, 63, low, high, value)); \ } while (0) -#define EFX_SET_OWORD_FIELD32(oword, field, value) do { \ +#define EFX_SET_OWORD32(oword, low, high, value) do { \ (oword).u32[0] = (((oword).u32[0] \ - & ~EFX_INPLACE_MASK32(0, 31, field)) \ - | EFX_INSERT_FIELD32(0, 31, field, value)); \ + & ~EFX_INPLACE_MASK32(0, 31, low, high)) \ + | EFX_INSERT32(0, 31, low, high, value)); \ (oword).u32[1] = (((oword).u32[1] \ - & ~EFX_INPLACE_MASK32(32, 63, field)) \ - | EFX_INSERT_FIELD32(32, 63, field, value)); \ + & ~EFX_INPLACE_MASK32(32, 63, low, high)) \ + | EFX_INSERT32(32, 63, low, high, value)); \ (oword).u32[2] = (((oword).u32[2] \ - & ~EFX_INPLACE_MASK32(64, 95, field)) \ - | EFX_INSERT_FIELD32(64, 95, field, value)); \ + & ~EFX_INPLACE_MASK32(64, 95, low, high)) \ + | EFX_INSERT32(64, 95, low, high, value)); \ (oword).u32[3] = (((oword).u32[3] \ - & ~EFX_INPLACE_MASK32(96, 127, field)) \ - | EFX_INSERT_FIELD32(96, 127, field, value)); \ + & ~EFX_INPLACE_MASK32(96, 127, low, high)) \ + | EFX_INSERT32(96, 127, low, high, value)); \ } while (0) -#define EFX_SET_QWORD_FIELD32(qword, field, value) do { \ +#define EFX_SET_QWORD32(qword, low, high, value) do { \ (qword).u32[0] = (((qword).u32[0] \ - & ~EFX_INPLACE_MASK32(0, 31, field)) \ - | EFX_INSERT_FIELD32(0, 31, field, value)); \ + & ~EFX_INPLACE_MASK32(0, 31, low, high)) \ + | EFX_INSERT32(0, 31, low, high, value)); \ (qword).u32[1] = (((qword).u32[1] \ - & ~EFX_INPLACE_MASK32(32, 63, field)) \ - | EFX_INSERT_FIELD32(32, 63, field, value)); \ + & ~EFX_INPLACE_MASK32(32, 63, low, high)) \ + | EFX_INSERT32(32, 63, low, high, value)); \ } while (0) -#define EFX_SET_DWORD_FIELD(dword, field, value) do { \ - (dword).u32[0] = (((dword).u32[0] \ - & ~EFX_INPLACE_MASK32(0, 31, field)) \ - | EFX_INSERT_FIELD32(0, 31, field, value)); \ +#define EFX_SET_DWORD32(dword, low, high, value) do { \ + (dword).u32[0] = (((dword).u32[0] \ + & ~EFX_INPLACE_MASK32(0, 31, low, high)) \ + | EFX_INSERT32(0, 31, low, high, value)); \ } while (0) +#define EFX_SET_OWORD_FIELD64(oword, field, value) \ + EFX_SET_OWORD64(oword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field), value) + +#define EFX_SET_QWORD_FIELD64(qword, field, value) \ + EFX_SET_QWORD64(qword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field), value) + +#define EFX_SET_OWORD_FIELD32(oword, field, value) \ + EFX_SET_OWORD32(oword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field), value) + +#define EFX_SET_QWORD_FIELD32(qword, field, value) \ + EFX_SET_QWORD32(qword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field), value) + +#define EFX_SET_DWORD_FIELD(dword, field, value) \ + EFX_SET_DWORD32(dword, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field), value) + + + #if BITS_PER_LONG == 64 #define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64 #define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64 @@ -502,4 +540,10 @@ typedef union efx_oword { #define EFX_DMA_TYPE_WIDTH(width) \ (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH) + +/* Static initialiser */ +#define EFX_OWORD32(a, b, c, d) \ + { .u32 = { __constant_cpu_to_le32(a), __constant_cpu_to_le32(b), \ + __constant_cpu_to_le32(c), __constant_cpu_to_le32(d) } } + #endif /* EFX_BITFIELD_H */ diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c index d3d3dd0a117..99e60237326 100644 --- a/drivers/net/sfc/boards.c +++ b/drivers/net/sfc/boards.c @@ -31,23 +31,23 @@ static void blink_led_timer(unsigned long context) mod_timer(&bl->timer, jiffies + BLINK_INTERVAL); } -static void board_blink(struct efx_nic *efx, int blink) +static void board_blink(struct efx_nic *efx, bool blink) { struct efx_blinker *blinker = &efx->board_info.blinker; /* The rtnl mutex serialises all ethtool ioctls, so * nothing special needs doing here. */ if (blink) { - blinker->resubmit = 1; - blinker->state = 0; + blinker->resubmit = true; + blinker->state = false; setup_timer(&blinker->timer, blink_led_timer, (unsigned long)efx); mod_timer(&blinker->timer, jiffies + BLINK_INTERVAL); } else { - blinker->resubmit = 0; + blinker->resubmit = false; if (blinker->timer.function) del_timer_sync(&blinker->timer); - efx->board_info.set_fault_led(efx, 0); + efx->board_info.set_fault_led(efx, false); } } @@ -78,7 +78,7 @@ static int sfe4002_init_leds(struct efx_nic *efx) return 0; } -static void sfe4002_fault_led(struct efx_nic *efx, int state) +static void sfe4002_fault_led(struct efx_nic *efx, bool state) { xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON : QUAKE_LED_OFF); diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h index e5e844359ce..c6e01b64bfb 100644 --- a/drivers/net/sfc/boards.h +++ b/drivers/net/sfc/boards.h @@ -21,7 +21,5 @@ enum efx_board_type { extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info); extern int sfe4001_init(struct efx_nic *efx); -/* Are we putting the PHY into flash config mode */ -extern unsigned int sfe4001_phy_flash_cfg; #endif diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 45c72eebb3a..06ea71c7e34 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -28,7 +28,6 @@ #include "efx.h" #include "mdio_10g.h" #include "falcon.h" -#include "workarounds.h" #include "mac.h" #define EFX_MAX_MTU (9 * 1024) @@ -52,7 +51,7 @@ static struct workqueue_struct *refill_workqueue; * This sets the default for new devices. It can be controlled later * using ethtool. */ -static int lro = 1; +static int lro = true; module_param(lro, int, 0644); MODULE_PARM_DESC(lro, "Large receive offload acceleration"); @@ -65,7 +64,7 @@ MODULE_PARM_DESC(lro, "Large receive offload acceleration"); * This is forced to 0 for MSI interrupt mode as the interrupt vector * is not written */ -static unsigned int separate_tx_and_rx_channels = 1; +static unsigned int separate_tx_and_rx_channels = true; /* This is the weight assigned to each of the (per-channel) virtual * NAPI devices. @@ -81,7 +80,7 @@ unsigned int efx_monitor_interval = 1 * HZ; /* This controls whether or not the hardware monitor will trigger a * reset when it detects an error condition. */ -static unsigned int monitor_reset = 1; +static unsigned int monitor_reset = true; /* This controls whether or not the driver will initialise devices * with invalid MAC addresses stored in the EEPROM or flash. If true, @@ -141,8 +140,7 @@ static void efx_fini_channels(struct efx_nic *efx); #define EFX_ASSERT_RESET_SERIALISED(efx) \ do { \ - if ((efx->state == STATE_RUNNING) || \ - (efx->state == STATE_RESETTING)) \ + if (efx->state == STATE_RUNNING) \ ASSERT_RTNL(); \ } while (0) @@ -159,16 +157,18 @@ static void efx_fini_channels(struct efx_nic *efx); * never be concurrently called more than once on the same channel, * though different channels may be being processed concurrently. */ -static inline int efx_process_channel(struct efx_channel *channel, int rx_quota) +static int efx_process_channel(struct efx_channel *channel, int rx_quota) { - int rxdmaqs; - struct efx_rx_queue *rx_queue; + struct efx_nic *efx = channel->efx; + int rx_packets; - if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE || + if (unlikely(efx->reset_pending != RESET_TYPE_NONE || !channel->enabled)) - return rx_quota; + return 0; - rxdmaqs = falcon_process_eventq(channel, &rx_quota); + rx_packets = falcon_process_eventq(channel, rx_quota); + if (rx_packets == 0) + return 0; /* Deliver last RX packet. */ if (channel->rx_pkt) { @@ -180,16 +180,9 @@ static inline int efx_process_channel(struct efx_channel *channel, int rx_quota) efx_flush_lro(channel); efx_rx_strategy(channel); - /* Refill descriptor rings as necessary */ - rx_queue = &channel->efx->rx_queue[0]; - while (rxdmaqs) { - if (rxdmaqs & 0x01) - efx_fast_push_rx_descriptors(rx_queue); - rx_queue++; - rxdmaqs >>= 1; - } + efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]); - return rx_quota; + return rx_packets; } /* Mark channel as finished processing @@ -203,7 +196,7 @@ static inline void efx_channel_processed(struct efx_channel *channel) /* The interrupt handler for this channel may set work_pending * as soon as we acknowledge the events we've seen. Make sure * it's cleared before then. */ - channel->work_pending = 0; + channel->work_pending = false; smp_wmb(); falcon_eventq_read_ack(channel); @@ -219,14 +212,12 @@ static int efx_poll(struct napi_struct *napi, int budget) struct efx_channel *channel = container_of(napi, struct efx_channel, napi_str); struct net_device *napi_dev = channel->napi_dev; - int unused; int rx_packets; EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n", channel->channel, raw_smp_processor_id()); - unused = efx_process_channel(channel, budget); - rx_packets = (budget - unused); + rx_packets = efx_process_channel(channel, budget); if (rx_packets < budget) { /* There is no race here; although napi_disable() will @@ -260,7 +251,7 @@ void efx_process_channel_now(struct efx_channel *channel) falcon_disable_interrupts(efx); if (efx->legacy_irq) synchronize_irq(efx->legacy_irq); - if (channel->has_interrupt && channel->irq) + if (channel->irq) synchronize_irq(channel->irq); /* Wait for any NAPI processing to complete */ @@ -290,13 +281,13 @@ static int efx_probe_eventq(struct efx_channel *channel) } /* Prepare channel's event queue */ -static int efx_init_eventq(struct efx_channel *channel) +static void efx_init_eventq(struct efx_channel *channel) { EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel); channel->eventq_read_ptr = 0; - return falcon_init_eventq(channel); + falcon_init_eventq(channel); } static void efx_fini_eventq(struct efx_channel *channel) @@ -362,12 +353,11 @@ static int efx_probe_channel(struct efx_channel *channel) * to propagate configuration changes (mtu, checksum offload), or * to clear hardware error conditions */ -static int efx_init_channels(struct efx_nic *efx) +static void efx_init_channels(struct efx_nic *efx) { struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; struct efx_channel *channel; - int rc = 0; /* Calculate the rx buffer allocation parameters required to * support the current MTU, including padding for header @@ -382,36 +372,20 @@ static int efx_init_channels(struct efx_nic *efx) efx_for_each_channel(channel, efx) { EFX_LOG(channel->efx, "init chan %d\n", channel->channel); - rc = efx_init_eventq(channel); - if (rc) - goto err; + efx_init_eventq(channel); - efx_for_each_channel_tx_queue(tx_queue, channel) { - rc = efx_init_tx_queue(tx_queue); - if (rc) - goto err; - } + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_init_tx_queue(tx_queue); /* The rx buffer allocation strategy is MTU dependent */ efx_rx_strategy(channel); - efx_for_each_channel_rx_queue(rx_queue, channel) { - rc = efx_init_rx_queue(rx_queue); - if (rc) - goto err; - } + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_init_rx_queue(rx_queue); WARN_ON(channel->rx_pkt != NULL); efx_rx_strategy(channel); } - - return 0; - - err: - EFX_ERR(efx, "failed to initialise channel %d\n", - channel ? channel->channel : -1); - efx_fini_channels(efx); - return rc; } /* This enables event queue processing and packet transmission. @@ -432,8 +406,8 @@ static void efx_start_channel(struct efx_channel *channel) /* The interrupt handler for this channel may set work_pending * as soon as we enable it. Make sure it's cleared before * then. Similarly, make sure it sees the enabled flag set. */ - channel->work_pending = 0; - channel->enabled = 1; + channel->work_pending = false; + channel->enabled = true; smp_wmb(); napi_enable(&channel->napi_str); @@ -456,7 +430,7 @@ static void efx_stop_channel(struct efx_channel *channel) EFX_LOG(channel->efx, "stop chan %d\n", channel->channel); - channel->enabled = 0; + channel->enabled = false; napi_disable(&channel->napi_str); /* Ensure that any worker threads have exited or will be no-ops */ @@ -471,10 +445,17 @@ static void efx_fini_channels(struct efx_nic *efx) struct efx_channel *channel; struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; + int rc; EFX_ASSERT_RESET_SERIALISED(efx); BUG_ON(efx->port_enabled); + rc = falcon_flush_queues(efx); + if (rc) + EFX_ERR(efx, "failed to flush queues\n"); + else + EFX_LOG(efx, "successfully flushed all queues\n"); + efx_for_each_channel(channel, efx) { EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel); @@ -482,13 +463,6 @@ static void efx_fini_channels(struct efx_nic *efx) efx_fini_rx_queue(rx_queue); efx_for_each_channel_tx_queue(tx_queue, channel) efx_fini_tx_queue(tx_queue); - } - - /* Do the event queues last so that we can handle flush events - * for all DMA queues. */ - efx_for_each_channel(channel, efx) { - EFX_LOG(channel->efx, "shut down evq %d\n", channel->channel); - efx_fini_eventq(channel); } } @@ -526,8 +500,6 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay) */ static void efx_link_status_changed(struct efx_nic *efx) { - int carrier_ok; - /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure * that no events are triggered between unregister_netdev() and the * driver unloading. A more general condition is that NETDEV_CHANGE @@ -535,8 +507,12 @@ static void efx_link_status_changed(struct efx_nic *efx) if (!netif_running(efx->net_dev)) return; - carrier_ok = netif_carrier_ok(efx->net_dev) ? 1 : 0; - if (efx->link_up != carrier_ok) { + if (efx->port_inhibited) { + netif_carrier_off(efx->net_dev); + return; + } + + if (efx->link_up != netif_carrier_ok(efx->net_dev)) { efx->n_link_state_changes++; if (efx->link_up) @@ -577,13 +553,19 @@ static void efx_link_status_changed(struct efx_nic *efx) /* This call reinitialises the MAC to pick up new PHY settings. The * caller must hold the mac_lock */ -static void __efx_reconfigure_port(struct efx_nic *efx) +void __efx_reconfigure_port(struct efx_nic *efx) { WARN_ON(!mutex_is_locked(&efx->mac_lock)); EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n", raw_smp_processor_id()); + /* Serialise the promiscuous flag with efx_set_multicast_list. */ + if (efx_dev_registered(efx)) { + netif_addr_lock_bh(efx->net_dev); + netif_addr_unlock_bh(efx->net_dev); + } + falcon_reconfigure_xmac(efx); /* Inform kernel of loss/gain of carrier */ @@ -661,7 +643,8 @@ static int efx_init_port(struct efx_nic *efx) if (rc) return rc; - efx->port_initialized = 1; + efx->port_initialized = true; + efx->stats_enabled = true; /* Reconfigure port to program MAC registers */ falcon_reconfigure_xmac(efx); @@ -678,7 +661,7 @@ static void efx_start_port(struct efx_nic *efx) BUG_ON(efx->port_enabled); mutex_lock(&efx->mac_lock); - efx->port_enabled = 1; + efx->port_enabled = true; __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); } @@ -692,7 +675,7 @@ static void efx_stop_port(struct efx_nic *efx) EFX_LOG(efx, "stop port\n"); mutex_lock(&efx->mac_lock); - efx->port_enabled = 0; + efx->port_enabled = false; mutex_unlock(&efx->mac_lock); /* Serialise against efx_set_multicast_list() */ @@ -710,9 +693,9 @@ static void efx_fini_port(struct efx_nic *efx) return; falcon_fini_xmac(efx); - efx->port_initialized = 0; + efx->port_initialized = false; - efx->link_up = 0; + efx->link_up = false; efx_link_status_changed(efx); } @@ -797,7 +780,7 @@ static int efx_init_io(struct efx_nic *efx) return 0; fail4: - release_mem_region(efx->membase_phys, efx->type->mem_map_size); + pci_release_region(efx->pci_dev, efx->type->mem_bar); fail3: efx->membase_phys = 0; fail2: @@ -823,53 +806,61 @@ static void efx_fini_io(struct efx_nic *efx) pci_disable_device(efx->pci_dev); } -/* Probe the number and type of interrupts we are able to obtain. */ +/* Get number of RX queues wanted. Return number of online CPU + * packages in the expectation that an IRQ balancer will spread + * interrupts across them. */ +static int efx_wanted_rx_queues(void) +{ + cpumask_t core_mask; + int count; + int cpu; + + cpus_clear(core_mask); + count = 0; + for_each_online_cpu(cpu) { + if (!cpu_isset(cpu, core_mask)) { + ++count; + cpus_or(core_mask, core_mask, + topology_core_siblings(cpu)); + } + } + + return count; +} + +/* Probe the number and type of interrupts we are able to obtain, and + * the resulting numbers of channels and RX queues. + */ static void efx_probe_interrupts(struct efx_nic *efx) { - int max_channel = efx->type->phys_addr_channels - 1; - struct msix_entry xentries[EFX_MAX_CHANNELS]; + int max_channels = + min_t(int, efx->type->phys_addr_channels, EFX_MAX_CHANNELS); int rc, i; if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { - BUG_ON(!pci_find_capability(efx->pci_dev, PCI_CAP_ID_MSIX)); - - if (rss_cpus == 0) { - cpumask_t core_mask; - int cpu; - - cpus_clear(core_mask); - efx->rss_queues = 0; - for_each_online_cpu(cpu) { - if (!cpu_isset(cpu, core_mask)) { - ++efx->rss_queues; - cpus_or(core_mask, core_mask, - topology_core_siblings(cpu)); - } - } - } else { - efx->rss_queues = rss_cpus; - } + struct msix_entry xentries[EFX_MAX_CHANNELS]; + int wanted_ints; - efx->rss_queues = min(efx->rss_queues, max_channel + 1); - efx->rss_queues = min(efx->rss_queues, EFX_MAX_CHANNELS); + /* We want one RX queue and interrupt per CPU package + * (or as specified by the rss_cpus module parameter). + * We will need one channel per interrupt. + */ + wanted_ints = rss_cpus ? rss_cpus : efx_wanted_rx_queues(); + efx->n_rx_queues = min(wanted_ints, max_channels); - /* Request maximum number of MSI interrupts, and fill out - * the channel interrupt information the allowed allocation */ - for (i = 0; i < efx->rss_queues; i++) + for (i = 0; i < efx->n_rx_queues; i++) xentries[i].entry = i; - rc = pci_enable_msix(efx->pci_dev, xentries, efx->rss_queues); + rc = pci_enable_msix(efx->pci_dev, xentries, efx->n_rx_queues); if (rc > 0) { - EFX_BUG_ON_PARANOID(rc >= efx->rss_queues); - efx->rss_queues = rc; + EFX_BUG_ON_PARANOID(rc >= efx->n_rx_queues); + efx->n_rx_queues = rc; rc = pci_enable_msix(efx->pci_dev, xentries, - efx->rss_queues); + efx->n_rx_queues); } if (rc == 0) { - for (i = 0; i < efx->rss_queues; i++) { - efx->channel[i].has_interrupt = 1; + for (i = 0; i < efx->n_rx_queues; i++) efx->channel[i].irq = xentries[i].vector; - } } else { /* Fall back to single channel MSI */ efx->interrupt_mode = EFX_INT_MODE_MSI; @@ -879,11 +870,10 @@ static void efx_probe_interrupts(struct efx_nic *efx) /* Try single interrupt MSI */ if (efx->interrupt_mode == EFX_INT_MODE_MSI) { - efx->rss_queues = 1; + efx->n_rx_queues = 1; rc = pci_enable_msi(efx->pci_dev); if (rc == 0) { efx->channel[0].irq = efx->pci_dev->irq; - efx->channel[0].has_interrupt = 1; } else { EFX_ERR(efx, "could not enable MSI\n"); efx->interrupt_mode = EFX_INT_MODE_LEGACY; @@ -892,10 +882,7 @@ static void efx_probe_interrupts(struct efx_nic *efx) /* Assume legacy interrupts */ if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) { - efx->rss_queues = 1; - /* Every channel is interruptible */ - for (i = 0; i < EFX_MAX_CHANNELS; i++) - efx->channel[i].has_interrupt = 1; + efx->n_rx_queues = 1; efx->legacy_irq = efx->pci_dev->irq; } } @@ -905,7 +892,7 @@ static void efx_remove_interrupts(struct efx_nic *efx) struct efx_channel *channel; /* Remove MSI/MSI-X interrupts */ - efx_for_each_channel_with_interrupt(channel, efx) + efx_for_each_channel(channel, efx) channel->irq = 0; pci_disable_msi(efx->pci_dev); pci_disable_msix(efx->pci_dev); @@ -914,45 +901,22 @@ static void efx_remove_interrupts(struct efx_nic *efx) efx->legacy_irq = 0; } -/* Select number of used resources - * Should be called after probe_interrupts() - */ -static void efx_select_used(struct efx_nic *efx) +static void efx_set_channels(struct efx_nic *efx) { struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; - int i; - /* TX queues. One per port per channel with TX capability - * (more than one per port won't work on Linux, due to out - * of order issues... but will be fine on Solaris) - */ - tx_queue = &efx->tx_queue[0]; - - /* Perform this for each channel with TX capabilities. - * At the moment, we only support a single TX queue - */ - tx_queue->used = 1; - if ((!EFX_INT_MODE_USE_MSI(efx)) && separate_tx_and_rx_channels) - tx_queue->channel = &efx->channel[1]; - else - tx_queue->channel = &efx->channel[0]; - tx_queue->channel->used_flags |= EFX_USED_BY_TX; - tx_queue++; - - /* RX queues. Each has a dedicated channel. */ - for (i = 0; i < EFX_MAX_RX_QUEUES; i++) { - rx_queue = &efx->rx_queue[i]; + efx_for_each_tx_queue(tx_queue, efx) { + if (!EFX_INT_MODE_USE_MSI(efx) && separate_tx_and_rx_channels) + tx_queue->channel = &efx->channel[1]; + else + tx_queue->channel = &efx->channel[0]; + tx_queue->channel->used_flags |= EFX_USED_BY_TX; + } - if (i < efx->rss_queues) { - rx_queue->used = 1; - /* If we allow multiple RX queues per channel - * we need to decide that here - */ - rx_queue->channel = &efx->channel[rx_queue->queue]; - rx_queue->channel->used_flags |= EFX_USED_BY_RX; - rx_queue++; - } + efx_for_each_rx_queue(rx_queue, efx) { + rx_queue->channel = &efx->channel[rx_queue->queue]; + rx_queue->channel->used_flags |= EFX_USED_BY_RX; } } @@ -971,8 +935,7 @@ static int efx_probe_nic(struct efx_nic *efx) * in MSI-X interrupts. */ efx_probe_interrupts(efx); - /* Determine number of RX queues and TX queues */ - efx_select_used(efx); + efx_set_channels(efx); /* Initialise the interrupt moderation settings */ efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec); @@ -1058,7 +1021,8 @@ static void efx_start_all(struct efx_nic *efx) /* Mark the port as enabled so port reconfigurations can start, then * restart the transmit interface early so the watchdog timer stops */ efx_start_port(efx); - efx_wake_queue(efx); + if (efx_dev_registered(efx)) + efx_wake_queue(efx); efx_for_each_channel(channel, efx) efx_start_channel(channel); @@ -1109,7 +1073,7 @@ static void efx_stop_all(struct efx_nic *efx) falcon_disable_interrupts(efx); if (efx->legacy_irq) synchronize_irq(efx->legacy_irq); - efx_for_each_channel_with_interrupt(channel, efx) { + efx_for_each_channel(channel, efx) { if (channel->irq) synchronize_irq(channel->irq); } @@ -1128,13 +1092,12 @@ static void efx_stop_all(struct efx_nic *efx) /* Isolate the MAC from the TX and RX engines, so that queue * flushes will complete in a timely fashion. */ - falcon_deconfigure_mac_wrapper(efx); falcon_drain_tx_fifo(efx); /* Stop the kernel transmit interface late, so the watchdog * timer isn't ticking over the flush */ - efx_stop_queue(efx); if (efx_dev_registered(efx)) { + efx_stop_queue(efx); netif_tx_lock_bh(efx->net_dev); netif_tx_unlock_bh(efx->net_dev); } @@ -1151,24 +1114,16 @@ static void efx_remove_all(struct efx_nic *efx) } /* A convinience function to safely flush all the queues */ -int efx_flush_queues(struct efx_nic *efx) +void efx_flush_queues(struct efx_nic *efx) { - int rc; - EFX_ASSERT_RESET_SERIALISED(efx); efx_stop_all(efx); efx_fini_channels(efx); - rc = efx_init_channels(efx); - if (rc) { - efx_schedule_reset(efx, RESET_TYPE_DISABLE); - return rc; - } + efx_init_channels(efx); efx_start_all(efx); - - return 0; } /************************************************************************** @@ -1249,7 +1204,7 @@ static void efx_monitor(struct work_struct *data) */ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); EFX_ASSERT_RESET_SERIALISED(efx); @@ -1303,10 +1258,10 @@ static void efx_fini_napi(struct efx_nic *efx) */ static void efx_netpoll(struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); struct efx_channel *channel; - efx_for_each_channel_with_interrupt(channel, efx) + efx_for_each_channel(channel, efx) efx_schedule_channel(channel); } @@ -1321,12 +1276,15 @@ static void efx_netpoll(struct net_device *net_dev) /* Context: process, rtnl_lock() held. */ static int efx_net_open(struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); EFX_ASSERT_RESET_SERIALISED(efx); EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name, raw_smp_processor_id()); + if (efx->phy_mode & PHY_MODE_SPECIAL) + return -EBUSY; + efx_start_all(efx); return 0; } @@ -1337,8 +1295,7 @@ static int efx_net_open(struct net_device *net_dev) */ static int efx_net_stop(struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; - int rc; + struct efx_nic *efx = netdev_priv(net_dev); EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name, raw_smp_processor_id()); @@ -1346,9 +1303,7 @@ static int efx_net_stop(struct net_device *net_dev) /* Stop the device and flush all the channels */ efx_stop_all(efx); efx_fini_channels(efx); - rc = efx_init_channels(efx); - if (rc) - efx_schedule_reset(efx, RESET_TYPE_DISABLE); + efx_init_channels(efx); return 0; } @@ -1356,7 +1311,7 @@ static int efx_net_stop(struct net_device *net_dev) /* Context: process, dev_base_lock or RTNL held, non-blocking. */ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); struct efx_mac_stats *mac_stats = &efx->mac_stats; struct net_device_stats *stats = &net_dev->stats; @@ -1366,7 +1321,7 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) */ if (!spin_trylock(&efx->stats_lock)) return stats; - if (efx->state == STATE_RUNNING) { + if (efx->stats_enabled) { falcon_update_stats_xmac(efx); falcon_update_nic_stats(efx); } @@ -1403,7 +1358,7 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) /* Context: netif_tx_lock held, BHs disabled. */ static void efx_watchdog(struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n", atomic_read(&efx->netif_stop_count), efx->port_enabled, @@ -1417,7 +1372,7 @@ static void efx_watchdog(struct net_device *net_dev) /* Context: process, rtnl_lock() held. */ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); int rc = 0; EFX_ASSERT_RESET_SERIALISED(efx); @@ -1431,21 +1386,15 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) efx_fini_channels(efx); net_dev->mtu = new_mtu; - rc = efx_init_channels(efx); - if (rc) - goto fail; + efx_init_channels(efx); efx_start_all(efx); return rc; - - fail: - efx_schedule_reset(efx, RESET_TYPE_DISABLE); - return rc; } static int efx_set_mac_address(struct net_device *net_dev, void *data) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); struct sockaddr *addr = data; char *new_addr = addr->sa_data; @@ -1466,26 +1415,19 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) return 0; } -/* Context: netif_tx_lock held, BHs disabled. */ +/* Context: netif_addr_lock held, BHs disabled. */ static void efx_set_multicast_list(struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); struct dev_mc_list *mc_list = net_dev->mc_list; union efx_multicast_hash *mc_hash = &efx->multicast_hash; - int promiscuous; + bool promiscuous = !!(net_dev->flags & IFF_PROMISC); + bool changed = (efx->promiscuous != promiscuous); u32 crc; int bit; int i; - /* Set per-MAC promiscuity flag and reconfigure MAC if necessary */ - promiscuous = (net_dev->flags & IFF_PROMISC) ? 1 : 0; - if (efx->promiscuous != promiscuous) { - efx->promiscuous = promiscuous; - /* Close the window between efx_stop_port() and efx_flush_all() - * by only queuing work when the port is enabled. */ - if (efx->port_enabled) - queue_work(efx->workqueue, &efx->reconfigure_work); - } + efx->promiscuous = promiscuous; /* Build multicast hash table */ if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) { @@ -1500,6 +1442,13 @@ static void efx_set_multicast_list(struct net_device *net_dev) } } + if (!efx->port_enabled) + /* Delay pushing settings until efx_start_port() */ + return; + + if (changed) + queue_work(efx->workqueue, &efx->reconfigure_work); + /* Create and activate new global multicast hash table */ falcon_set_multicast_hash(efx); } @@ -1510,7 +1459,7 @@ static int efx_netdev_event(struct notifier_block *this, struct net_device *net_dev = ptr; if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); strcpy(efx->name, net_dev->name); } @@ -1568,7 +1517,7 @@ static void efx_unregister_netdev(struct efx_nic *efx) if (!efx->net_dev) return; - BUG_ON(efx->net_dev->priv != efx); + BUG_ON(netdev_priv(efx->net_dev) != efx); /* Free up any skbs still remaining. This has to happen before * we try to unregister the netdev as running their destructors @@ -1588,49 +1537,60 @@ static void efx_unregister_netdev(struct efx_nic *efx) * **************************************************************************/ -/* The final hardware and software finalisation before reset. */ -static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) +/* Tears down the entire software state and most of the hardware state + * before reset. */ +void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) { int rc; EFX_ASSERT_RESET_SERIALISED(efx); + /* The net_dev->get_stats handler is quite slow, and will fail + * if a fetch is pending over reset. Serialise against it. */ + spin_lock(&efx->stats_lock); + efx->stats_enabled = false; + spin_unlock(&efx->stats_lock); + + efx_stop_all(efx); + mutex_lock(&efx->mac_lock); + rc = falcon_xmac_get_settings(efx, ecmd); - if (rc) { + if (rc) EFX_ERR(efx, "could not back up PHY settings\n"); - goto fail; - } efx_fini_channels(efx); - return 0; - - fail: - return rc; } -/* The first part of software initialisation after a hardware reset - * This function does not handle serialisation with the kernel, it - * assumes the caller has done this */ -static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd) +/* This function will always ensure that the locks acquired in + * efx_reset_down() are released. A failure return code indicates + * that we were unable to reinitialise the hardware, and the + * driver should be disabled. If ok is false, then the rx and tx + * engines are not restarted, pending a RESET_DISABLE. */ +int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) { int rc; - rc = efx_init_channels(efx); - if (rc) - goto fail1; + EFX_ASSERT_RESET_SERIALISED(efx); - /* Restore MAC and PHY settings. */ - rc = falcon_xmac_set_settings(efx, ecmd); + rc = falcon_init_nic(efx); if (rc) { - EFX_ERR(efx, "could not restore PHY settings\n"); - goto fail2; + EFX_ERR(efx, "failed to initialise NIC\n"); + ok = false; } - return 0; + if (ok) { + efx_init_channels(efx); - fail2: - efx_fini_channels(efx); - fail1: + if (falcon_xmac_set_settings(efx, ecmd)) + EFX_ERR(efx, "could not restore PHY settings\n"); + } + + mutex_unlock(&efx->mac_lock); + + if (ok) { + efx_start_all(efx); + efx->stats_enabled = true; + } return rc; } @@ -1659,25 +1619,14 @@ static int efx_reset(struct efx_nic *efx) goto unlock_rtnl; } - efx->state = STATE_RESETTING; EFX_INFO(efx, "resetting (%d)\n", method); - /* The net_dev->get_stats handler is quite slow, and will fail - * if a fetch is pending over reset. Serialise against it. */ - spin_lock(&efx->stats_lock); - spin_unlock(&efx->stats_lock); - - efx_stop_all(efx); - mutex_lock(&efx->mac_lock); - - rc = efx_reset_down(efx, &ecmd); - if (rc) - goto fail1; + efx_reset_down(efx, &ecmd); rc = falcon_reset_hw(efx, method); if (rc) { EFX_ERR(efx, "failed to reset hardware\n"); - goto fail2; + goto fail; } /* Allow resets to be rescheduled. */ @@ -1689,46 +1638,27 @@ static int efx_reset(struct efx_nic *efx) * can respond to requests. */ pci_set_master(efx->pci_dev); - /* Reinitialise device. This is appropriate in the RESET_TYPE_DISABLE - * case so the driver can talk to external SRAM */ - rc = falcon_init_nic(efx); - if (rc) { - EFX_ERR(efx, "failed to initialise NIC\n"); - goto fail3; - } - /* Leave device stopped if necessary */ if (method == RESET_TYPE_DISABLE) { - /* Reinitialise the device anyway so the driver unload sequence - * can talk to the external SRAM */ - falcon_init_nic(efx); rc = -EIO; - goto fail4; + goto fail; } - rc = efx_reset_up(efx, &ecmd); + rc = efx_reset_up(efx, &ecmd, true); if (rc) - goto fail5; + goto disable; - mutex_unlock(&efx->mac_lock); EFX_LOG(efx, "reset complete\n"); - - efx->state = STATE_RUNNING; - efx_start_all(efx); - unlock_rtnl: rtnl_unlock(); return 0; - fail5: - fail4: - fail3: - fail2: - fail1: + fail: + efx_reset_up(efx, &ecmd, false); + disable: EFX_ERR(efx, "has been disabled\n"); efx->state = STATE_DISABLED; - mutex_unlock(&efx->mac_lock); rtnl_unlock(); efx_unregister_netdev(efx); efx_fini_port(efx); @@ -1801,7 +1731,7 @@ static struct pci_device_id efx_pci_table[] __devinitdata = { * * Dummy PHY/MAC/Board operations * - * Can be used where the MAC does not implement this operation + * Can be used for some unimplemented operations * Needed so all function pointers are valid and do not have to be tested * before use * @@ -1811,7 +1741,7 @@ int efx_port_dummy_op_int(struct efx_nic *efx) return 0; } void efx_port_dummy_op_void(struct efx_nic *efx) {} -void efx_port_dummy_op_blink(struct efx_nic *efx, int blink) {} +void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {} static struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, @@ -1819,20 +1749,14 @@ static struct efx_phy_operations efx_dummy_phy_operations = { .check_hw = efx_port_dummy_op_int, .fini = efx_port_dummy_op_void, .clear_interrupt = efx_port_dummy_op_void, - .reset_xaui = efx_port_dummy_op_void, }; -/* Dummy board operations */ -static int efx_nic_dummy_op_int(struct efx_nic *nic) -{ - return 0; -} - static struct efx_board efx_dummy_board_info = { - .init = efx_nic_dummy_op_int, - .init_leds = efx_port_dummy_op_int, - .set_fault_led = efx_port_dummy_op_blink, - .fini = efx_port_dummy_op_void, + .init = efx_port_dummy_op_int, + .init_leds = efx_port_dummy_op_int, + .set_fault_led = efx_port_dummy_op_blink, + .blink = efx_port_dummy_op_blink, + .fini = efx_port_dummy_op_void, }; /************************************************************************** @@ -1865,7 +1789,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, efx->board_info = efx_dummy_board_info; efx->net_dev = net_dev; - efx->rx_checksum_enabled = 1; + efx->rx_checksum_enabled = true; spin_lock_init(&efx->netif_stop_lock); spin_lock_init(&efx->stats_lock); mutex_init(&efx->mac_lock); @@ -1878,10 +1802,9 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, channel = &efx->channel[i]; channel->efx = efx; channel->channel = i; - channel->evqnum = i; - channel->work_pending = 0; + channel->work_pending = false; } - for (i = 0; i < EFX_MAX_TX_QUEUES; i++) { + for (i = 0; i < EFX_TX_QUEUE_COUNT; i++) { tx_queue = &efx->tx_queue[i]; tx_queue->efx = efx; tx_queue->queue = i; @@ -2056,19 +1979,16 @@ static int efx_pci_probe_main(struct efx_nic *efx) goto fail5; } - rc = efx_init_channels(efx); - if (rc) - goto fail6; + efx_init_channels(efx); rc = falcon_init_interrupt(efx); if (rc) - goto fail7; + goto fail6; return 0; - fail7: - efx_fini_channels(efx); fail6: + efx_fini_channels(efx); efx_fini_port(efx); fail5: fail4: @@ -2105,7 +2025,10 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, NETIF_F_HIGHDMA | NETIF_F_TSO); if (lro) net_dev->features |= NETIF_F_LRO; - efx = net_dev->priv; + /* 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); + efx = netdev_priv(net_dev); pci_set_drvdata(pci_dev, efx); rc = efx_init_struct(efx, type, pci_dev, net_dev); if (rc) diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 3b2f69f4a9a..d02937b70ee 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -28,15 +28,21 @@ extern void efx_wake_queue(struct efx_nic *efx); /* RX */ extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, - unsigned int len, int checksummed, int discard); + unsigned int len, bool checksummed, bool discard); extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay); /* Channels */ extern void efx_process_channel_now(struct efx_channel *channel); -extern int efx_flush_queues(struct efx_nic *efx); +extern void efx_flush_queues(struct efx_nic *efx); /* Ports */ extern void efx_reconfigure_port(struct efx_nic *efx); +extern void __efx_reconfigure_port(struct efx_nic *efx); + +/* Reset handling */ +extern void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd); +extern int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, + bool ok); /* Global */ extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); @@ -50,7 +56,7 @@ extern void efx_hex_dump(const u8 *, unsigned int, const char *); /* Dummy PHY ops for PHY drivers */ extern int efx_port_dummy_op_int(struct efx_nic *efx); extern void efx_port_dummy_op_void(struct efx_nic *efx); -extern void efx_port_dummy_op_blink(struct efx_nic *efx, int blink); +extern void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink); extern unsigned int efx_monitor_interval; @@ -59,7 +65,7 @@ static inline void efx_schedule_channel(struct efx_channel *channel) { EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n", channel->channel, raw_smp_processor_id()); - channel->work_pending = 1; + channel->work_pending = true; netif_rx_schedule(channel->napi_dev, &channel->napi_str); } diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h index c53290d08e2..cec15dbb88e 100644 --- a/drivers/net/sfc/enum.h +++ b/drivers/net/sfc/enum.h @@ -52,12 +52,11 @@ extern const char *efx_loopback_mode_names[]; #define LOOPBACK_MASK(_efx) \ (1 << (_efx)->loopback_mode) -#define LOOPBACK_INTERNAL(_efx) \ - ((LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx)) ? 1 : 0) +#define LOOPBACK_INTERNAL(_efx) \ + (!!(LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx))) -#define LOOPBACK_OUT_OF(_from, _to, _mask) \ - (((LOOPBACK_MASK(_from) & (_mask)) && \ - ((LOOPBACK_MASK(_to) & (_mask)) == 0)) ? 1 : 0) +#define LOOPBACK_OUT_OF(_from, _to, _mask) \ + ((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask))) /*****************************************************************************/ diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index e2c75d10161..fa98af58223 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -17,6 +17,7 @@ #include "ethtool.h" #include "falcon.h" #include "gmii.h" +#include "spi.h" #include "mac.h" const char *efx_loopback_mode_names[] = { @@ -32,8 +33,6 @@ const char *efx_loopback_mode_names[] = { [LOOPBACK_NETWORK] = "NETWORK", }; -static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable); - struct ethtool_string { char name[ETH_GSTRING_LEN]; }; @@ -173,6 +172,11 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { /* Number of ethtool statistics */ #define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats) +/* EEPROM range with gPXE configuration */ +#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB +#define EFX_ETHTOOL_EEPROM_MIN 0x100U +#define EFX_ETHTOOL_EEPROM_MAX 0x400U + /************************************************************************** * * Ethtool operations @@ -183,7 +187,7 @@ 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 seconds) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); efx->board_info.blink(efx, 1); schedule_timeout_interruptible(seconds * HZ); @@ -195,7 +199,7 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds) int efx_ethtool_get_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); int rc; mutex_lock(&efx->mac_lock); @@ -209,7 +213,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev, int efx_ethtool_set_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); int rc; mutex_lock(&efx->mac_lock); @@ -224,7 +228,7 @@ int efx_ethtool_set_settings(struct net_device *net_dev, static void efx_ethtool_get_drvinfo(struct net_device *net_dev, struct ethtool_drvinfo *info) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver)); strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); @@ -329,7 +333,10 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, unsigned int n = 0; enum efx_loopback_mode mode; - /* Interrupt */ + efx_fill_test(n++, strings, data, &tests->mii, + "core", 0, "mii", NULL); + efx_fill_test(n++, strings, data, &tests->nvram, + "core", 0, "nvram", NULL); efx_fill_test(n++, strings, data, &tests->interrupt, "core", 0, "interrupt", NULL); @@ -349,16 +356,17 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, "eventq.poll", NULL); } - /* PHY presence */ - efx_fill_test(n++, strings, data, &tests->phy_ok, - EFX_PORT_NAME, "phy_ok", NULL); + efx_fill_test(n++, strings, data, &tests->registers, + "core", 0, "registers", NULL); + efx_fill_test(n++, strings, data, &tests->phy, + EFX_PORT_NAME, "phy", NULL); /* Loopback tests */ efx_fill_test(n++, strings, data, &tests->loopback_speed, EFX_PORT_NAME, "loopback.speed", NULL); efx_fill_test(n++, strings, data, &tests->loopback_full_duplex, EFX_PORT_NAME, "loopback.full_duplex", NULL); - for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) { + for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { if (!(efx->loopback_modes & (1 << mode))) continue; n = efx_fill_loopback_test(efx, @@ -369,22 +377,24 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, return n; } -static int efx_ethtool_get_stats_count(struct net_device *net_dev) +static int efx_ethtool_get_sset_count(struct net_device *net_dev, + int string_set) { - return EFX_ETHTOOL_NUM_STATS; -} - -static int efx_ethtool_self_test_count(struct net_device *net_dev) -{ - struct efx_nic *efx = net_dev->priv; - - return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL); + switch (string_set) { + case ETH_SS_STATS: + return EFX_ETHTOOL_NUM_STATS; + case ETH_SS_TEST: + return efx_ethtool_fill_self_tests(netdev_priv(net_dev), + NULL, NULL, NULL); + default: + return -EINVAL; + } } static void efx_ethtool_get_strings(struct net_device *net_dev, u32 string_set, u8 *strings) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); struct ethtool_string *ethtool_strings = (struct ethtool_string *)strings; int i; @@ -410,7 +420,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, struct ethtool_stats *stats, u64 *data) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); struct efx_mac_stats *mac_stats = &efx->mac_stats; struct efx_ethtool_stat *stat; struct efx_channel *channel; @@ -442,60 +452,21 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, } } -static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) -{ - int rc; - - /* Our TSO requires TX checksumming, so force TX checksumming - * on when TSO is enabled. - */ - if (enable) { - rc = efx_ethtool_set_tx_csum(net_dev, 1); - if (rc) - return rc; - } - - return ethtool_op_set_tso(net_dev, enable); -} - -static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx = net_dev->priv; - int rc; - - rc = ethtool_op_set_tx_csum(net_dev, enable); - if (rc) - return rc; - - efx_flush_queues(efx); - - /* Our TSO requires TX checksumming, so disable TSO when - * checksumming is disabled - */ - if (!enable) { - rc = efx_ethtool_set_tso(net_dev, 0); - if (rc) - return rc; - } - - return 0; -} - static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable) { - struct efx_nic *efx = net_dev->priv; + 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 ? 1 : 0); + efx->rx_checksum_enabled = !!enable; return 0; } static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); return efx->rx_checksum_enabled; } @@ -503,7 +474,7 @@ static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev) static void efx_ethtool_self_test(struct net_device *net_dev, struct ethtool_test *test, u64 *data) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); struct efx_self_tests efx_tests; int offline, already_up; int rc; @@ -533,15 +504,9 @@ static void efx_ethtool_self_test(struct net_device *net_dev, goto out; /* Perform offline tests only if online tests passed */ - if (offline) { - /* Stop the kernel from sending packets during the test. */ - efx_stop_queue(efx); - rc = efx_flush_queues(efx); - if (!rc) - rc = efx_offline_test(efx, &efx_tests, - efx->loopback_modes); - efx_wake_queue(efx); - } + if (offline) + rc = efx_offline_test(efx, &efx_tests, + efx->loopback_modes); out: if (!already_up) @@ -561,22 +526,65 @@ static void efx_ethtool_self_test(struct net_device *net_dev, /* Restart autonegotiation */ static int efx_ethtool_nway_reset(struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); return mii_nway_restart(&efx->mii); } static u32 efx_ethtool_get_link(struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); return efx->link_up; } +static int efx_ethtool_get_eeprom_len(struct net_device *net_dev) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_spi_device *spi = efx->spi_eeprom; + + if (!spi) + return 0; + return min(spi->size, EFX_ETHTOOL_EEPROM_MAX) - + min(spi->size, EFX_ETHTOOL_EEPROM_MIN); +} + +static int efx_ethtool_get_eeprom(struct net_device *net_dev, + struct ethtool_eeprom *eeprom, u8 *buf) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_spi_device *spi = efx->spi_eeprom; + size_t len; + int rc; + + rc = falcon_spi_read(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN, + eeprom->len, &len, buf); + eeprom->magic = EFX_ETHTOOL_EEPROM_MAGIC; + eeprom->len = len; + return rc; +} + +static int efx_ethtool_set_eeprom(struct net_device *net_dev, + struct ethtool_eeprom *eeprom, u8 *buf) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_spi_device *spi = efx->spi_eeprom; + size_t len; + int rc; + + if (eeprom->magic != EFX_ETHTOOL_EEPROM_MAGIC) + return -EINVAL; + + rc = falcon_spi_write(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN, + eeprom->len, &len, buf); + eeprom->len = len; + return rc; +} + static int efx_ethtool_get_coalesce(struct net_device *net_dev, struct ethtool_coalesce *coalesce) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; struct efx_channel *channel; @@ -614,7 +622,7 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, static int efx_ethtool_set_coalesce(struct net_device *net_dev, struct ethtool_coalesce *coalesce) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); struct efx_channel *channel; struct efx_tx_queue *tx_queue; unsigned tx_usecs, rx_usecs; @@ -657,7 +665,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, static int efx_ethtool_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); enum efx_fc_type flow_control = efx->flow_control; int rc; @@ -680,11 +688,11 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, static void efx_ethtool_get_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); - pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0; - pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0; - pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0; + pause->rx_pause = !!(efx->flow_control & EFX_FC_RX); + pause->tx_pause = !!(efx->flow_control & EFX_FC_TX); + pause->autoneg = !!(efx->flow_control & EFX_FC_AUTO); } @@ -694,6 +702,9 @@ struct ethtool_ops efx_ethtool_ops = { .get_drvinfo = efx_ethtool_get_drvinfo, .nway_reset = efx_ethtool_nway_reset, .get_link = efx_ethtool_get_link, + .get_eeprom_len = efx_ethtool_get_eeprom_len, + .get_eeprom = efx_ethtool_get_eeprom, + .set_eeprom = efx_ethtool_set_eeprom, .get_coalesce = efx_ethtool_get_coalesce, .set_coalesce = efx_ethtool_set_coalesce, .get_pauseparam = efx_ethtool_get_pauseparam, @@ -701,17 +712,16 @@ struct ethtool_ops efx_ethtool_ops = { .get_rx_csum = efx_ethtool_get_rx_csum, .set_rx_csum = efx_ethtool_set_rx_csum, .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = efx_ethtool_set_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 = efx_ethtool_set_tso, + .set_tso = ethtool_op_set_tso, .get_flags = ethtool_op_get_flags, .set_flags = ethtool_op_set_flags, - .self_test_count = efx_ethtool_self_test_count, + .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, - .get_stats_count = efx_ethtool_get_stats_count, .get_ethtool_stats = efx_ethtool_get_stats, }; diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 9138ee5b7b7..31ed1f49de0 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -108,10 +108,10 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); /* Max number of internal errors. After this resets will not be performed */ #define FALCON_MAX_INT_ERRORS 4 -/* Maximum period that we wait for flush events. If the flush event - * doesn't arrive in this period of time then we check if the queue - * was disabled anyway. */ -#define FALCON_FLUSH_TIMEOUT 10 /* 10ms */ +/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times + */ +#define FALCON_FLUSH_INTERVAL 10 +#define FALCON_FLUSH_POLL_COUNT 100 /************************************************************************** * @@ -242,7 +242,7 @@ static struct i2c_algo_bit_data falcon_i2c_bit_operations = { * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing * it to be used for event queues, descriptor rings etc. */ -static int +static void falcon_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) { @@ -266,8 +266,6 @@ falcon_init_special_buffer(struct efx_nic *efx, BUF_OWNER_ID_FBUF, 0); falcon_write_sram(efx, &buf_desc, index); } - - return 0; } /* Unmaps a buffer from Falcon and clears the buffer table entries */ @@ -449,16 +447,15 @@ int falcon_probe_tx(struct efx_tx_queue *tx_queue) sizeof(efx_qword_t)); } -int falcon_init_tx(struct efx_tx_queue *tx_queue) +void falcon_init_tx(struct efx_tx_queue *tx_queue) { efx_oword_t tx_desc_ptr; struct efx_nic *efx = tx_queue->efx; - int rc; + + tx_queue->flushed = false; /* Pin TX descriptor ring */ - rc = falcon_init_special_buffer(efx, &tx_queue->txd); - if (rc) - return rc; + falcon_init_special_buffer(efx, &tx_queue->txd); /* Push TX descriptor ring to card */ EFX_POPULATE_OWORD_10(tx_desc_ptr, @@ -466,7 +463,7 @@ int falcon_init_tx(struct efx_tx_queue *tx_queue) TX_ISCSI_DDIG_EN, 0, TX_ISCSI_HDIG_EN, 0, TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index, - TX_DESCQ_EVQ_ID, tx_queue->channel->evqnum, + TX_DESCQ_EVQ_ID, tx_queue->channel->channel, TX_DESCQ_OWNER_ID, 0, TX_DESCQ_LABEL, tx_queue->queue, TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER, @@ -474,9 +471,9 @@ int falcon_init_tx(struct efx_tx_queue *tx_queue) TX_NON_IP_DROP_DIS_B0, 1); if (falcon_rev(efx) >= FALCON_REV_B0) { - int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM); - EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum); - EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum); + int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM; + EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, !csum); + EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, !csum); } falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, @@ -485,73 +482,28 @@ int falcon_init_tx(struct efx_tx_queue *tx_queue) if (falcon_rev(efx) < FALCON_REV_B0) { efx_oword_t reg; - BUG_ON(tx_queue->queue >= 128); /* HW limit */ + /* Only 128 bits in this register */ + BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128); falcon_read(efx, ®, TX_CHKSM_CFG_REG_KER_A1); - if (efx->net_dev->features & NETIF_F_IP_CSUM) + if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM) clear_bit_le(tx_queue->queue, (void *)®); else set_bit_le(tx_queue->queue, (void *)®); falcon_write(efx, ®, TX_CHKSM_CFG_REG_KER_A1); } - - return 0; } -static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) +static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) { struct efx_nic *efx = tx_queue->efx; - struct efx_channel *channel = &efx->channel[0]; efx_oword_t tx_flush_descq; - unsigned int read_ptr, i; /* Post a flush command */ EFX_POPULATE_OWORD_2(tx_flush_descq, TX_FLUSH_DESCQ_CMD, 1, TX_FLUSH_DESCQ, tx_queue->queue); falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER); - msleep(FALCON_FLUSH_TIMEOUT); - - if (EFX_WORKAROUND_7803(efx)) - return 0; - - /* Look for a flush completed event */ - read_ptr = channel->eventq_read_ptr; - for (i = 0; i < FALCON_EVQ_SIZE; ++i) { - efx_qword_t *event = falcon_event(channel, read_ptr); - int ev_code, ev_sub_code, ev_queue; - if (!falcon_event_present(event)) - break; - - ev_code = EFX_QWORD_FIELD(*event, EV_CODE); - ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); - ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_TX_DESCQ_ID); - if ((ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) && - (ev_queue == tx_queue->queue)) { - EFX_LOG(efx, "tx queue %d flush command succesful\n", - tx_queue->queue); - return 0; - } - - read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; - } - - if (EFX_WORKAROUND_11557(efx)) { - efx_oword_t reg; - int enabled; - - falcon_read_table(efx, ®, efx->type->txd_ptr_tbl_base, - tx_queue->queue); - enabled = EFX_OWORD_FIELD(reg, TX_DESCQ_EN); - if (!enabled) { - EFX_LOG(efx, "tx queue %d disabled without a " - "flush event seen\n", tx_queue->queue); - return 0; - } - } - - EFX_ERR(efx, "tx queue %d flush command timed out\n", tx_queue->queue); - return -ETIMEDOUT; } void falcon_fini_tx(struct efx_tx_queue *tx_queue) @@ -559,9 +511,8 @@ void falcon_fini_tx(struct efx_tx_queue *tx_queue) struct efx_nic *efx = tx_queue->efx; efx_oword_t tx_desc_ptr; - /* Stop the hardware using the queue */ - if (falcon_flush_tx_queue(tx_queue)) - EFX_ERR(efx, "failed to flush tx queue %d\n", tx_queue->queue); + /* The queue should have been flushed */ + WARN_ON(!tx_queue->flushed); /* Remove TX descriptor ring from card */ EFX_ZERO_OWORD(tx_desc_ptr); @@ -638,29 +589,28 @@ int falcon_probe_rx(struct efx_rx_queue *rx_queue) sizeof(efx_qword_t)); } -int falcon_init_rx(struct efx_rx_queue *rx_queue) +void falcon_init_rx(struct efx_rx_queue *rx_queue) { efx_oword_t rx_desc_ptr; struct efx_nic *efx = rx_queue->efx; - int rc; - int is_b0 = falcon_rev(efx) >= FALCON_REV_B0; - int iscsi_digest_en = is_b0; + bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0; + bool iscsi_digest_en = is_b0; EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n", rx_queue->queue, rx_queue->rxd.index, rx_queue->rxd.index + rx_queue->rxd.entries - 1); + rx_queue->flushed = false; + /* Pin RX descriptor ring */ - rc = falcon_init_special_buffer(efx, &rx_queue->rxd); - if (rc) - return rc; + falcon_init_special_buffer(efx, &rx_queue->rxd); /* Push RX descriptor ring to card */ EFX_POPULATE_OWORD_10(rx_desc_ptr, RX_ISCSI_DDIG_EN, iscsi_digest_en, RX_ISCSI_HDIG_EN, iscsi_digest_en, RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index, - RX_DESCQ_EVQ_ID, rx_queue->channel->evqnum, + RX_DESCQ_EVQ_ID, rx_queue->channel->channel, RX_DESCQ_OWNER_ID, 0, RX_DESCQ_LABEL, rx_queue->queue, RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER, @@ -670,14 +620,11 @@ int falcon_init_rx(struct efx_rx_queue *rx_queue) RX_DESCQ_EN, 1); falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, rx_queue->queue); - return 0; } -static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) +static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; - struct efx_channel *channel = &efx->channel[0]; - unsigned int read_ptr, i; efx_oword_t rx_flush_descq; /* Post a flush command */ @@ -685,75 +632,15 @@ static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) RX_FLUSH_DESCQ_CMD, 1, RX_FLUSH_DESCQ, rx_queue->queue); falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER); - msleep(FALCON_FLUSH_TIMEOUT); - - if (EFX_WORKAROUND_7803(efx)) - return 0; - - /* Look for a flush completed event */ - read_ptr = channel->eventq_read_ptr; - for (i = 0; i < FALCON_EVQ_SIZE; ++i) { - efx_qword_t *event = falcon_event(channel, read_ptr); - int ev_code, ev_sub_code, ev_queue, ev_failed; - if (!falcon_event_present(event)) - break; - - ev_code = EFX_QWORD_FIELD(*event, EV_CODE); - ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); - ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_DESCQ_ID); - ev_failed = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_FLUSH_FAIL); - - if ((ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) && - (ev_queue == rx_queue->queue)) { - if (ev_failed) { - EFX_INFO(efx, "rx queue %d flush command " - "failed\n", rx_queue->queue); - return -EAGAIN; - } else { - EFX_LOG(efx, "rx queue %d flush command " - "succesful\n", rx_queue->queue); - return 0; - } - } - - read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; - } - - if (EFX_WORKAROUND_11557(efx)) { - efx_oword_t reg; - int enabled; - - falcon_read_table(efx, ®, efx->type->rxd_ptr_tbl_base, - rx_queue->queue); - enabled = EFX_OWORD_FIELD(reg, RX_DESCQ_EN); - if (!enabled) { - EFX_LOG(efx, "rx queue %d disabled without a " - "flush event seen\n", rx_queue->queue); - return 0; - } - } - - EFX_ERR(efx, "rx queue %d flush command timed out\n", rx_queue->queue); - return -ETIMEDOUT; } void falcon_fini_rx(struct efx_rx_queue *rx_queue) { efx_oword_t rx_desc_ptr; struct efx_nic *efx = rx_queue->efx; - int i, rc; - /* Try and flush the rx queue. This may need to be repeated */ - for (i = 0; i < 5; i++) { - rc = falcon_flush_rx_queue(rx_queue); - if (rc == -EAGAIN) - continue; - break; - } - if (rc) { - EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue); - efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); - } + /* The queue should already have been flushed */ + WARN_ON(!rx_queue->flushed); /* Remove RX descriptor ring from card */ EFX_ZERO_OWORD(rx_desc_ptr); @@ -793,7 +680,7 @@ void falcon_eventq_read_ack(struct efx_channel *channel) EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr); falcon_writel_table(efx, ®, efx->type->evq_rptr_tbl_base, - channel->evqnum); + channel->channel); } /* Use HW to insert a SW defined event */ @@ -802,7 +689,7 @@ void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event) efx_oword_t drv_ev_reg; EFX_POPULATE_OWORD_2(drv_ev_reg, - DRV_EV_QID, channel->evqnum, + DRV_EV_QID, channel->channel, DRV_EV_DATA, EFX_QWORD_FIELD64(*event, WHOLE_EVENT)); falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER); @@ -813,8 +700,8 @@ void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event) * Falcon batches TX completion events; the message we receive is of * the form "complete all TX events up to this index". */ -static inline void falcon_handle_tx_event(struct efx_channel *channel, - efx_qword_t *event) +static void falcon_handle_tx_event(struct efx_channel *channel, + efx_qword_t *event) { unsigned int tx_ev_desc_ptr; unsigned int tx_ev_q_label; @@ -847,39 +734,19 @@ static inline void falcon_handle_tx_event(struct efx_channel *channel, } } -/* Check received packet's destination MAC address. */ -static int check_dest_mac(struct efx_rx_queue *rx_queue, - const efx_qword_t *event) -{ - struct efx_rx_buffer *rx_buf; - struct efx_nic *efx = rx_queue->efx; - int rx_ev_desc_ptr; - struct ethhdr *eh; - - if (efx->promiscuous) - return 1; - - rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR); - rx_buf = efx_rx_buffer(rx_queue, rx_ev_desc_ptr); - eh = (struct ethhdr *)rx_buf->data; - if (memcmp(eh->h_dest, efx->net_dev->dev_addr, ETH_ALEN)) - return 0; - return 1; -} - /* Detect errors included in the rx_evt_pkt_ok bit. */ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, const efx_qword_t *event, - unsigned *rx_ev_pkt_ok, - int *discard, int byte_count) + bool *rx_ev_pkt_ok, + bool *discard) { struct efx_nic *efx = rx_queue->efx; - unsigned rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; - unsigned rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err; - unsigned rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc; - unsigned rx_ev_pkt_type, rx_ev_other_err, rx_ev_pause_frm; - unsigned rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt; - int snap, non_ip; + bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; + bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err; + bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc; + bool rx_ev_other_err, rx_ev_pause_frm; + bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt; + unsigned rx_ev_pkt_type; rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE); rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT); @@ -903,41 +770,6 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, rx_ev_buf_owner_id_err | rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err); - snap = (rx_ev_pkt_type == RX_EV_PKT_TYPE_LLC_DECODE) || - (rx_ev_pkt_type == RX_EV_PKT_TYPE_VLAN_LLC_DECODE); - non_ip = (rx_ev_hdr_type == RX_EV_HDR_TYPE_NON_IP_DECODE); - - /* SFC bug 5475/8970: The Falcon XMAC incorrectly calculates the - * length field of an LLC frame, which sets TOBE_DISC. We could set - * PASS_LEN_ERR, but we want the MAC to filter out short frames (to - * protect the RX block). - * - * bug5475 - LLC/SNAP: Falcon identifies SNAP packets. - * bug8970 - LLC/noSNAP: Falcon does not provide an LLC flag. - * LLC can't encapsulate IP, so by definition - * these packets are NON_IP. - * - * Unicast mismatch will also cause TOBE_DISC, so the driver needs - * to check this. - */ - if (EFX_WORKAROUND_5475(efx) && rx_ev_tobe_disc && (snap || non_ip)) { - /* If all the other flags are zero then we can state the - * entire packet is ok, which will flag to the kernel not - * to recalculate checksums. - */ - if (!(non_ip | rx_ev_other_err | rx_ev_pause_frm)) - *rx_ev_pkt_ok = 1; - - rx_ev_tobe_disc = 0; - - /* TOBE_DISC is set for unicast mismatch. But given that - * we can't trust TOBE_DISC here, we must validate the dest - * MAC address ourselves. - */ - if (!rx_ev_mcast_pkt && !check_dest_mac(rx_queue, event)) - rx_ev_tobe_disc = 1; - } - /* Count errors that are not in MAC stats. */ if (rx_ev_frm_trunc) ++rx_queue->channel->n_rx_frm_trunc; @@ -961,7 +793,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, #ifdef EFX_ENABLE_DEBUG if (rx_ev_other_err) { EFX_INFO_RL(efx, " RX queue %d unexpected RX event " - EFX_QWORD_FMT "%s%s%s%s%s%s%s%s%s\n", + EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n", rx_queue->queue, EFX_QWORD_VAL(*event), rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "", rx_ev_ip_hdr_chksum_err ? @@ -972,8 +804,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, rx_ev_frm_trunc ? " [FRM_TRUNC]" : "", rx_ev_drib_nib ? " [DRIB_NIB]" : "", rx_ev_tobe_disc ? " [TOBE_DISC]" : "", - rx_ev_pause_frm ? " [PAUSE]" : "", - snap ? " [SNAP/LLC]" : ""); + rx_ev_pause_frm ? " [PAUSE]" : ""); } #endif @@ -1006,13 +837,13 @@ static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue, * Also "is multicast" and "matches multicast filter" flags can be used to * discard non-matching multicast packets. */ -static inline int falcon_handle_rx_event(struct efx_channel *channel, - const efx_qword_t *event) +static void falcon_handle_rx_event(struct efx_channel *channel, + const efx_qword_t *event) { - unsigned int rx_ev_q_label, rx_ev_desc_ptr, rx_ev_byte_cnt; - unsigned int rx_ev_pkt_ok, rx_ev_hdr_type, rx_ev_mcast_pkt; + unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt; + unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt; unsigned expected_ptr; - int discard = 0, checksummed; + bool rx_ev_pkt_ok, discard = false, checksummed; struct efx_rx_queue *rx_queue; struct efx_nic *efx = channel->efx; @@ -1022,16 +853,14 @@ static inline int falcon_handle_rx_event(struct efx_channel *channel, rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE); WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT)); WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1); + WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL) != channel->channel); - rx_ev_q_label = EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL); - rx_queue = &efx->rx_queue[rx_ev_q_label]; + rx_queue = &efx->rx_queue[channel->channel]; rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR); expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK; - if (unlikely(rx_ev_desc_ptr != expected_ptr)) { + if (unlikely(rx_ev_desc_ptr != expected_ptr)) falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); - return rx_ev_q_label; - } if (likely(rx_ev_pkt_ok)) { /* If packet is marked as OK and packet type is TCP/IPv4 or @@ -1040,8 +869,8 @@ static inline int falcon_handle_rx_event(struct efx_channel *channel, checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type); } else { falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, - &discard, rx_ev_byte_cnt); - checksummed = 0; + &discard); + checksummed = false; } /* Detect multicast packets that didn't match the filter */ @@ -1051,14 +880,12 @@ static inline int falcon_handle_rx_event(struct efx_channel *channel, EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH); if (unlikely(!rx_ev_mcast_hash_match)) - discard = 1; + discard = true; } /* Handle received packet */ efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, checksummed, discard); - - return rx_ev_q_label; } /* Global events are basically PHY events */ @@ -1066,23 +893,23 @@ static void falcon_handle_global_event(struct efx_channel *channel, efx_qword_t *event) { struct efx_nic *efx = channel->efx; - int is_phy_event = 0, handled = 0; + bool is_phy_event = false, handled = false; /* Check for interrupt on either port. Some boards have a * single PHY wired to the interrupt line for port 1. */ if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) || EFX_QWORD_FIELD(*event, G_PHY1_INTR) || EFX_QWORD_FIELD(*event, XG_PHY_INTR)) - is_phy_event = 1; + is_phy_event = true; if ((falcon_rev(efx) >= FALCON_REV_B0) && - EFX_OWORD_FIELD(*event, XG_MNT_INTR_B0)) - is_phy_event = 1; + EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) + is_phy_event = true; if (is_phy_event) { efx->phy_op->clear_interrupt(efx); queue_work(efx->workqueue, &efx->reconfigure_work); - handled = 1; + handled = true; } if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) { @@ -1092,7 +919,7 @@ static void falcon_handle_global_event(struct efx_channel *channel, atomic_inc(&efx->rx_reset); efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ? RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); - handled = 1; + handled = true; } if (!handled) @@ -1163,13 +990,12 @@ static void falcon_handle_driver_event(struct efx_channel *channel, } } -int falcon_process_eventq(struct efx_channel *channel, int *rx_quota) +int falcon_process_eventq(struct efx_channel *channel, int rx_quota) { unsigned int read_ptr; efx_qword_t event, *p_event; int ev_code; - int rxq; - int rxdmaqs = 0; + int rx_packets = 0; read_ptr = channel->eventq_read_ptr; @@ -1191,9 +1017,8 @@ int falcon_process_eventq(struct efx_channel *channel, int *rx_quota) switch (ev_code) { case RX_IP_EV_DECODE: - rxq = falcon_handle_rx_event(channel, &event); - rxdmaqs |= (1 << rxq); - (*rx_quota)--; + falcon_handle_rx_event(channel, &event); + ++rx_packets; break; case TX_IP_EV_DECODE: falcon_handle_tx_event(channel, &event); @@ -1220,10 +1045,10 @@ int falcon_process_eventq(struct efx_channel *channel, int *rx_quota) /* Increment read pointer */ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; - } while (*rx_quota); + } while (rx_packets < rx_quota); channel->eventq_read_ptr = read_ptr; - return rxdmaqs; + return rx_packets; } void falcon_set_int_moderation(struct efx_channel *channel) @@ -1251,7 +1076,7 @@ void falcon_set_int_moderation(struct efx_channel *channel) TIMER_VAL, 0); } falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER, - channel->evqnum); + channel->channel); } @@ -1265,20 +1090,17 @@ int falcon_probe_eventq(struct efx_channel *channel) return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size); } -int falcon_init_eventq(struct efx_channel *channel) +void falcon_init_eventq(struct efx_channel *channel) { efx_oword_t evq_ptr; struct efx_nic *efx = channel->efx; - int rc; EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", channel->channel, channel->eventq.index, channel->eventq.index + channel->eventq.entries - 1); /* Pin event queue buffer */ - rc = falcon_init_special_buffer(efx, &channel->eventq); - if (rc) - return rc; + falcon_init_special_buffer(efx, &channel->eventq); /* Fill event queue with all ones (i.e. empty events) */ memset(channel->eventq.addr, 0xff, channel->eventq.len); @@ -1289,11 +1111,9 @@ int falcon_init_eventq(struct efx_channel *channel) EVQ_SIZE, FALCON_EVQ_ORDER, EVQ_BUF_BASE_ID, channel->eventq.index); falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base, - channel->evqnum); + channel->channel); falcon_set_int_moderation(channel); - - return 0; } void falcon_fini_eventq(struct efx_channel *channel) @@ -1304,7 +1124,7 @@ void falcon_fini_eventq(struct efx_channel *channel) /* Remove event queue from card */ EFX_ZERO_OWORD(eventq_ptr); falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base, - channel->evqnum); + channel->channel); /* Unpin event queue */ falcon_fini_special_buffer(efx, &channel->eventq); @@ -1331,6 +1151,121 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) falcon_generate_event(channel, &test_event); } +/************************************************************************** + * + * Flush handling + * + **************************************************************************/ + + +static void falcon_poll_flush_events(struct efx_nic *efx) +{ + struct efx_channel *channel = &efx->channel[0]; + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + unsigned int read_ptr, i; + + read_ptr = channel->eventq_read_ptr; + for (i = 0; i < FALCON_EVQ_SIZE; ++i) { + efx_qword_t *event = falcon_event(channel, read_ptr); + int ev_code, ev_sub_code, ev_queue; + bool ev_failed; + if (!falcon_event_present(event)) + break; + + ev_code = EFX_QWORD_FIELD(*event, EV_CODE); + if (ev_code != DRIVER_EV_DECODE) + continue; + + ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); + switch (ev_sub_code) { + case TX_DESCQ_FLS_DONE_EV_DECODE: + ev_queue = EFX_QWORD_FIELD(*event, + DRIVER_EV_TX_DESCQ_ID); + if (ev_queue < EFX_TX_QUEUE_COUNT) { + tx_queue = efx->tx_queue + ev_queue; + tx_queue->flushed = true; + } + break; + case RX_DESCQ_FLS_DONE_EV_DECODE: + ev_queue = EFX_QWORD_FIELD(*event, + DRIVER_EV_RX_DESCQ_ID); + ev_failed = EFX_QWORD_FIELD(*event, + DRIVER_EV_RX_FLUSH_FAIL); + if (ev_queue < efx->n_rx_queues) { + rx_queue = efx->rx_queue + ev_queue; + + /* retry the rx flush */ + if (ev_failed) + falcon_flush_rx_queue(rx_queue); + else + rx_queue->flushed = true; + } + break; + } + + read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; + } +} + +/* Handle tx and rx flushes at the same time, since they run in + * parallel in the hardware and there's no reason for us to + * serialise them */ +int falcon_flush_queues(struct efx_nic *efx) +{ + struct efx_rx_queue *rx_queue; + struct efx_tx_queue *tx_queue; + int i; + bool outstanding; + + /* Issue flush requests */ + efx_for_each_tx_queue(tx_queue, efx) { + tx_queue->flushed = false; + falcon_flush_tx_queue(tx_queue); + } + efx_for_each_rx_queue(rx_queue, efx) { + rx_queue->flushed = false; + falcon_flush_rx_queue(rx_queue); + } + + /* Poll the evq looking for flush completions. Since we're not pushing + * any more rx or tx descriptors at this point, we're in no danger of + * overflowing the evq whilst we wait */ + for (i = 0; i < FALCON_FLUSH_POLL_COUNT; ++i) { + msleep(FALCON_FLUSH_INTERVAL); + falcon_poll_flush_events(efx); + + /* Check if every queue has been succesfully flushed */ + outstanding = false; + efx_for_each_tx_queue(tx_queue, efx) + outstanding |= !tx_queue->flushed; + efx_for_each_rx_queue(rx_queue, efx) + outstanding |= !rx_queue->flushed; + if (!outstanding) + return 0; + } + + /* Mark the queues as all flushed. We're going to return failure + * leading to a reset, or fake up success anyway. "flushed" now + * indicates that we tried to flush. */ + efx_for_each_tx_queue(tx_queue, efx) { + if (!tx_queue->flushed) + EFX_ERR(efx, "tx queue %d flush command timed out\n", + tx_queue->queue); + tx_queue->flushed = true; + } + efx_for_each_rx_queue(rx_queue, efx) { + if (!rx_queue->flushed) + EFX_ERR(efx, "rx queue %d flush command timed out\n", + rx_queue->queue); + rx_queue->flushed = true; + } + + if (EFX_WORKAROUND_7803(efx)) + return 0; + + return -ETIMEDOUT; +} /************************************************************************** * @@ -1371,7 +1306,7 @@ void falcon_enable_interrupts(struct efx_nic *efx) /* Force processing of all the channels to get the EVQ RPTRs up to date */ - efx_for_each_channel_with_interrupt(channel, efx) + efx_for_each_channel(channel, efx) efx_schedule_channel(channel); } @@ -1439,10 +1374,11 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx) EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg)); } - /* Disable DMA bus mastering on both devices */ + /* Disable both devices */ pci_disable_device(efx->pci_dev); if (FALCON_IS_DUAL_FUNC(efx)) pci_disable_device(nic_data->pci_dev2); + falcon_disable_interrupts(efx); if (++n_int_errors < FALCON_MAX_INT_ERRORS) { EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n"); @@ -1589,7 +1525,7 @@ static void falcon_setup_rss_indir_table(struct efx_nic *efx) offset < RX_RSS_INDIR_TBL_B0 + 0x800; offset += 0x10) { EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0, - i % efx->rss_queues); + i % efx->n_rx_queues); falcon_writel(efx, &dword, offset); i++; } @@ -1621,7 +1557,7 @@ int falcon_init_interrupt(struct efx_nic *efx) } /* Hook MSI or MSI-X interrupt */ - efx_for_each_channel_with_interrupt(channel, efx) { + efx_for_each_channel(channel, efx) { rc = request_irq(channel->irq, falcon_msi_interrupt, IRQF_PROBE_SHARED, /* Not shared */ efx->name, channel); @@ -1634,7 +1570,7 @@ int falcon_init_interrupt(struct efx_nic *efx) return 0; fail2: - efx_for_each_channel_with_interrupt(channel, efx) + efx_for_each_channel(channel, efx) free_irq(channel->irq, channel); fail1: return rc; @@ -1646,7 +1582,7 @@ void falcon_fini_interrupt(struct efx_nic *efx) efx_oword_t reg; /* Disable MSI/MSI-X interrupts */ - efx_for_each_channel_with_interrupt(channel, efx) { + efx_for_each_channel(channel, efx) { if (channel->irq) free_irq(channel->irq, channel); } @@ -1669,69 +1605,200 @@ void falcon_fini_interrupt(struct efx_nic *efx) ************************************************************************** */ -#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t) +#define FALCON_SPI_MAX_LEN ((unsigned) sizeof(efx_oword_t)) /* Wait for SPI command completion */ static int falcon_spi_wait(struct efx_nic *efx) { + unsigned long timeout = jiffies + DIV_ROUND_UP(HZ, 10); efx_oword_t reg; - int cmd_en, timer_active; - int count; + bool cmd_en, timer_active; - count = 0; - do { + for (;;) { falcon_read(efx, ®, EE_SPI_HCMD_REG_KER); cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN); timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE); if (!cmd_en && !timer_active) return 0; - udelay(10); - } while (++count < 10000); /* wait upto 100msec */ - EFX_ERR(efx, "timed out waiting for SPI\n"); - return -ETIMEDOUT; + if (time_after_eq(jiffies, timeout)) { + EFX_ERR(efx, "timed out waiting for SPI\n"); + return -ETIMEDOUT; + } + cpu_relax(); + } } -static int -falcon_spi_read(struct efx_nic *efx, int device_id, unsigned int command, - unsigned int address, unsigned int addr_len, - void *data, unsigned int len) +static int falcon_spi_cmd(const struct efx_spi_device *spi, + unsigned int command, int address, + const void *in, void *out, unsigned int len) { + struct efx_nic *efx = spi->efx; + bool addressed = (address >= 0); + bool reading = (out != NULL); efx_oword_t reg; int rc; - BUG_ON(len > FALCON_SPI_MAX_LEN); + /* Input validation */ + if (len > FALCON_SPI_MAX_LEN) + return -EINVAL; /* Check SPI not currently being accessed */ rc = falcon_spi_wait(efx); if (rc) return rc; - /* Program address register */ - EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address); - falcon_write(efx, ®, EE_SPI_HADR_REG_KER); + /* Program address register, if we have an address */ + if (addressed) { + EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address); + falcon_write(efx, ®, EE_SPI_HADR_REG_KER); + } + + /* Program data register, if we have data */ + if (in != NULL) { + memcpy(®, in, len); + falcon_write(efx, ®, EE_SPI_HDATA_REG_KER); + } - /* Issue read command */ + /* Issue read/write command */ EFX_POPULATE_OWORD_7(reg, EE_SPI_HCMD_CMD_EN, 1, - EE_SPI_HCMD_SF_SEL, device_id, + EE_SPI_HCMD_SF_SEL, spi->device_id, EE_SPI_HCMD_DABCNT, len, - EE_SPI_HCMD_READ, EE_SPI_READ, + EE_SPI_HCMD_READ, reading, EE_SPI_HCMD_DUBCNT, 0, - EE_SPI_HCMD_ADBCNT, addr_len, + EE_SPI_HCMD_ADBCNT, + (addressed ? spi->addr_len : 0), EE_SPI_HCMD_ENC, command); falcon_write(efx, ®, EE_SPI_HCMD_REG_KER); - /* Wait for read to complete */ + /* Wait for read/write to complete */ rc = falcon_spi_wait(efx); if (rc) return rc; /* Read data */ - falcon_read(efx, ®, EE_SPI_HDATA_REG_KER); - memcpy(data, ®, len); + if (out != NULL) { + falcon_read(efx, ®, EE_SPI_HDATA_REG_KER); + memcpy(out, ®, len); + } + return 0; } +static unsigned int +falcon_spi_write_limit(const struct efx_spi_device *spi, unsigned int start) +{ + return min(FALCON_SPI_MAX_LEN, + (spi->block_size - (start & (spi->block_size - 1)))); +} + +static inline u8 +efx_spi_munge_command(const struct efx_spi_device *spi, + const u8 command, const unsigned int address) +{ + return command | (((address >> 8) & spi->munge_address) << 3); +} + + +static int falcon_spi_fast_wait(const struct efx_spi_device *spi) +{ + u8 status; + int i, rc; + + /* Wait up to 1000us for flash/EEPROM to finish a fast operation. */ + for (i = 0; i < 50; i++) { + udelay(20); + + rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, + &status, sizeof(status)); + if (rc) + return rc; + if (!(status & SPI_STATUS_NRDY)) + return 0; + } + EFX_ERR(spi->efx, + "timed out waiting for device %d last status=0x%02x\n", + spi->device_id, status); + return -ETIMEDOUT; +} + +int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, + size_t len, size_t *retlen, u8 *buffer) +{ + unsigned int command, block_len, pos = 0; + int rc = 0; + + while (pos < len) { + block_len = min((unsigned int)len - pos, + FALCON_SPI_MAX_LEN); + + command = efx_spi_munge_command(spi, SPI_READ, start + pos); + rc = falcon_spi_cmd(spi, command, start + pos, NULL, + buffer + pos, block_len); + if (rc) + break; + pos += block_len; + + /* Avoid locking up the system */ + cond_resched(); + if (signal_pending(current)) { + rc = -EINTR; + break; + } + } + + if (retlen) + *retlen = pos; + return rc; +} + +int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, + size_t len, size_t *retlen, const u8 *buffer) +{ + u8 verify_buffer[FALCON_SPI_MAX_LEN]; + unsigned int command, block_len, pos = 0; + int rc = 0; + + while (pos < len) { + rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + if (rc) + break; + + block_len = min((unsigned int)len - pos, + falcon_spi_write_limit(spi, start + pos)); + command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); + rc = falcon_spi_cmd(spi, command, start + pos, + buffer + pos, NULL, block_len); + if (rc) + break; + + rc = falcon_spi_fast_wait(spi); + if (rc) + break; + + command = efx_spi_munge_command(spi, SPI_READ, start + pos); + rc = falcon_spi_cmd(spi, command, start + pos, + NULL, verify_buffer, block_len); + if (memcmp(verify_buffer, buffer + pos, block_len)) { + rc = -EIO; + break; + } + + pos += block_len; + + /* Avoid locking up the system */ + cond_resched(); + if (signal_pending(current)) { + rc = -EINTR; + break; + } + } + + if (retlen) + *retlen = pos; + return rc; +} + /************************************************************************** * * MAC wrapper @@ -1812,7 +1879,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) { efx_oword_t reg; int link_speed; - unsigned int tx_fc; + bool tx_fc; if (efx->link_options & GM_LPA_10000) link_speed = 0x3; @@ -1847,7 +1914,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) /* Transmission of pause frames when RX crosses the threshold is * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. * Action on receipt of pause frames is controller by XM_DIS_FCNTL */ - tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0; + tx_fc = !!(efx->flow_control & EFX_FC_TX); falcon_read(efx, ®, RX_CFG_REG_KER); EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc); @@ -1887,8 +1954,10 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) /* Wait for transfer to complete */ for (i = 0; i < 400; i++) { - if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) + if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) { + rmb(); /* Ensure the stats are valid. */ return 0; + } udelay(10); } @@ -1951,7 +2020,7 @@ static int falcon_gmii_wait(struct efx_nic *efx) static void falcon_mdio_write(struct net_device *net_dev, int phy_id, int addr, int value) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK; efx_oword_t reg; @@ -2019,7 +2088,7 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id, * could be read, -1 will be returned. */ static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr) { - struct efx_nic *efx = net_dev->priv; + struct efx_nic *efx = netdev_priv(net_dev); unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK; efx_oword_t reg; int value = -1; @@ -2120,7 +2189,7 @@ int falcon_probe_port(struct efx_nic *efx) return rc; /* Set up GMII structure for PHY */ - efx->mii.supports_gmii = 1; + efx->mii.supports_gmii = true; falcon_init_mdio(&efx->mii); /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ @@ -2168,6 +2237,170 @@ void falcon_set_multicast_hash(struct efx_nic *efx) falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER); } + +/************************************************************************** + * + * Falcon test code + * + **************************************************************************/ + +int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) +{ + struct falcon_nvconfig *nvconfig; + struct efx_spi_device *spi; + void *region; + int rc, magic_num, struct_ver; + __le16 *word, *limit; + u32 csum; + + region = kmalloc(NVCONFIG_END, GFP_KERNEL); + if (!region) + return -ENOMEM; + nvconfig = region + NVCONFIG_OFFSET; + + spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; + rc = falcon_spi_read(spi, 0, NVCONFIG_END, NULL, region); + if (rc) { + EFX_ERR(efx, "Failed to read %s\n", + efx->spi_flash ? "flash" : "EEPROM"); + rc = -EIO; + goto out; + } + + magic_num = le16_to_cpu(nvconfig->board_magic_num); + struct_ver = le16_to_cpu(nvconfig->board_struct_ver); + + rc = -EINVAL; + if (magic_num != NVCONFIG_BOARD_MAGIC_NUM) { + EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num); + goto out; + } + if (struct_ver < 2) { + EFX_ERR(efx, "NVRAM has ancient version 0x%x\n", struct_ver); + goto out; + } else if (struct_ver < 4) { + word = &nvconfig->board_magic_num; + limit = (__le16 *) (nvconfig + 1); + } else { + word = region; + limit = region + NVCONFIG_END; + } + for (csum = 0; word < limit; ++word) + csum += le16_to_cpu(*word); + + if (~csum & 0xffff) { + EFX_ERR(efx, "NVRAM has incorrect checksum\n"); + goto out; + } + + rc = 0; + if (nvconfig_out) + memcpy(nvconfig_out, nvconfig, sizeof(*nvconfig)); + + out: + kfree(region); + return rc; +} + +/* Registers tested in the falcon register test */ +static struct { + unsigned address; + efx_oword_t mask; +} efx_test_registers[] = { + { ADR_REGION_REG_KER, + EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, + { RX_CFG_REG_KER, + EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) }, + { TX_CFG_REG_KER, + EFX_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) }, + { TX_CFG2_REG_KER, + EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, + { MAC0_CTRL_REG_KER, + EFX_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) }, + { SRM_TX_DC_CFG_REG_KER, + EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, + { RX_DC_CFG_REG_KER, + EFX_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) }, + { RX_DC_PF_WM_REG_KER, + EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, + { DP_CTRL_REG, + EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, + { XM_GLB_CFG_REG, + EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) }, + { XM_TX_CFG_REG, + EFX_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) }, + { XM_RX_CFG_REG, + EFX_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) }, + { XM_RX_PARAM_REG, + EFX_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) }, + { XM_FC_REG, + EFX_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) }, + { XM_ADR_LO_REG, + EFX_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) }, + { XX_SD_CTL_REG, + EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, +}; + +static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, + const efx_oword_t *mask) +{ + return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) || + ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); +} + +int falcon_test_registers(struct efx_nic *efx) +{ + unsigned address = 0, i, j; + efx_oword_t mask, imask, original, reg, buf; + + /* Falcon should be in loopback to isolate the XMAC from the PHY */ + WARN_ON(!LOOPBACK_INTERNAL(efx)); + + for (i = 0; i < ARRAY_SIZE(efx_test_registers); ++i) { + address = efx_test_registers[i].address; + mask = imask = efx_test_registers[i].mask; + EFX_INVERT_OWORD(imask); + + falcon_read(efx, &original, address); + + /* bit sweep on and off */ + for (j = 0; j < 128; j++) { + if (!EFX_EXTRACT_OWORD32(mask, j, j)) + continue; + + /* Test this testable bit can be set in isolation */ + EFX_AND_OWORD(reg, original, mask); + EFX_SET_OWORD32(reg, j, j, 1); + + falcon_write(efx, ®, address); + falcon_read(efx, &buf, address); + + if (efx_masked_compare_oword(®, &buf, &mask)) + goto fail; + + /* Test this testable bit can be cleared in isolation */ + EFX_OR_OWORD(reg, original, mask); + EFX_SET_OWORD32(reg, j, j, 0); + + falcon_write(efx, ®, address); + falcon_read(efx, &buf, address); + + if (efx_masked_compare_oword(®, &buf, &mask)) + goto fail; + } + + falcon_write(efx, &original, address); + } + + return 0; + +fail: + EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT + " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg), + EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask)); + return -EIO; +} + /************************************************************************** * * Device reset @@ -2305,68 +2538,103 @@ static int falcon_reset_sram(struct efx_nic *efx) return -ETIMEDOUT; } +static int falcon_spi_device_init(struct efx_nic *efx, + struct efx_spi_device **spi_device_ret, + unsigned int device_id, u32 device_type) +{ + struct efx_spi_device *spi_device; + + if (device_type != 0) { + spi_device = kmalloc(sizeof(*spi_device), GFP_KERNEL); + if (!spi_device) + return -ENOMEM; + spi_device->device_id = device_id; + spi_device->size = + 1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE); + spi_device->addr_len = + SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN); + spi_device->munge_address = (spi_device->size == 1 << 9 && + spi_device->addr_len == 1); + spi_device->block_size = + 1 << SPI_DEV_TYPE_FIELD(device_type, + SPI_DEV_TYPE_BLOCK_SIZE); + + spi_device->efx = efx; + } else { + spi_device = NULL; + } + + kfree(*spi_device_ret); + *spi_device_ret = spi_device; + return 0; +} + + +static void falcon_remove_spi_devices(struct efx_nic *efx) +{ + kfree(efx->spi_eeprom); + efx->spi_eeprom = NULL; + kfree(efx->spi_flash); + efx->spi_flash = NULL; +} + /* Extract non-volatile configuration */ static int falcon_probe_nvconfig(struct efx_nic *efx) { struct falcon_nvconfig *nvconfig; - efx_oword_t nic_stat; - int device_id; - unsigned addr_len; - size_t offset, len; - int magic_num, struct_ver, board_rev; + int board_rev; int rc; - /* Find the boot device. */ - falcon_read(efx, &nic_stat, NIC_STAT_REG); - if (EFX_OWORD_FIELD(nic_stat, SF_PRST)) { - device_id = EE_SPI_FLASH; - addr_len = 3; - } else if (EFX_OWORD_FIELD(nic_stat, EE_PRST)) { - device_id = EE_SPI_EEPROM; - addr_len = 2; - } else { - return -ENODEV; - } - nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL); + if (!nvconfig) + return -ENOMEM; - /* Read the whole configuration structure into memory. */ - for (offset = 0; offset < sizeof(*nvconfig); offset += len) { - len = min(sizeof(*nvconfig) - offset, - (size_t) FALCON_SPI_MAX_LEN); - rc = falcon_spi_read(efx, device_id, SPI_READ, - NVCONFIG_BASE + offset, addr_len, - (char *)nvconfig + offset, len); - if (rc) - goto out; - } - - /* Read the MAC addresses */ - memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN); - - /* Read the board configuration. */ - magic_num = le16_to_cpu(nvconfig->board_magic_num); - struct_ver = le16_to_cpu(nvconfig->board_struct_ver); - - if (magic_num != NVCONFIG_BOARD_MAGIC_NUM || struct_ver < 2) { - EFX_ERR(efx, "Non volatile memory bad magic=%x ver=%x " - "therefore using defaults\n", magic_num, struct_ver); + rc = falcon_read_nvram(efx, nvconfig); + if (rc == -EINVAL) { + EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n"); efx->phy_type = PHY_TYPE_NONE; efx->mii.phy_id = PHY_ADDR_INVALID; board_rev = 0; + rc = 0; + } else if (rc) { + goto fail1; } else { struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2; + struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3; efx->phy_type = v2->port0_phy_type; efx->mii.phy_id = v2->port0_phy_addr; board_rev = le16_to_cpu(v2->board_revision); + + if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) { + __le32 fl = v3->spi_device_type[EE_SPI_FLASH]; + __le32 ee = v3->spi_device_type[EE_SPI_EEPROM]; + rc = falcon_spi_device_init(efx, &efx->spi_flash, + EE_SPI_FLASH, + le32_to_cpu(fl)); + if (rc) + goto fail2; + rc = falcon_spi_device_init(efx, &efx->spi_eeprom, + EE_SPI_EEPROM, + le32_to_cpu(ee)); + if (rc) + goto fail2; + } } + /* Read the MAC addresses */ + memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN); + EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id); efx_set_board_info(efx, board_rev); - out: + kfree(nvconfig); + return 0; + + fail2: + falcon_remove_spi_devices(efx); + fail1: kfree(nvconfig); return rc; } @@ -2417,6 +2685,86 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) return 0; } +/* Probe all SPI devices on the NIC */ +static void falcon_probe_spi_devices(struct efx_nic *efx) +{ + efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg; + bool has_flash, has_eeprom, boot_is_external; + + falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER); + falcon_read(efx, &nic_stat, NIC_STAT_REG); + falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); + + has_flash = EFX_OWORD_FIELD(nic_stat, SF_PRST); + has_eeprom = EFX_OWORD_FIELD(nic_stat, EE_PRST); + boot_is_external = EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE); + + if (has_flash) { + /* Default flash SPI device: Atmel AT25F1024 + * 128 KB, 24-bit address, 32 KB erase block, + * 256 B write block + */ + u32 flash_device_type = + (17 << SPI_DEV_TYPE_SIZE_LBN) + | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN) + | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN) + | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) + | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN); + + falcon_spi_device_init(efx, &efx->spi_flash, + EE_SPI_FLASH, flash_device_type); + + if (!boot_is_external) { + /* Disable VPD and set clock dividers to safe + * values for initial programming. + */ + EFX_LOG(efx, "Booted from internal ASIC settings;" + " setting SPI config\n"); + EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0, + /* 125 MHz / 7 ~= 20 MHz */ + EE_SF_CLOCK_DIV, 7, + /* 125 MHz / 63 ~= 2 MHz */ + EE_EE_CLOCK_DIV, 63); + falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); + } + } + + if (has_eeprom) { + u32 eeprom_device_type; + + /* If it has no flash, it must have a large EEPROM + * for chip config; otherwise check whether 9-bit + * addressing is used for VPD configuration + */ + if (has_flash && + (!boot_is_external || + EFX_OWORD_FIELD(ee_vpd_cfg, EE_VPD_EN_AD9_MODE))) { + /* Default SPI device: Atmel AT25040 or similar + * 512 B, 9-bit address, 8 B write block + */ + eeprom_device_type = + (9 << SPI_DEV_TYPE_SIZE_LBN) + | (1 << SPI_DEV_TYPE_ADDR_LEN_LBN) + | (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN); + } else { + /* "Large" SPI device: Atmel AT25640 or similar + * 8 KB, 16-bit address, 32 B write block + */ + eeprom_device_type = + (13 << SPI_DEV_TYPE_SIZE_LBN) + | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN) + | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN); + } + + falcon_spi_device_init(efx, &efx->spi_eeprom, + EE_SPI_EEPROM, eeprom_device_type); + } + + EFX_LOG(efx, "flash is %s, EEPROM is %s\n", + (has_flash ? "present" : "absent"), + (has_eeprom ? "present" : "absent")); +} + int falcon_probe_nic(struct efx_nic *efx) { struct falcon_nic_data *nic_data; @@ -2424,6 +2772,8 @@ int falcon_probe_nic(struct efx_nic *efx) /* Allocate storage for hardware specific data */ nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL); + if (!nic_data) + return -ENOMEM; efx->nic_data = nic_data; /* Determine number of ports etc. */ @@ -2467,6 +2817,8 @@ int falcon_probe_nic(struct efx_nic *efx) (unsigned long long)efx->irq_status.dma_addr, efx->irq_status.addr, virt_to_phys(efx->irq_status.addr)); + falcon_probe_spi_devices(efx); + /* Read in the non-volatile configuration */ rc = falcon_probe_nvconfig(efx); if (rc) @@ -2486,6 +2838,7 @@ int falcon_probe_nic(struct efx_nic *efx) return 0; fail5: + falcon_remove_spi_devices(efx); falcon_free_buffer(efx, &efx->irq_status); fail4: fail3: @@ -2573,19 +2926,14 @@ int falcon_init_nic(struct efx_nic *efx) EFX_INVERT_OWORD(temp); falcon_write(efx, &temp, FATAL_INTR_REG_KER); - /* Set number of RSS queues for receive path. */ - falcon_read(efx, &temp, RX_FILTER_CTL_REG); - if (falcon_rev(efx) >= FALCON_REV_B0) - EFX_SET_OWORD_FIELD(temp, NUM_KER, 0); - else - EFX_SET_OWORD_FIELD(temp, NUM_KER, efx->rss_queues - 1); if (EFX_WORKAROUND_7244(efx)) { + falcon_read(efx, &temp, RX_FILTER_CTL_REG); EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8); EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8); EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8); EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8); + falcon_write(efx, &temp, RX_FILTER_CTL_REG); } - falcon_write(efx, &temp, RX_FILTER_CTL_REG); falcon_setup_rss_indir_table(efx); @@ -2641,8 +2989,8 @@ int falcon_init_nic(struct efx_nic *efx) rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh); EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256); /* RX control FIFO thresholds [32 entries] */ - EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 25); - EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 20); + EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 20); + EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 25); falcon_write(efx, &temp, RX_CFG_REG_KER); /* Set destination of both TX and RX Flush events */ @@ -2662,6 +3010,7 @@ void falcon_remove_nic(struct efx_nic *efx) rc = i2c_del_adapter(&efx->i2c_adap); BUG_ON(rc); + falcon_remove_spi_devices(efx); falcon_free_buffer(efx, &efx->irq_status); falcon_reset_hw(efx, RESET_TYPE_ALL); diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 492f9bc2884..be025ba7a6c 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -40,24 +40,24 @@ extern struct efx_nic_type falcon_b_nic_type; /* TX data path */ extern int falcon_probe_tx(struct efx_tx_queue *tx_queue); -extern int falcon_init_tx(struct efx_tx_queue *tx_queue); +extern void falcon_init_tx(struct efx_tx_queue *tx_queue); extern void falcon_fini_tx(struct efx_tx_queue *tx_queue); extern void falcon_remove_tx(struct efx_tx_queue *tx_queue); extern void falcon_push_buffers(struct efx_tx_queue *tx_queue); /* RX data path */ extern int falcon_probe_rx(struct efx_rx_queue *rx_queue); -extern int falcon_init_rx(struct efx_rx_queue *rx_queue); +extern void falcon_init_rx(struct efx_rx_queue *rx_queue); extern void falcon_fini_rx(struct efx_rx_queue *rx_queue); extern void falcon_remove_rx(struct efx_rx_queue *rx_queue); extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue); /* Event data path */ extern int falcon_probe_eventq(struct efx_channel *channel); -extern int falcon_init_eventq(struct efx_channel *channel); +extern void falcon_init_eventq(struct efx_channel *channel); extern void falcon_fini_eventq(struct efx_channel *channel); extern void falcon_remove_eventq(struct efx_channel *channel); -extern int falcon_process_eventq(struct efx_channel *channel, int *rx_quota); +extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota); extern void falcon_eventq_read_ack(struct efx_channel *channel); /* Ports */ @@ -65,7 +65,7 @@ extern int falcon_probe_port(struct efx_nic *efx); extern void falcon_remove_port(struct efx_nic *efx); /* MAC/PHY */ -extern int falcon_xaui_link_ok(struct efx_nic *efx); +extern bool falcon_xaui_link_ok(struct efx_nic *efx); extern int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset); extern void falcon_drain_tx_fifo(struct efx_nic *efx); @@ -86,6 +86,7 @@ extern void falcon_fini_interrupt(struct efx_nic *efx); extern int falcon_probe_nic(struct efx_nic *efx); extern int falcon_probe_resources(struct efx_nic *efx); extern int falcon_init_nic(struct efx_nic *efx); +extern int falcon_flush_queues(struct efx_nic *efx); extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method); extern void falcon_remove_resources(struct efx_nic *efx); extern void falcon_remove_nic(struct efx_nic *efx); @@ -93,6 +94,12 @@ extern void falcon_update_nic_stats(struct efx_nic *efx); extern void falcon_set_multicast_hash(struct efx_nic *efx); extern int falcon_reset_xaui(struct efx_nic *efx); +/* Tests */ +struct falcon_nvconfig; +extern int falcon_read_nvram(struct efx_nic *efx, + struct falcon_nvconfig *nvconfig); +extern int falcon_test_registers(struct efx_nic *efx); + /************************************************************************** * * Falcon MAC stats diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h index 6d003114eea..5d584b0dbb5 100644 --- a/drivers/net/sfc/falcon_hwdefs.h +++ b/drivers/net/sfc/falcon_hwdefs.h @@ -92,6 +92,17 @@ /* SPI host data register */ #define EE_SPI_HDATA_REG_KER 0x0120 +/* SPI/VPD config register */ +#define EE_VPD_CFG_REG_KER 0x0140 +#define EE_VPD_EN_LBN 0 +#define EE_VPD_EN_WIDTH 1 +#define EE_VPD_EN_AD9_MODE_LBN 1 +#define EE_VPD_EN_AD9_MODE_WIDTH 1 +#define EE_EE_CLOCK_DIV_LBN 112 +#define EE_EE_CLOCK_DIV_WIDTH 7 +#define EE_SF_CLOCK_DIV_LBN 120 +#define EE_SF_CLOCK_DIV_WIDTH 7 + /* PCIE CORE ACCESS REG */ #define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68 #define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70 @@ -106,7 +117,6 @@ #define SF_PRST_WIDTH 1 #define EE_PRST_LBN 8 #define EE_PRST_WIDTH 1 -/* See pic_mode_t for decoding of this field */ /* These bit definitions are extrapolated from the list of numerical * values for STRAP_PINS. */ @@ -115,6 +125,9 @@ #define STRAP_PCIE_LBN 0 #define STRAP_PCIE_WIDTH 1 +#define BOOTED_USING_NVDEVICE_LBN 3 +#define BOOTED_USING_NVDEVICE_WIDTH 1 + /* GPIO control register */ #define GPIO_CTL_REG_KER 0x0210 #define GPIO_OUTPUTS_LBN (16) @@ -479,18 +492,8 @@ #define MAC_MCAST_HASH_REG0_KER 0xca0 #define MAC_MCAST_HASH_REG1_KER 0xcb0 -/* GMAC registers */ -#define FALCON_GMAC_REGBANK 0xe00 -#define FALCON_GMAC_REGBANK_SIZE 0x200 -#define FALCON_GMAC_REG_SIZE 0x10 - -/* XMAC registers */ -#define FALCON_XMAC_REGBANK 0x1200 -#define FALCON_XMAC_REGBANK_SIZE 0x200 -#define FALCON_XMAC_REG_SIZE 0x10 - /* XGMAC address register low */ -#define XM_ADR_LO_REG_MAC 0x00 +#define XM_ADR_LO_REG 0x1200 #define XM_ADR_3_LBN 24 #define XM_ADR_3_WIDTH 8 #define XM_ADR_2_LBN 16 @@ -501,14 +504,14 @@ #define XM_ADR_0_WIDTH 8 /* XGMAC address register high */ -#define XM_ADR_HI_REG_MAC 0x01 +#define XM_ADR_HI_REG 0x1210 #define XM_ADR_5_LBN 8 #define XM_ADR_5_WIDTH 8 #define XM_ADR_4_LBN 0 #define XM_ADR_4_WIDTH 8 /* XGMAC global configuration */ -#define XM_GLB_CFG_REG_MAC 0x02 +#define XM_GLB_CFG_REG 0x1220 #define XM_RX_STAT_EN_LBN 11 #define XM_RX_STAT_EN_WIDTH 1 #define XM_TX_STAT_EN_LBN 10 @@ -521,7 +524,7 @@ #define XM_CORE_RST_WIDTH 1 /* XGMAC transmit configuration */ -#define XM_TX_CFG_REG_MAC 0x03 +#define XM_TX_CFG_REG 0x1230 #define XM_IPG_LBN 16 #define XM_IPG_WIDTH 4 #define XM_FCNTL_LBN 10 @@ -536,7 +539,7 @@ #define XM_TXEN_WIDTH 1 /* XGMAC receive configuration */ -#define XM_RX_CFG_REG_MAC 0x04 +#define XM_RX_CFG_REG 0x1240 #define XM_PASS_CRC_ERR_LBN 25 #define XM_PASS_CRC_ERR_WIDTH 1 #define XM_ACPT_ALL_MCAST_LBN 11 @@ -549,7 +552,7 @@ #define XM_RXEN_WIDTH 1 /* XGMAC management interrupt mask register */ -#define XM_MGT_INT_MSK_REG_MAC_B0 0x5 +#define XM_MGT_INT_MSK_REG_B0 0x1250 #define XM_MSK_PRMBLE_ERR_LBN 2 #define XM_MSK_PRMBLE_ERR_WIDTH 1 #define XM_MSK_RMTFLT_LBN 1 @@ -558,29 +561,29 @@ #define XM_MSK_LCLFLT_WIDTH 1 /* XGMAC flow control register */ -#define XM_FC_REG_MAC 0x7 +#define XM_FC_REG 0x1270 #define XM_PAUSE_TIME_LBN 16 #define XM_PAUSE_TIME_WIDTH 16 #define XM_DIS_FCNTL_LBN 0 #define XM_DIS_FCNTL_WIDTH 1 /* XGMAC pause time count register */ -#define XM_PAUSE_TIME_REG_MAC 0x9 +#define XM_PAUSE_TIME_REG 0x1290 /* XGMAC transmit parameter register */ -#define XM_TX_PARAM_REG_MAC 0x0d +#define XM_TX_PARAM_REG 0x012d0 #define XM_TX_JUMBO_MODE_LBN 31 #define XM_TX_JUMBO_MODE_WIDTH 1 #define XM_MAX_TX_FRM_SIZE_LBN 16 #define XM_MAX_TX_FRM_SIZE_WIDTH 14 /* XGMAC receive parameter register */ -#define XM_RX_PARAM_REG_MAC 0x0e +#define XM_RX_PARAM_REG 0x12e0 #define XM_MAX_RX_FRM_SIZE_LBN 0 #define XM_MAX_RX_FRM_SIZE_WIDTH 14 /* XGMAC management interrupt status register */ -#define XM_MGT_INT_REG_MAC_B0 0x0f +#define XM_MGT_INT_REG_B0 0x12f0 #define XM_PRMBLE_ERR 2 #define XM_PRMBLE_WIDTH 1 #define XM_RMTFLT_LBN 1 @@ -589,7 +592,7 @@ #define XM_LCLFLT_WIDTH 1 /* XGXS/XAUI powerdown/reset register */ -#define XX_PWR_RST_REG_MAC 0x10 +#define XX_PWR_RST_REG 0x1300 #define XX_PWRDND_EN_LBN 15 #define XX_PWRDND_EN_WIDTH 1 @@ -619,7 +622,7 @@ #define XX_RST_XX_EN_WIDTH 1 /* XGXS/XAUI powerdown/reset control register */ -#define XX_SD_CTL_REG_MAC 0x11 +#define XX_SD_CTL_REG 0x1310 #define XX_HIDRVD_LBN 15 #define XX_HIDRVD_WIDTH 1 #define XX_LODRVD_LBN 14 @@ -645,7 +648,7 @@ #define XX_LPBKA_LBN 0 #define XX_LPBKA_WIDTH 1 -#define XX_TXDRV_CTL_REG_MAC 0x12 +#define XX_TXDRV_CTL_REG 0x1320 #define XX_DEQD_LBN 28 #define XX_DEQD_WIDTH 4 #define XX_DEQC_LBN 24 @@ -664,7 +667,7 @@ #define XX_DTXA_WIDTH 4 /* XAUI XGXS core status register */ -#define XX_CORE_STAT_REG_MAC 0x16 +#define XX_CORE_STAT_REG 0x1360 #define XX_FORCE_SIG_LBN 24 #define XX_FORCE_SIG_WIDTH 8 #define XX_FORCE_SIG_DECODE_FORCED 0xff @@ -1127,7 +1130,28 @@ struct falcon_nvconfig_board_v2 { __le16 board_revision; } __packed; -#define NVCONFIG_BASE 0x300 +/* Board configuration v3 extra information */ +struct falcon_nvconfig_board_v3 { + __le32 spi_device_type[2]; +} __packed; + +/* Bit numbers for spi_device_type */ +#define SPI_DEV_TYPE_SIZE_LBN 0 +#define SPI_DEV_TYPE_SIZE_WIDTH 5 +#define SPI_DEV_TYPE_ADDR_LEN_LBN 6 +#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2 +#define SPI_DEV_TYPE_ERASE_CMD_LBN 8 +#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8 +#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16 +#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5 +#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24 +#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5 +#define SPI_DEV_TYPE_FIELD(type, field) \ + (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) + +#define NVCONFIG_OFFSET 0x300 +#define NVCONFIG_END 0x400 + #define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C struct falcon_nvconfig { efx_oword_t ee_vpd_cfg_reg; /* 0x300 */ @@ -1144,6 +1168,8 @@ struct falcon_nvconfig { __le16 board_struct_ver; __le16 board_checksum; struct falcon_nvconfig_board_v2 board_v2; + efx_oword_t ee_base_page_reg; /* 0x3B0 */ + struct falcon_nvconfig_board_v3 board_v3; } __packed; #endif /* EFX_FALCON_HWDEFS_H */ diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h index 6670cdfc41a..c16da3149fa 100644 --- a/drivers/net/sfc/falcon_io.h +++ b/drivers/net/sfc/falcon_io.h @@ -13,7 +13,6 @@ #include <linux/io.h> #include <linux/spinlock.h> -#include "net_driver.h" /************************************************************************** * diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 55c0d9760be..d4012314dd0 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -23,56 +23,24 @@ /************************************************************************** * - * MAC register access - * - **************************************************************************/ - -/* Offset of an XMAC register within Falcon */ -#define FALCON_XMAC_REG(mac_reg) \ - (FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE)) - -void falcon_xmac_writel(struct efx_nic *efx, - efx_dword_t *value, unsigned int mac_reg) -{ - efx_oword_t temp; - - EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA)); - falcon_write(efx, &temp, FALCON_XMAC_REG(mac_reg)); -} - -void falcon_xmac_readl(struct efx_nic *efx, - efx_dword_t *value, unsigned int mac_reg) -{ - efx_oword_t temp; - - falcon_read(efx, &temp, FALCON_XMAC_REG(mac_reg)); - EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA)); -} - -/************************************************************************** - * * MAC operations * *************************************************************************/ static int falcon_reset_xmac(struct efx_nic *efx) { - efx_dword_t reg; + efx_oword_t reg; int count; - EFX_POPULATE_DWORD_1(reg, XM_CORE_RST, 1); - falcon_xmac_writel(efx, ®, XM_GLB_CFG_REG_MAC); + EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1); + falcon_write(efx, ®, XM_GLB_CFG_REG); for (count = 0; count < 10000; count++) { /* wait upto 100ms */ - falcon_xmac_readl(efx, ®, XM_GLB_CFG_REG_MAC); - if (EFX_DWORD_FIELD(reg, XM_CORE_RST) == 0) + falcon_read(efx, ®, XM_GLB_CFG_REG); + if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0) return 0; udelay(10); } - /* This often fails when DSP is disabled, ignore it */ - if (sfe4001_phy_flash_cfg != 0) - return 0; - EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); return -ETIMEDOUT; } @@ -80,25 +48,25 @@ static int falcon_reset_xmac(struct efx_nic *efx) /* Configure the XAUI driver that is an output from Falcon */ static void falcon_setup_xaui(struct efx_nic *efx) { - efx_dword_t sdctl, txdrv; + efx_oword_t sdctl, txdrv; /* Move the XAUI into low power, unless there is no PHY, in * which case the XAUI will have to drive a cable. */ if (efx->phy_type == PHY_TYPE_NONE) return; - falcon_xmac_readl(efx, &sdctl, XX_SD_CTL_REG_MAC); - EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_DWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_DWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_DWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_DWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT); - falcon_xmac_writel(efx, &sdctl, XX_SD_CTL_REG_MAC); - - EFX_POPULATE_DWORD_8(txdrv, + falcon_read(efx, &sdctl, XX_SD_CTL_REG); + EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT); + EFX_SET_OWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT); + EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT); + EFX_SET_OWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT); + EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT); + EFX_SET_OWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT); + EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT); + EFX_SET_OWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT); + falcon_write(efx, &sdctl, XX_SD_CTL_REG); + + EFX_POPULATE_OWORD_8(txdrv, XX_DEQD, XX_TXDRV_DEQ_DEFAULT, XX_DEQC, XX_TXDRV_DEQ_DEFAULT, XX_DEQB, XX_TXDRV_DEQ_DEFAULT, @@ -107,93 +75,21 @@ static void falcon_setup_xaui(struct efx_nic *efx) XX_DTXC, XX_TXDRV_DTX_DEFAULT, XX_DTXB, XX_TXDRV_DTX_DEFAULT, XX_DTXA, XX_TXDRV_DTX_DEFAULT); - falcon_xmac_writel(efx, &txdrv, XX_TXDRV_CTL_REG_MAC); + falcon_write(efx, &txdrv, XX_TXDRV_CTL_REG); } -static void falcon_hold_xaui_in_rst(struct efx_nic *efx) -{ - efx_dword_t reg; - - EFX_ZERO_DWORD(reg); - EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(10); -} - -static int _falcon_reset_xaui_a(struct efx_nic *efx) -{ - efx_dword_t reg; - - falcon_hold_xaui_in_rst(efx); - falcon_xmac_readl(efx, ®, XX_PWR_RST_REG_MAC); - - /* Follow the RAMBUS XAUI data reset sequencing - * Channels A and B first: power down, reset PLL, reset, clear - */ - EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 0); - EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 0); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(10); - - EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(10); - - EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 0); - EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 0); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(10); - - /* Channels C and D: power down, reset PLL, reset, clear */ - EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 0); - EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 0); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(10); - - EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(10); - - EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 0); - EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 0); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(10); - - /* Setup XAUI */ - falcon_setup_xaui(efx); - udelay(10); - - /* Take XGXS out of reset */ - EFX_ZERO_DWORD(reg); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(10); - - return 0; -} - -static int _falcon_reset_xaui_b(struct efx_nic *efx) +int falcon_reset_xaui(struct efx_nic *efx) { - efx_dword_t reg; + efx_oword_t reg; int count; EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); + falcon_write(efx, ®, XX_PWR_RST_REG); /* Give some time for the link to establish */ for (count = 0; count < 1000; count++) { /* wait upto 10ms */ - falcon_xmac_readl(efx, ®, XX_PWR_RST_REG_MAC); - if (EFX_DWORD_FIELD(reg, XX_RST_XX_EN) == 0) { + falcon_read(efx, ®, XX_PWR_RST_REG); + if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0) { falcon_setup_xaui(efx); return 0; } @@ -203,55 +99,41 @@ static int _falcon_reset_xaui_b(struct efx_nic *efx) return -ETIMEDOUT; } -int falcon_reset_xaui(struct efx_nic *efx) +static bool falcon_xgmii_status(struct efx_nic *efx) { - int rc; - - if (EFX_WORKAROUND_9388(efx)) { - falcon_hold_xaui_in_rst(efx); - efx->phy_op->reset_xaui(efx); - rc = _falcon_reset_xaui_a(efx); - } else { - rc = _falcon_reset_xaui_b(efx); - } - return rc; -} - -static int falcon_xgmii_status(struct efx_nic *efx) -{ - efx_dword_t reg; + efx_oword_t reg; if (falcon_rev(efx) < FALCON_REV_B0) - return 1; + return true; /* The ISR latches, so clear it and re-read */ - falcon_xmac_readl(efx, ®, XM_MGT_INT_REG_MAC_B0); - falcon_xmac_readl(efx, ®, XM_MGT_INT_REG_MAC_B0); + falcon_read(efx, ®, XM_MGT_INT_REG_B0); + falcon_read(efx, ®, XM_MGT_INT_REG_B0); - if (EFX_DWORD_FIELD(reg, XM_LCLFLT) || - EFX_DWORD_FIELD(reg, XM_RMTFLT)) { + if (EFX_OWORD_FIELD(reg, XM_LCLFLT) || + EFX_OWORD_FIELD(reg, XM_RMTFLT)) { EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg)); - return 0; + return false; } - return 1; + return true; } -static void falcon_mask_status_intr(struct efx_nic *efx, int enable) +static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) { - efx_dword_t reg; + efx_oword_t reg; if ((falcon_rev(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) return; /* Flush the ISR */ if (enable) - falcon_xmac_readl(efx, ®, XM_MGT_INT_REG_MAC_B0); + falcon_read(efx, ®, XM_MGT_INT_REG_B0); - EFX_POPULATE_DWORD_2(reg, + EFX_POPULATE_OWORD_2(reg, XM_MSK_RMTFLT, !enable, XM_MSK_LCLFLT, !enable); - falcon_xmac_writel(efx, ®, XM_MGT_INT_MSK_REG_MAC_B0); + falcon_write(efx, ®, XM_MGT_INT_MSK_REG_B0); } int falcon_init_xmac(struct efx_nic *efx) @@ -274,7 +156,7 @@ int falcon_init_xmac(struct efx_nic *efx) if (rc) goto fail2; - falcon_mask_status_intr(efx, 1); + falcon_mask_status_intr(efx, true); return 0; fail2: @@ -283,34 +165,34 @@ int falcon_init_xmac(struct efx_nic *efx) return rc; } -int falcon_xaui_link_ok(struct efx_nic *efx) +bool falcon_xaui_link_ok(struct efx_nic *efx) { - efx_dword_t reg; - int align_done, sync_status, link_ok = 0; + efx_oword_t reg; + bool align_done, link_ok = false; + int sync_status; if (LOOPBACK_INTERNAL(efx)) - return 1; + return true; /* Read link status */ - falcon_xmac_readl(efx, ®, XX_CORE_STAT_REG_MAC); + falcon_read(efx, ®, XX_CORE_STAT_REG); - align_done = EFX_DWORD_FIELD(reg, XX_ALIGN_DONE); - sync_status = EFX_DWORD_FIELD(reg, XX_SYNC_STAT); + align_done = EFX_OWORD_FIELD(reg, XX_ALIGN_DONE); + sync_status = EFX_OWORD_FIELD(reg, XX_SYNC_STAT); if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED)) - link_ok = 1; + link_ok = true; /* Clear link status ready for next read */ - EFX_SET_DWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET); - EFX_SET_DWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET); - EFX_SET_DWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET); - falcon_xmac_writel(efx, ®, XX_CORE_STAT_REG_MAC); + EFX_SET_OWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET); + EFX_SET_OWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET); + EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET); + falcon_write(efx, ®, XX_CORE_STAT_REG); /* If the link is up, then check the phy side of the xaui link * (error conditions from the wire side propoagate back through * the phy to the xaui side). */ if (efx->link_up && link_ok) { - int has_phyxs = efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS); - if (has_phyxs) + if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) link_ok = mdio_clause45_phyxgxs_lane_sync(efx); } @@ -325,15 +207,15 @@ int falcon_xaui_link_ok(struct efx_nic *efx) static void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; - efx_dword_t reg; - int rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0; + efx_oword_t reg; + bool rx_fc = !!(efx->flow_control & EFX_FC_RX); /* Configure MAC - cut-thru mode is hard wired on */ EFX_POPULATE_DWORD_3(reg, XM_RX_JUMBO_MODE, 1, XM_TX_STAT_EN, 1, XM_RX_STAT_EN, 1); - falcon_xmac_writel(efx, ®, XM_GLB_CFG_REG_MAC); + falcon_write(efx, ®, XM_GLB_CFG_REG); /* Configure TX */ EFX_POPULATE_DWORD_6(reg, @@ -343,7 +225,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx) XM_TXCRC, 1, XM_FCNTL, 1, XM_IPG, 0x3); - falcon_xmac_writel(efx, ®, XM_TX_CFG_REG_MAC); + falcon_write(efx, ®, XM_TX_CFG_REG); /* Configure RX */ EFX_POPULATE_DWORD_5(reg, @@ -352,21 +234,21 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx) XM_ACPT_ALL_MCAST, 1, XM_ACPT_ALL_UCAST, efx->promiscuous, XM_PASS_CRC_ERR, 1); - falcon_xmac_writel(efx, ®, XM_RX_CFG_REG_MAC); + falcon_write(efx, ®, XM_RX_CFG_REG); /* Set frame length */ max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len); - falcon_xmac_writel(efx, ®, XM_RX_PARAM_REG_MAC); + falcon_write(efx, ®, XM_RX_PARAM_REG); EFX_POPULATE_DWORD_2(reg, XM_MAX_TX_FRM_SIZE, max_frame_len, XM_TX_JUMBO_MODE, 1); - falcon_xmac_writel(efx, ®, XM_TX_PARAM_REG_MAC); + falcon_write(efx, ®, XM_TX_PARAM_REG); EFX_POPULATE_DWORD_2(reg, XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ - XM_DIS_FCNTL, rx_fc ? 0 : 1); - falcon_xmac_writel(efx, ®, XM_FC_REG_MAC); + XM_DIS_FCNTL, !rx_fc); + falcon_write(efx, ®, XM_FC_REG); /* Set MAC address */ EFX_POPULATE_DWORD_4(reg, @@ -374,83 +256,75 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx) XM_ADR_1, efx->net_dev->dev_addr[1], XM_ADR_2, efx->net_dev->dev_addr[2], XM_ADR_3, efx->net_dev->dev_addr[3]); - falcon_xmac_writel(efx, ®, XM_ADR_LO_REG_MAC); + falcon_write(efx, ®, XM_ADR_LO_REG); EFX_POPULATE_DWORD_2(reg, XM_ADR_4, efx->net_dev->dev_addr[4], XM_ADR_5, efx->net_dev->dev_addr[5]); - falcon_xmac_writel(efx, ®, XM_ADR_HI_REG_MAC); + falcon_write(efx, ®, XM_ADR_HI_REG); } static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) { - efx_dword_t reg; - int xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS) ? 1 : 0; - int xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI) ? 1 : 0; - int xgmii_loopback = - (efx->loopback_mode == LOOPBACK_XGMII) ? 1 : 0; + efx_oword_t reg; + bool xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS); + bool xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI); + bool xgmii_loopback = (efx->loopback_mode == LOOPBACK_XGMII); /* XGXS block is flaky and will need to be reset if moving * into our out of XGMII, XGXS or XAUI loopbacks. */ if (EFX_WORKAROUND_5147(efx)) { - int old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback; - int reset_xgxs; + bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback; + bool reset_xgxs; - falcon_xmac_readl(efx, ®, XX_CORE_STAT_REG_MAC); - old_xgxs_loopback = EFX_DWORD_FIELD(reg, XX_XGXS_LB_EN); - old_xgmii_loopback = EFX_DWORD_FIELD(reg, XX_XGMII_LB_EN); + falcon_read(efx, ®, XX_CORE_STAT_REG); + old_xgxs_loopback = EFX_OWORD_FIELD(reg, XX_XGXS_LB_EN); + old_xgmii_loopback = EFX_OWORD_FIELD(reg, XX_XGMII_LB_EN); - falcon_xmac_readl(efx, ®, XX_SD_CTL_REG_MAC); - old_xaui_loopback = EFX_DWORD_FIELD(reg, XX_LPBKA); + falcon_read(efx, ®, XX_SD_CTL_REG); + old_xaui_loopback = EFX_OWORD_FIELD(reg, XX_LPBKA); /* The PHY driver may have turned XAUI off */ reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) || (xaui_loopback != old_xaui_loopback) || (xgmii_loopback != old_xgmii_loopback)); - if (reset_xgxs) { - falcon_xmac_readl(efx, ®, XX_PWR_RST_REG_MAC); - EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1); - EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(1); - EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 0); - EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 0); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(1); - } + + if (reset_xgxs) + falcon_reset_xaui(efx); } - falcon_xmac_readl(efx, ®, XX_CORE_STAT_REG_MAC); - EFX_SET_DWORD_FIELD(reg, XX_FORCE_SIG, + falcon_read(efx, ®, XX_CORE_STAT_REG); + EFX_SET_OWORD_FIELD(reg, XX_FORCE_SIG, (xgxs_loopback || xaui_loopback) ? XX_FORCE_SIG_DECODE_FORCED : 0); - EFX_SET_DWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback); - EFX_SET_DWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback); - falcon_xmac_writel(efx, ®, XX_CORE_STAT_REG_MAC); - - falcon_xmac_readl(efx, ®, XX_SD_CTL_REG_MAC); - EFX_SET_DWORD_FIELD(reg, XX_LPBKD, xaui_loopback); - EFX_SET_DWORD_FIELD(reg, XX_LPBKC, xaui_loopback); - EFX_SET_DWORD_FIELD(reg, XX_LPBKB, xaui_loopback); - EFX_SET_DWORD_FIELD(reg, XX_LPBKA, xaui_loopback); - falcon_xmac_writel(efx, ®, XX_SD_CTL_REG_MAC); + EFX_SET_OWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback); + EFX_SET_OWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback); + falcon_write(efx, ®, XX_CORE_STAT_REG); + + falcon_read(efx, ®, XX_SD_CTL_REG); + EFX_SET_OWORD_FIELD(reg, XX_LPBKD, xaui_loopback); + EFX_SET_OWORD_FIELD(reg, XX_LPBKC, xaui_loopback); + EFX_SET_OWORD_FIELD(reg, XX_LPBKB, xaui_loopback); + EFX_SET_OWORD_FIELD(reg, XX_LPBKA, xaui_loopback); + falcon_write(efx, ®, XX_SD_CTL_REG); } /* Try and bring the Falcon side of the Falcon-Phy XAUI link fails * to come back up. Bash it until it comes back up */ -static int falcon_check_xaui_link_up(struct efx_nic *efx) +static bool falcon_check_xaui_link_up(struct efx_nic *efx) { int max_tries, tries; tries = EFX_WORKAROUND_5147(efx) ? 5 : 1; max_tries = tries; if ((efx->loopback_mode == LOOPBACK_NETWORK) || - (efx->phy_type == PHY_TYPE_NONE)) - return 0; + (efx->phy_type == PHY_TYPE_NONE) || + efx_phy_mode_disabled(efx->phy_mode)) + return false; while (tries) { if (falcon_xaui_link_ok(efx)) - return 1; + return true; EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n", __func__, tries); @@ -461,18 +335,22 @@ static int falcon_check_xaui_link_up(struct efx_nic *efx) EFX_LOG(efx, "Failed to bring XAUI link back up in %d tries!\n", max_tries); - return 0; + return false; } void falcon_reconfigure_xmac(struct efx_nic *efx) { - int xaui_link_ok; + bool xaui_link_ok; - falcon_mask_status_intr(efx, 0); + falcon_mask_status_intr(efx, false); falcon_deconfigure_mac_wrapper(efx); - efx->tx_disabled = LOOPBACK_INTERNAL(efx); + /* Reconfigure the PHY, disabling transmit in mac level loopback. */ + if (LOOPBACK_INTERNAL(efx)) + efx->phy_mode |= PHY_MODE_TX_DISABLED; + else + efx->phy_mode &= ~PHY_MODE_TX_DISABLED; efx->phy_op->reconfigure(efx); falcon_reconfigure_xgxs_core(efx); @@ -484,7 +362,7 @@ void falcon_reconfigure_xmac(struct efx_nic *efx) xaui_link_ok = falcon_check_xaui_link_up(efx); if (xaui_link_ok && efx->link_up) - falcon_mask_status_intr(efx, 1); + falcon_mask_status_intr(efx, true); } void falcon_fini_xmac(struct efx_nic *efx) @@ -554,21 +432,23 @@ void falcon_update_stats_xmac(struct efx_nic *efx) /* Update derived statistics */ mac_stats->tx_good_bytes = - (mac_stats->tx_bytes - mac_stats->tx_bad_bytes); + (mac_stats->tx_bytes - mac_stats->tx_bad_bytes - + mac_stats->tx_control * 64); mac_stats->rx_bad_bytes = - (mac_stats->rx_bytes - mac_stats->rx_good_bytes); + (mac_stats->rx_bytes - mac_stats->rx_good_bytes - + mac_stats->rx_control * 64); } int falcon_check_xmac(struct efx_nic *efx) { - unsigned xaui_link_ok; + bool xaui_link_ok; int rc; if ((efx->loopback_mode == LOOPBACK_NETWORK) || - (efx->phy_type == PHY_TYPE_NONE)) + efx_phy_mode_disabled(efx->phy_mode)) return 0; - falcon_mask_status_intr(efx, 0); + falcon_mask_status_intr(efx, false); xaui_link_ok = falcon_xaui_link_ok(efx); if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok) @@ -579,7 +459,7 @@ int falcon_check_xmac(struct efx_nic *efx) /* Unmask interrupt if everything was (and still is) ok */ if (xaui_link_ok && efx->link_up) - falcon_mask_status_intr(efx, 1); + falcon_mask_status_intr(efx, true); return rc; } @@ -620,7 +500,7 @@ int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control) { - int reset; + bool reset; if (flow_control & EFX_FC_AUTO) { EFX_LOG(efx, "10G does not support flow control " diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index edd07d4dee1..a31571c6913 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -13,10 +13,6 @@ #include "net_driver.h" -extern void falcon_xmac_writel(struct efx_nic *efx, - efx_dword_t *value, unsigned int mac_reg); -extern void falcon_xmac_readl(struct efx_nic *efx, - efx_dword_t *value, unsigned int mac_reg); extern int falcon_init_xmac(struct efx_nic *efx); extern void falcon_reconfigure_xmac(struct efx_nic *efx); extern void falcon_update_stats_xmac(struct efx_nic *efx); diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index c4f540e93b7..003e48dcb2f 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -159,20 +159,21 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, return 0; } -int mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) +bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) { int phy_id = efx->mii.phy_id; int status; - int ok = 1; + bool ok = true; int mmd = 0; - int good; /* If the port is in loopback, then we should only consider a subset * of mmd's */ if (LOOPBACK_INTERNAL(efx)) - return 1; + return true; else if (efx->loopback_mode == LOOPBACK_NETWORK) - return 0; + return false; + else if (efx_phy_mode_disabled(efx->phy_mode)) + return false; else if (efx->loopback_mode == LOOPBACK_PHYXS) mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS | MDIO_MMDREG_DEVS0_PCS | @@ -192,8 +193,7 @@ int mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1); - good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN); - ok = ok && good; + ok = ok && (status & (1 << MDIO_MMDREG_STAT1_LINK_LBN)); } mmd_mask = (mmd_mask >> 1); mmd++; @@ -208,7 +208,7 @@ void mdio_clause45_transmit_disable(struct efx_nic *efx) ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_TXDIS); - if (efx->tx_disabled) + if (efx->phy_mode & PHY_MODE_TX_DISABLED) ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); else ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index cb99f3f4491..19c42eaf7fb 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -199,18 +199,19 @@ static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd) return (id_hi << 16) | (id_low); } -static inline int mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx) +static inline bool mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx) { - int i, sync, lane_status; + int i, lane_status; + bool sync; for (i = 0; i < 2; ++i) lane_status = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PHYXS, MDIO_PHYXS_LANE_STATE); - sync = (lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)) != 0; + sync = !!(lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)); if (!sync) - EFX_INFO(efx, "XGXS lane status: %x\n", lane_status); + EFX_LOG(efx, "XGXS lane status: %x\n", lane_status); return sync; } @@ -230,8 +231,8 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, unsigned int mmd_mask, unsigned int fatal_mask); /* Check the link status of specified mmds in bit mask */ -extern int mdio_clause45_links_ok(struct efx_nic *efx, - unsigned int mmd_mask); +extern bool mdio_clause45_links_ok(struct efx_nic *efx, + unsigned int mmd_mask); /* Generic transmit disable support though PMAPMD */ extern void mdio_clause45_transmit_disable(struct efx_nic *efx); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 219c74a772c..cdb11fad605 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -88,9 +88,12 @@ do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0) **************************************************************************/ #define EFX_MAX_CHANNELS 32 -#define EFX_MAX_TX_QUEUES 1 #define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS +#define EFX_TX_QUEUE_OFFLOAD_CSUM 0 +#define EFX_TX_QUEUE_NO_CSUM 1 +#define EFX_TX_QUEUE_COUNT 2 + /** * struct efx_special_buffer - An Efx special buffer * @addr: CPU base address of the buffer @@ -127,7 +130,6 @@ struct efx_special_buffer { * This field is zero when the queue slot is empty. * @continuation: True if this fragment is not the end of a packet. * @unmap_single: True if pci_unmap_single should be used. - * @unmap_addr: DMA address to unmap * @unmap_len: Length of this fragment to unmap */ struct efx_tx_buffer { @@ -135,9 +137,8 @@ struct efx_tx_buffer { struct efx_tso_header *tsoh; dma_addr_t dma_addr; unsigned short len; - unsigned char continuation; - unsigned char unmap_single; - dma_addr_t unmap_addr; + bool continuation; + bool unmap_single; unsigned short unmap_len; }; @@ -156,13 +157,13 @@ struct efx_tx_buffer { * * @efx: The associated Efx NIC * @queue: DMA queue number - * @used: Queue is used by net driver * @channel: The associated channel * @buffer: The software buffer ring * @txd: The hardware descriptor ring + * @flushed: Used when handling queue flushing * @read_count: Current read pointer. * This is the number of buffers that have been removed from both rings. - * @stopped: Stopped flag. + * @stopped: Stopped count. * Set if this TX queue is currently stopping its port. * @insert_count: Current insert pointer * This is the number of buffers that have been added to the @@ -188,11 +189,11 @@ struct efx_tx_queue { /* Members which don't change on the fast path */ struct efx_nic *efx ____cacheline_aligned_in_smp; int queue; - int used; struct efx_channel *channel; struct efx_nic *nic; struct efx_tx_buffer *buffer; struct efx_special_buffer txd; + bool flushed; /* Members used mainly on the completion path */ unsigned int read_count ____cacheline_aligned_in_smp; @@ -232,7 +233,6 @@ struct efx_rx_buffer { * struct efx_rx_queue - An Efx RX queue * @efx: The associated Efx NIC * @queue: DMA queue number - * @used: Queue is used by net driver * @channel: The associated channel * @buffer: The software buffer ring * @rxd: The hardware descriptor ring @@ -262,11 +262,11 @@ struct efx_rx_buffer { * the remaining space in the allocation. * @buf_dma_addr: Page's DMA address. * @buf_data: Page's host address. + * @flushed: Use when handling queue flushing */ struct efx_rx_queue { struct efx_nic *efx; int queue; - int used; struct efx_channel *channel; struct efx_rx_buffer *buffer; struct efx_special_buffer rxd; @@ -288,6 +288,7 @@ struct efx_rx_queue { struct page *buf_page; dma_addr_t buf_dma_addr; char *buf_data; + bool flushed; }; /** @@ -325,12 +326,10 @@ enum efx_rx_alloc_method { * queue. * * @efx: Associated Efx NIC - * @evqnum: Event queue number * @channel: Channel instance number * @used_flags: Channel is used by net driver * @enabled: Channel enabled indicator * @irq: IRQ number (MSI and MSI-X only) - * @has_interrupt: Channel has an interrupt * @irq_moderation: IRQ moderation value (in us) * @napi_dev: Net device used with NAPI * @napi_str: NAPI control structure @@ -357,17 +356,14 @@ enum efx_rx_alloc_method { */ struct efx_channel { struct efx_nic *efx; - int evqnum; int channel; int used_flags; - int enabled; + bool enabled; int irq; - unsigned int has_interrupt; unsigned int irq_moderation; struct net_device *napi_dev; struct napi_struct napi_str; - struct work_struct reset_work; - int work_pending; + bool work_pending; struct efx_special_buffer eventq; unsigned int eventq_read_ptr; unsigned int last_eventq_read_ptr; @@ -390,7 +386,7 @@ struct efx_channel { * access with prefetches. */ struct efx_rx_buffer *rx_pkt; - int rx_pkt_csummed; + bool rx_pkt_csummed; }; @@ -403,8 +399,8 @@ struct efx_channel { */ struct efx_blinker { int led_num; - int state; - int resubmit; + bool state; + bool resubmit; struct timer_list timer; }; @@ -432,8 +428,8 @@ struct efx_board { * have a separate init callback that happens later than * board init. */ int (*init_leds)(struct efx_nic *efx); - void (*set_fault_led) (struct efx_nic *efx, int state); - void (*blink) (struct efx_nic *efx, int start); + void (*set_fault_led) (struct efx_nic *efx, bool state); + void (*blink) (struct efx_nic *efx, bool start); void (*fini) (struct efx_nic *nic); struct efx_blinker blinker; struct i2c_client *hwmon_client, *ioexp_client; @@ -467,8 +463,7 @@ enum nic_state { STATE_INIT = 0, STATE_RUNNING = 1, STATE_FINI = 2, - STATE_RESETTING = 3, /* rtnl_lock always held */ - STATE_DISABLED = 4, + STATE_DISABLED = 3, STATE_MAX, }; @@ -479,7 +474,7 @@ enum nic_state { * This is the equivalent of NET_IP_ALIGN [which controls the alignment * of the skb->head for hardware DMA]. */ -#if defined(__i386__) || defined(__x86_64__) +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS #define EFX_PAGE_IP_ALIGN 0 #else #define EFX_PAGE_IP_ALIGN NET_IP_ALIGN @@ -512,7 +507,6 @@ enum efx_fc_type { * @clear_interrupt: Clear down interrupt * @blink: Blink LEDs * @check_hw: Check hardware - * @reset_xaui: Reset XAUI side of PHY for (software sequenced reset) * @mmds: MMD presence mask * @loopbacks: Supported loopback modes mask */ @@ -522,11 +516,28 @@ struct efx_phy_operations { void (*reconfigure) (struct efx_nic *efx); void (*clear_interrupt) (struct efx_nic *efx); int (*check_hw) (struct efx_nic *efx); - void (*reset_xaui) (struct efx_nic *efx); + int (*test) (struct efx_nic *efx); int mmds; unsigned loopbacks; }; +/** + * @enum efx_phy_mode - PHY operating mode flags + * @PHY_MODE_NORMAL: on and should pass traffic + * @PHY_MODE_TX_DISABLED: on with TX disabled + * @PHY_MODE_SPECIAL: on but will not pass traffic + */ +enum efx_phy_mode { + PHY_MODE_NORMAL = 0, + PHY_MODE_TX_DISABLED = 1, + PHY_MODE_SPECIAL = 8, +}; + +static inline bool efx_phy_mode_disabled(enum efx_phy_mode mode) +{ + return !!(mode & ~PHY_MODE_TX_DISABLED); +} + /* * Efx extended statistics * @@ -632,7 +643,7 @@ union efx_multicast_hash { * @tx_queue: TX DMA queues * @rx_queue: RX DMA queues * @channel: Channels - * @rss_queues: Number of RSS queues + * @n_rx_queues: Number of RX queues * @rx_buffer_len: RX buffer length * @rx_buffer_order: Order (log2) of number of pages for each RX buffer * @irq_status: Interrupt status buffer @@ -640,15 +651,20 @@ union efx_multicast_hash { * This register is written with the SMP processor ID whenever an * interrupt is handled. It is used by falcon_test_interrupt() * to verify that an interrupt has occurred. + * @spi_flash: SPI flash device + * This field will be %NULL if no flash device is present. + * @spi_eeprom: SPI EEPROM device + * This field will be %NULL if no EEPROM device is present. * @n_rx_nodesc_drop_cnt: RX no descriptor drop count * @nic_data: Hardware dependant state - * @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and - * efx_reconfigure_port() + * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, + * @port_inhibited, efx_monitor() and efx_reconfigure_port() * @port_enabled: Port enabled indicator. * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and * efx_reconfigure_work with kernel interfaces. Safe to read under any * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must * be held to modify it. + * @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 @@ -658,14 +674,16 @@ union efx_multicast_hash { * can provide. Generic code converts these into a standard * &struct net_device_stats. * @stats_buffer: DMA buffer for statistics - * @stats_lock: Statistics update lock + * @stats_lock: Statistics update lock. Serialises statistics fetches + * @stats_enabled: Temporarily disable statistics fetches. + * Serialised by @stats_lock * @mac_address: Permanent MAC address * @phy_type: PHY type * @phy_lock: PHY access lock * @phy_op: PHY interface * @phy_data: PHY private data (including PHY-specific stats) * @mii: PHY interface - * @tx_disabled: PHY transmitter turned off + * @phy_mode: PHY operating mode. Serialised by @mac_lock. * @link_up: Link status * @link_options: Link options (MII/GMII format) * @n_link_state_changes: Number of times the link has changed state @@ -700,27 +718,31 @@ struct efx_nic { enum nic_state state; enum reset_type reset_pending; - struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES]; + struct efx_tx_queue tx_queue[EFX_TX_QUEUE_COUNT]; struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES]; struct efx_channel channel[EFX_MAX_CHANNELS]; - int rss_queues; + int n_rx_queues; unsigned int rx_buffer_len; unsigned int rx_buffer_order; struct efx_buffer irq_status; volatile signed int last_irq_cpu; + struct efx_spi_device *spi_flash; + struct efx_spi_device *spi_eeprom; + unsigned n_rx_nodesc_drop_cnt; struct falcon_nic_data *nic_data; struct mutex mac_lock; - int port_enabled; + bool port_enabled; + bool port_inhibited; - int port_initialized; + bool port_initialized; struct net_device *net_dev; - int rx_checksum_enabled; + bool rx_checksum_enabled; atomic_t netif_stop_count; spinlock_t netif_stop_lock; @@ -728,6 +750,7 @@ struct efx_nic { struct efx_mac_stats mac_stats; struct efx_buffer stats_buffer; spinlock_t stats_lock; + bool stats_enabled; unsigned char mac_address[ETH_ALEN]; @@ -736,13 +759,13 @@ struct efx_nic { struct efx_phy_operations *phy_op; void *phy_data; struct mii_if_info mii; - unsigned tx_disabled; + enum efx_phy_mode phy_mode; - int link_up; + bool link_up; unsigned int link_options; unsigned int n_link_state_changes; - int promiscuous; + bool promiscuous; union efx_multicast_hash multicast_hash; enum efx_fc_type flow_control; struct work_struct reconfigure_work; @@ -829,50 +852,33 @@ struct efx_nic_type { continue; \ else -/* Iterate over all used channels with interrupts */ -#define efx_for_each_channel_with_interrupt(_channel, _efx) \ - for (_channel = &_efx->channel[0]; \ - _channel < &_efx->channel[EFX_MAX_CHANNELS]; \ - _channel++) \ - if (!(_channel->used_flags && _channel->has_interrupt)) \ - continue; \ - else - /* Iterate over all used TX queues */ #define efx_for_each_tx_queue(_tx_queue, _efx) \ for (_tx_queue = &_efx->tx_queue[0]; \ - _tx_queue < &_efx->tx_queue[EFX_MAX_TX_QUEUES]; \ - _tx_queue++) \ - if (!_tx_queue->used) \ - continue; \ - else + _tx_queue < &_efx->tx_queue[EFX_TX_QUEUE_COUNT]; \ + _tx_queue++) /* Iterate over all TX queues belonging to a channel */ #define efx_for_each_channel_tx_queue(_tx_queue, _channel) \ for (_tx_queue = &_channel->efx->tx_queue[0]; \ - _tx_queue < &_channel->efx->tx_queue[EFX_MAX_TX_QUEUES]; \ + _tx_queue < &_channel->efx->tx_queue[EFX_TX_QUEUE_COUNT]; \ _tx_queue++) \ - if ((!_tx_queue->used) || \ - (_tx_queue->channel != _channel)) \ + if (_tx_queue->channel != _channel) \ continue; \ else /* Iterate over all used RX queues */ #define efx_for_each_rx_queue(_rx_queue, _efx) \ for (_rx_queue = &_efx->rx_queue[0]; \ - _rx_queue < &_efx->rx_queue[EFX_MAX_RX_QUEUES]; \ - _rx_queue++) \ - if (!_rx_queue->used) \ - continue; \ - else + _rx_queue < &_efx->rx_queue[_efx->n_rx_queues]; \ + _rx_queue++) /* Iterate over all RX queues belonging to a channel */ #define efx_for_each_channel_rx_queue(_rx_queue, _channel) \ - for (_rx_queue = &_channel->efx->rx_queue[0]; \ - _rx_queue < &_channel->efx->rx_queue[EFX_MAX_RX_QUEUES]; \ - _rx_queue++) \ - if ((!_rx_queue->used) || \ - (_rx_queue->channel != _channel)) \ + for (_rx_queue = &_channel->efx->rx_queue[_channel->channel]; \ + _rx_queue; \ + _rx_queue = NULL) \ + if (_rx_queue->channel != _channel) \ continue; \ else @@ -886,13 +892,13 @@ static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue, } /* Set bit in a little-endian bitfield */ -static inline void set_bit_le(int nr, unsigned char *addr) +static inline void set_bit_le(unsigned nr, unsigned char *addr) { addr[nr / 8] |= (1 << (nr % 8)); } /* Clear bit in a little-endian bitfield */ -static inline void clear_bit_le(int nr, unsigned char *addr) +static inline void clear_bit_le(unsigned nr, unsigned char *addr) { addr[nr / 8] &= ~(1 << (nr % 8)); } diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index 9d02c84e6b2..f746536f4ff 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -15,15 +15,7 @@ */ extern struct efx_phy_operations falcon_tenxpress_phy_ops; -enum tenxpress_state { - TENXPRESS_STATUS_OFF = 0, - TENXPRESS_STATUS_OTEMP = 1, - TENXPRESS_STATUS_NORMAL = 2, -}; - -extern void tenxpress_set_state(struct efx_nic *efx, - enum tenxpress_state state); -extern void tenxpress_phy_blink(struct efx_nic *efx, int blink); +extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); extern void tenxpress_crc_err(struct efx_nic *efx); /**************************************************************************** diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 0d27dd39bc0..0f805da4ce5 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -212,8 +212,8 @@ void efx_lro_fini(struct net_lro_mgr *lro_mgr) * and populates a struct efx_rx_buffer with the relevant * information. Return a negative error code or 0 on success. */ -static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue, - struct efx_rx_buffer *rx_buf) +static int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue, + struct efx_rx_buffer *rx_buf) { struct efx_nic *efx = rx_queue->efx; struct net_device *net_dev = efx->net_dev; @@ -252,8 +252,8 @@ static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue, * and populates a struct efx_rx_buffer with the relevant * information. Return a negative error code or 0 on success. */ -static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue, - struct efx_rx_buffer *rx_buf) +static int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue, + struct efx_rx_buffer *rx_buf) { struct efx_nic *efx = rx_queue->efx; int bytes, space, offset; @@ -319,8 +319,8 @@ static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue, * and populates a struct efx_rx_buffer with the relevant * information. */ -static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue, - struct efx_rx_buffer *new_rx_buf) +static int efx_init_rx_buffer(struct efx_rx_queue *rx_queue, + struct efx_rx_buffer *new_rx_buf) { int rc = 0; @@ -340,8 +340,8 @@ static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue, return rc; } -static inline void efx_unmap_rx_buffer(struct efx_nic *efx, - struct efx_rx_buffer *rx_buf) +static void efx_unmap_rx_buffer(struct efx_nic *efx, + struct efx_rx_buffer *rx_buf) { if (rx_buf->page) { EFX_BUG_ON_PARANOID(rx_buf->skb); @@ -357,8 +357,8 @@ static inline void efx_unmap_rx_buffer(struct efx_nic *efx, } } -static inline void efx_free_rx_buffer(struct efx_nic *efx, - struct efx_rx_buffer *rx_buf) +static void efx_free_rx_buffer(struct efx_nic *efx, + struct efx_rx_buffer *rx_buf) { if (rx_buf->page) { __free_pages(rx_buf->page, efx->rx_buffer_order); @@ -369,8 +369,8 @@ static inline void efx_free_rx_buffer(struct efx_nic *efx, } } -static inline void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue, - struct efx_rx_buffer *rx_buf) +static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue, + struct efx_rx_buffer *rx_buf) { efx_unmap_rx_buffer(rx_queue->efx, rx_buf); efx_free_rx_buffer(rx_queue->efx, rx_buf); @@ -506,10 +506,10 @@ void efx_rx_work(struct work_struct *data) efx_schedule_slow_fill(rx_queue, 1); } -static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue, - struct efx_rx_buffer *rx_buf, - int len, int *discard, - int *leak_packet) +static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue, + struct efx_rx_buffer *rx_buf, + int len, bool *discard, + bool *leak_packet) { struct efx_nic *efx = rx_queue->efx; unsigned max_len = rx_buf->len - efx->type->rx_buffer_padding; @@ -520,7 +520,7 @@ static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue, /* The packet must be discarded, but this is only a fatal error * if the caller indicated it was */ - *discard = 1; + *discard = true; if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) { EFX_ERR_RL(efx, " RX queue %d seriously overlength " @@ -546,8 +546,8 @@ static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue, * Handles driverlink veto, and passes the fragment up via * the appropriate LRO method */ -static inline void efx_rx_packet_lro(struct efx_channel *channel, - struct efx_rx_buffer *rx_buf) +static void efx_rx_packet_lro(struct efx_channel *channel, + struct efx_rx_buffer *rx_buf) { struct net_lro_mgr *lro_mgr = &channel->lro_mgr; void *priv = channel; @@ -574,9 +574,9 @@ static inline void efx_rx_packet_lro(struct efx_channel *channel, } /* Allocate and construct an SKB around a struct page.*/ -static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf, - struct efx_nic *efx, - int hdr_len) +static struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf, + struct efx_nic *efx, + int hdr_len) { struct sk_buff *skb; @@ -621,11 +621,11 @@ static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf, } void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, - unsigned int len, int checksummed, int discard) + unsigned int len, bool checksummed, bool discard) { struct efx_nic *efx = rx_queue->efx; struct efx_rx_buffer *rx_buf; - int leak_packet = 0; + bool leak_packet = false; rx_buf = efx_rx_buffer(rx_queue, index); EFX_BUG_ON_PARANOID(!rx_buf->data); @@ -683,11 +683,11 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, /* Handle a received packet. Second half: Touches packet payload. */ void __efx_rx_packet(struct efx_channel *channel, - struct efx_rx_buffer *rx_buf, int checksummed) + struct efx_rx_buffer *rx_buf, bool checksummed) { struct efx_nic *efx = channel->efx; struct sk_buff *skb; - int lro = efx->net_dev->features & NETIF_F_LRO; + bool lro = !!(efx->net_dev->features & NETIF_F_LRO); /* If we're in loopback test, then pass the packet directly to the * loopback layer, and free the rx_buf here @@ -789,27 +789,18 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) /* Allocate RX buffers */ rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer); rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL); - if (!rx_queue->buffer) { - rc = -ENOMEM; - goto fail1; - } + if (!rx_queue->buffer) + return -ENOMEM; rc = falcon_probe_rx(rx_queue); - if (rc) - goto fail2; - - return 0; - - fail2: - kfree(rx_queue->buffer); - rx_queue->buffer = NULL; - fail1: - rx_queue->used = 0; - + if (rc) { + kfree(rx_queue->buffer); + rx_queue->buffer = NULL; + } return rc; } -int efx_init_rx_queue(struct efx_rx_queue *rx_queue) +void efx_init_rx_queue(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; unsigned int max_fill, trigger, limit; @@ -833,7 +824,7 @@ int efx_init_rx_queue(struct efx_rx_queue *rx_queue) rx_queue->fast_fill_limit = limit; /* Set up RX descriptor ring */ - return falcon_init_rx(rx_queue); + falcon_init_rx(rx_queue); } void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) @@ -872,7 +863,6 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue) kfree(rx_queue->buffer); rx_queue->buffer = NULL; - rx_queue->used = 0; } void efx_flush_lro(struct efx_channel *channel) diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h index f35e377bfc5..0e88a9ddc1c 100644 --- a/drivers/net/sfc/rx.h +++ b/drivers/net/sfc/rx.h @@ -14,7 +14,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); -int efx_init_rx_queue(struct efx_rx_queue *rx_queue); +void efx_init_rx_queue(struct efx_rx_queue *rx_queue); void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx); @@ -24,6 +24,6 @@ void efx_rx_strategy(struct efx_channel *channel); void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); void efx_rx_work(struct work_struct *data); void __efx_rx_packet(struct efx_channel *channel, - struct efx_rx_buffer *rx_buf, int checksummed); + struct efx_rx_buffer *rx_buf, bool checksummed); #endif /* EFX_RX_H */ diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 3b2de9fe7f2..362956e3fe1 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -27,6 +27,9 @@ #include "boards.h" #include "workarounds.h" #include "mac.h" +#include "spi.h" +#include "falcon_io.h" +#include "mdio_10g.h" /* * Loopback test packet structure @@ -51,7 +54,7 @@ static const char *payload_msg = "Hello world! This is an Efx loopback test in progress!"; /** - * efx_selftest_state - persistent state during a selftest + * efx_loopback_state - persistent state during a loopback selftest * @flush: Drop all packets in efx_loopback_rx_packet * @packet_count: Number of packets being used in this test * @skbs: An array of skbs transmitted @@ -59,10 +62,14 @@ static const char *payload_msg = * @rx_bad: RX bad packet count * @payload: Payload used in tests */ -struct efx_selftest_state { - int flush; +struct efx_loopback_state { + bool flush; int packet_count; struct sk_buff **skbs; + + /* Checksums are being offloaded */ + bool offload_csum; + atomic_t rx_good; atomic_t rx_bad; struct efx_loopback_payload payload; @@ -70,21 +77,65 @@ struct efx_selftest_state { /************************************************************************** * - * Configurable values + * MII, NVRAM and register tests * **************************************************************************/ -/* Level of loopback testing - * - * The maximum packet burst length is 16**(n-1), i.e. - * - * - Level 0 : no packets - * - Level 1 : 1 packet - * - Level 2 : 17 packets (1 * 1 packet, 1 * 16 packets) - * - Level 3 : 273 packets (1 * 1 packet, 1 * 16 packet, 1 * 256 packets) - * - */ -static unsigned int loopback_test_level = 3; +static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) +{ + int rc = 0; + u16 physid1, physid2; + struct mii_if_info *mii = &efx->mii; + struct net_device *net_dev = efx->net_dev; + + if (efx->phy_type == PHY_TYPE_NONE) + return 0; + + mutex_lock(&efx->mac_lock); + tests->mii = -1; + + physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); + physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); + + if ((physid1 == 0x0000) || (physid1 == 0xffff) || + (physid2 == 0x0000) || (physid2 == 0xffff)) { + EFX_ERR(efx, "no MII PHY present with ID %d\n", + mii->phy_id); + rc = -EINVAL; + goto out; + } + + rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); + if (rc) + goto out; + +out: + mutex_unlock(&efx->mac_lock); + tests->mii = rc ? -1 : 1; + return rc; +} + +static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) +{ + int rc; + + rc = falcon_read_nvram(efx, NULL); + tests->nvram = rc ? -1 : 1; + return rc; +} + +static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) +{ + int rc; + + /* Not supported on A-series silicon */ + if (falcon_rev(efx) < FALCON_REV_B0) + return 0; + + rc = falcon_test_registers(efx); + tests->registers = rc ? -1 : 1; + return rc; +} /************************************************************************** * @@ -107,7 +158,7 @@ static int efx_test_interrupts(struct efx_nic *efx, /* ACK each interrupting event queue. Receiving an interrupt due to * traffic before a test event is raised is considered a pass */ - efx_for_each_channel_with_interrupt(channel, efx) { + efx_for_each_channel(channel, efx) { if (channel->work_pending) efx_process_channel_now(channel); if (efx->last_irq_cpu >= 0) @@ -132,41 +183,6 @@ static int efx_test_interrupts(struct efx_nic *efx, return 0; } -/* Test generation and receipt of non-interrupting events */ -static int efx_test_eventq(struct efx_channel *channel, - struct efx_self_tests *tests) -{ - unsigned int magic; - - /* Channel specific code, limited to 20 bits */ - magic = (0x00010150 + channel->channel); - EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n", - channel->channel, magic); - - tests->eventq_dma[channel->channel] = -1; - tests->eventq_int[channel->channel] = 1; /* fake pass */ - tests->eventq_poll[channel->channel] = 1; /* fake pass */ - - /* Reset flag and zero magic word */ - channel->efx->last_irq_cpu = -1; - channel->eventq_magic = 0; - smp_wmb(); - - falcon_generate_test_event(channel, magic); - udelay(1); - - efx_process_channel_now(channel); - if (channel->eventq_magic != magic) { - EFX_ERR(channel->efx, "channel %d failed to see test event\n", - channel->channel); - return -ETIMEDOUT; - } else { - tests->eventq_dma[channel->channel] = 1; - } - - return 0; -} - /* Test generation and receipt of interrupting events */ static int efx_test_eventq_irq(struct efx_channel *channel, struct efx_self_tests *tests) @@ -230,39 +246,18 @@ static int efx_test_eventq_irq(struct efx_channel *channel, return 0; } -/************************************************************************** - * - * PHY testing - * - **************************************************************************/ - -/* Check PHY presence by reading the PHY ID registers */ -static int efx_test_phy(struct efx_nic *efx, - struct efx_self_tests *tests) +static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests) { - u16 physid1, physid2; - struct mii_if_info *mii = &efx->mii; - struct net_device *net_dev = efx->net_dev; + int rc; - if (efx->phy_type == PHY_TYPE_NONE) + if (!efx->phy_op->test) return 0; - EFX_LOG(efx, "testing PHY presence\n"); - tests->phy_ok = -1; - - physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); - physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); - - if ((physid1 != 0x0000) && (physid1 != 0xffff) && - (physid2 != 0x0000) && (physid2 != 0xffff)) { - EFX_LOG(efx, "found MII PHY %d ID 0x%x:%x\n", - mii->phy_id, physid1, physid2); - tests->phy_ok = 1; - return 0; - } - - EFX_ERR(efx, "no MII PHY present with ID %d\n", mii->phy_id); - return -ENODEV; + mutex_lock(&efx->mac_lock); + rc = efx->phy_op->test(efx); + mutex_unlock(&efx->mac_lock); + tests->phy = rc ? -1 : 1; + return rc; } /************************************************************************** @@ -278,7 +273,7 @@ static int efx_test_phy(struct efx_nic *efx, void efx_loopback_rx_packet(struct efx_nic *efx, const char *buf_ptr, int pkt_len) { - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; struct efx_loopback_payload *received; struct efx_loopback_payload *payload; @@ -289,11 +284,12 @@ void efx_loopback_rx_packet(struct efx_nic *efx, return; payload = &state->payload; - + received = (struct efx_loopback_payload *) buf_ptr; received->ip.saddr = payload->ip.saddr; - received->ip.check = payload->ip.check; - + if (state->offload_csum) + received->ip.check = payload->ip.check; + /* Check that header exists */ if (pkt_len < sizeof(received->header)) { EFX_ERR(efx, "saw runt RX packet (length %d) in %s loopback " @@ -362,7 +358,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, /* Initialise an efx_selftest_state for a new iteration */ static void efx_iterate_state(struct efx_nic *efx) { - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; struct net_device *net_dev = efx->net_dev; struct efx_loopback_payload *payload = &state->payload; @@ -395,17 +391,17 @@ static void efx_iterate_state(struct efx_nic *efx) smp_wmb(); } -static int efx_tx_loopback(struct efx_tx_queue *tx_queue) +static int efx_begin_loopback(struct efx_tx_queue *tx_queue) { struct efx_nic *efx = tx_queue->efx; - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; struct efx_loopback_payload *payload; struct sk_buff *skb; int i, rc; /* Transmit N copies of buffer */ for (i = 0; i < state->packet_count; i++) { - /* Allocate an skb, holding an extra reference for + /* Allocate an skb, holding an extra reference for * transmit completion counting */ skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); if (!skb) @@ -444,11 +440,25 @@ static int efx_tx_loopback(struct efx_tx_queue *tx_queue) return 0; } -static int efx_rx_loopback(struct efx_tx_queue *tx_queue, - struct efx_loopback_self_tests *lb_tests) +static int efx_poll_loopback(struct efx_nic *efx) +{ + struct efx_loopback_state *state = efx->loopback_selftest; + struct efx_channel *channel; + + /* NAPI polling is not enabled, so process channels + * synchronously */ + efx_for_each_channel(channel, efx) { + if (channel->work_pending) + efx_process_channel_now(channel); + } + return atomic_read(&state->rx_good) == state->packet_count; +} + +static int efx_end_loopback(struct efx_tx_queue *tx_queue, + struct efx_loopback_self_tests *lb_tests) { struct efx_nic *efx = tx_queue->efx; - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; struct sk_buff *skb; int tx_done = 0, rx_good, rx_bad; int i, rc = 0; @@ -507,11 +517,10 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, struct efx_loopback_self_tests *lb_tests) { struct efx_nic *efx = tx_queue->efx; - struct efx_selftest_state *state = efx->loopback_selftest; - struct efx_channel *channel; - int i, rc = 0; + struct efx_loopback_state *state = efx->loopback_selftest; + int i, begin_rc, end_rc; - for (i = 0; i < loopback_test_level; i++) { + for (i = 0; i < 3; i++) { /* Determine how many packets to send */ state->packet_count = (efx->type->txd_ring_mask + 1) / 3; state->packet_count = min(1 << (i << 2), state->packet_count); @@ -519,30 +528,31 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, state->packet_count, GFP_KERNEL); if (!state->skbs) return -ENOMEM; - state->flush = 0; + state->flush = false; EFX_LOG(efx, "TX queue %d testing %s loopback with %d " "packets\n", tx_queue->queue, LOOPBACK_MODE(efx), state->packet_count); efx_iterate_state(efx); - rc = efx_tx_loopback(tx_queue); - - /* NAPI polling is not enabled, so process channels synchronously */ - schedule_timeout_uninterruptible(HZ / 50); - efx_for_each_channel_with_interrupt(channel, efx) { - if (channel->work_pending) - efx_process_channel_now(channel); + begin_rc = efx_begin_loopback(tx_queue); + + /* This will normally complete very quickly, but be + * prepared to wait up to 100 ms. */ + msleep(1); + if (!efx_poll_loopback(efx)) { + msleep(100); + efx_poll_loopback(efx); } - rc |= efx_rx_loopback(tx_queue, lb_tests); + end_rc = efx_end_loopback(tx_queue, lb_tests); kfree(state->skbs); - if (rc) { + if (begin_rc || end_rc) { /* Wait a while to ensure there are no packets * floating around after a failure. */ schedule_timeout_uninterruptible(HZ / 10); - return rc; + return begin_rc ? begin_rc : end_rc; } } @@ -550,49 +560,36 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, "of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx), state->packet_count); - return rc; + return 0; } -static int efx_test_loopbacks(struct efx_nic *efx, +static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, struct efx_self_tests *tests, unsigned int loopback_modes) { - struct efx_selftest_state *state = efx->loopback_selftest; - struct ethtool_cmd ecmd, ecmd_loopback; + enum efx_loopback_mode mode; + struct efx_loopback_state *state; struct efx_tx_queue *tx_queue; - enum efx_loopback_mode old_mode, mode; - int count, rc = 0, link_up; - - rc = efx_ethtool_get_settings(efx->net_dev, &ecmd); - if (rc) { - EFX_ERR(efx, "could not get GMII settings\n"); - return rc; - } - old_mode = efx->loopback_mode; - - /* Disable autonegotiation for the purposes of loopback */ - memcpy(&ecmd_loopback, &ecmd, sizeof(ecmd_loopback)); - if (ecmd_loopback.autoneg == AUTONEG_ENABLE) { - ecmd_loopback.autoneg = AUTONEG_DISABLE; - ecmd_loopback.duplex = DUPLEX_FULL; - ecmd_loopback.speed = SPEED_10000; - } + bool link_up; + int count, rc = 0; - rc = efx_ethtool_set_settings(efx->net_dev, &ecmd_loopback); - if (rc) { - EFX_ERR(efx, "could not disable autonegotiation\n"); - goto out; - } - tests->loopback_speed = ecmd_loopback.speed; - tests->loopback_full_duplex = ecmd_loopback.duplex; + /* Set the port loopback_selftest member. From this point on + * all received packets will be dropped. Mark the state as + * "flushing" so all inflight packets are dropped */ + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + BUG_ON(efx->loopback_selftest); + state->flush = true; + efx->loopback_selftest = state; /* Test all supported loopback modes */ - for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) { + for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { if (!(loopback_modes & (1 << mode))) continue; /* Move the port into the specified loopback mode. */ - state->flush = 1; + state->flush = true; efx->loopback_mode = mode; efx_reconfigure_port(efx); @@ -616,7 +613,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, */ link_up = efx->link_up; if (!falcon_xaui_link_ok(efx)) - link_up = 0; + link_up = false; } while ((++count < 20) && !link_up); @@ -634,18 +631,21 @@ static int efx_test_loopbacks(struct efx_nic *efx, /* Test every TX queue */ efx_for_each_tx_queue(tx_queue, efx) { - rc |= efx_test_loopback(tx_queue, - &tests->loopback[mode]); + state->offload_csum = (tx_queue->queue == + EFX_TX_QUEUE_OFFLOAD_CSUM); + rc = efx_test_loopback(tx_queue, + &tests->loopback[mode]); if (rc) goto out; } } out: - /* Take out of loopback and restore PHY settings */ - state->flush = 1; - efx->loopback_mode = old_mode; - efx_ethtool_set_settings(efx->net_dev, &ecmd); + /* Remove the flush. The caller will remove the loopback setting */ + state->flush = true; + efx->loopback_selftest = NULL; + wmb(); + kfree(state); return rc; } @@ -661,23 +661,27 @@ static int efx_test_loopbacks(struct efx_nic *efx, int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) { struct efx_channel *channel; - int rc = 0; + int rc, rc2 = 0; + + rc = efx_test_mii(efx, tests); + if (rc && !rc2) + rc2 = rc; - EFX_LOG(efx, "performing online self-tests\n"); + rc = efx_test_nvram(efx, tests); + if (rc && !rc2) + rc2 = rc; + + rc = efx_test_interrupts(efx, tests); + if (rc && !rc2) + rc2 = rc; - rc |= efx_test_interrupts(efx, tests); efx_for_each_channel(channel, efx) { - if (channel->has_interrupt) - rc |= efx_test_eventq_irq(channel, tests); - else - rc |= efx_test_eventq(channel, tests); + rc = efx_test_eventq_irq(channel, tests); + if (rc && !rc2) + rc2 = rc; } - rc |= efx_test_phy(efx, tests); - - if (rc) - EFX_ERR(efx, "failed online self-tests\n"); - return rc; + return rc2; } /* Offline (i.e. disruptive) testing @@ -685,35 +689,66 @@ int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) int efx_offline_test(struct efx_nic *efx, struct efx_self_tests *tests, unsigned int loopback_modes) { - struct efx_selftest_state *state; - int rc = 0; - - EFX_LOG(efx, "performing offline self-tests\n"); + enum efx_loopback_mode loopback_mode = efx->loopback_mode; + int phy_mode = efx->phy_mode; + struct ethtool_cmd ecmd, ecmd_test; + int rc, rc2 = 0; + + /* force the carrier state off so the kernel doesn't transmit during + * the loopback test, and the watchdog timeout doesn't fire. Also put + * falcon into loopback for the register test. + */ + mutex_lock(&efx->mac_lock); + efx->port_inhibited = true; + if (efx->loopback_modes) + efx->loopback_mode = __ffs(efx->loopback_modes); + __efx_reconfigure_port(efx); + mutex_unlock(&efx->mac_lock); + + /* free up all consumers of SRAM (including all the queues) */ + efx_reset_down(efx, &ecmd); + + rc = efx_test_chip(efx, tests); + if (rc && !rc2) + rc2 = rc; + + /* reset the chip to recover from the register test */ + rc = falcon_reset_hw(efx, RESET_TYPE_ALL); + + /* Modify the saved ecmd so that when efx_reset_up() restores the phy + * state, AN is disabled, and the phy is powered, and out of loopback */ + memcpy(&ecmd_test, &ecmd, sizeof(ecmd_test)); + if (ecmd_test.autoneg == AUTONEG_ENABLE) { + ecmd_test.autoneg = AUTONEG_DISABLE; + ecmd_test.duplex = DUPLEX_FULL; + ecmd_test.speed = SPEED_10000; + } + efx->loopback_mode = LOOPBACK_NONE; - /* Create a selftest_state structure to hold state for the test */ - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) { - rc = -ENOMEM; - goto out; + rc = efx_reset_up(efx, &ecmd_test, rc == 0); + if (rc) { + EFX_ERR(efx, "Unable to recover from chip test\n"); + efx_schedule_reset(efx, RESET_TYPE_DISABLE); + return rc; } - /* Set the port loopback_selftest member. From this point on - * all received packets will be dropped. Mark the state as - * "flushing" so all inflight packets are dropped */ - BUG_ON(efx->loopback_selftest); - state->flush = 1; - efx->loopback_selftest = state; + tests->loopback_speed = ecmd_test.speed; + tests->loopback_full_duplex = ecmd_test.duplex; - rc = efx_test_loopbacks(efx, tests, loopback_modes); + rc = efx_test_phy(efx, tests); + if (rc && !rc2) + rc2 = rc; - efx->loopback_selftest = NULL; - wmb(); - kfree(state); + rc = efx_test_loopbacks(efx, ecmd_test, tests, loopback_modes); + if (rc && !rc2) + rc2 = rc; - out: - if (rc) - EFX_ERR(efx, "failed offline self-tests\n"); + /* restore the PHY to the previous state */ + efx->loopback_mode = loopback_mode; + efx->phy_mode = phy_mode; + efx->port_inhibited = false; + efx_ethtool_set_settings(efx->net_dev, &ecmd); - return rc; + return rc2; } diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index f6999c2b622..fc15df15d76 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h @@ -18,8 +18,8 @@ */ struct efx_loopback_self_tests { - int tx_sent[EFX_MAX_TX_QUEUES]; - int tx_done[EFX_MAX_TX_QUEUES]; + int tx_sent[EFX_TX_QUEUE_COUNT]; + int tx_done[EFX_TX_QUEUE_COUNT]; int rx_good; int rx_bad; }; @@ -29,14 +29,19 @@ struct efx_loopback_self_tests { * indicates failure. */ struct efx_self_tests { + /* online tests */ + int mii; + int nvram; int interrupt; int eventq_dma[EFX_MAX_CHANNELS]; int eventq_int[EFX_MAX_CHANNELS]; int eventq_poll[EFX_MAX_CHANNELS]; - int phy_ok; + /* offline tests */ + int registers; + int phy; int loopback_speed; int loopback_full_duplex; - struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX]; + struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1]; }; extern void efx_loopback_rx_packet(struct efx_nic *efx, diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index b2784952399..fe4e3fd2233 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c @@ -13,11 +13,13 @@ * the PHY */ #include <linux/delay.h> +#include "net_driver.h" #include "efx.h" #include "phy.h" #include "boards.h" #include "falcon.h" #include "falcon_hwdefs.h" +#include "falcon_io.h" #include "mac.h" /************************************************************************** @@ -120,23 +122,144 @@ static void sfe4001_poweroff(struct efx_nic *efx) i2c_smbus_read_byte_data(hwmon_client, RSL); } -static void sfe4001_fini(struct efx_nic *efx) +static int sfe4001_poweron(struct efx_nic *efx) { - EFX_INFO(efx, "%s\n", __func__); + struct i2c_client *hwmon_client = efx->board_info.hwmon_client; + struct i2c_client *ioexp_client = efx->board_info.ioexp_client; + unsigned int i, j; + int rc; + u8 out; + + /* Clear any previous over-temperature alert */ + rc = i2c_smbus_read_byte_data(hwmon_client, RSL); + if (rc < 0) + return rc; + + /* Enable port 0 and port 1 outputs on IO expander */ + rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); + if (rc) + return rc; + rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, + 0xff & ~(1 << P1_SPARE_LBN)); + if (rc) + goto fail_on; + + /* If PHY power is on, turn it all off and wait 1 second to + * ensure a full reset. + */ + rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT); + if (rc < 0) + goto fail_on; + out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | + (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | + (0 << P0_EN_1V0X_LBN)); + if (rc != out) { + EFX_INFO(efx, "power-cycling PHY\n"); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); + if (rc) + goto fail_on; + schedule_timeout_uninterruptible(HZ); + } + for (i = 0; i < 20; ++i) { + /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ + out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | + (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | + (1 << P0_X_TRST_LBN)); + if (efx->phy_mode & PHY_MODE_SPECIAL) + out |= 1 << P0_EN_3V3X_LBN; + + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); + if (rc) + goto fail_on; + msleep(10); + + /* Turn on 1V power rail */ + out &= ~(1 << P0_EN_1V0X_LBN); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); + if (rc) + goto fail_on; + + EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i); + + /* In flash config mode, DSP does not turn on AFE, so + * just wait 1 second. + */ + if (efx->phy_mode & PHY_MODE_SPECIAL) { + schedule_timeout_uninterruptible(HZ); + return 0; + } + + for (j = 0; j < 10; ++j) { + msleep(100); + + /* Check DSP has asserted AFE power line */ + rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); + if (rc < 0) + goto fail_on; + if (rc & (1 << P1_AFE_PWD_LBN)) + return 0; + } + } + + EFX_INFO(efx, "timed out waiting for DSP boot\n"); + rc = -ETIMEDOUT; +fail_on: sfe4001_poweroff(efx); - i2c_unregister_device(efx->board_info.ioexp_client); - i2c_unregister_device(efx->board_info.hwmon_client); + return rc; } -/* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected - * to the FLASH_CFG_1 input on the DSP. We must keep it high at power- - * up to allow writing the flash (done through MDIO from userland). +/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin + * using the 3V3X output of the IO-expander. Allow the user to set + * this when the device is stopped, and keep it stopped then. */ -unsigned int sfe4001_phy_flash_cfg; -module_param_named(phy_flash_cfg, sfe4001_phy_flash_cfg, uint, 0444); -MODULE_PARM_DESC(phy_flash_cfg, - "Force PHY to enter flash configuration mode"); + +static ssize_t show_phy_flash_cfg(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL)); +} + +static ssize_t set_phy_flash_cfg(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + enum efx_phy_mode old_mode, new_mode; + int err; + + rtnl_lock(); + old_mode = efx->phy_mode; + if (count == 0 || *buf == '0') + new_mode = old_mode & ~PHY_MODE_SPECIAL; + else + new_mode = PHY_MODE_SPECIAL; + if (old_mode == new_mode) { + err = 0; + } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { + err = -EBUSY; + } else { + efx->phy_mode = new_mode; + err = sfe4001_poweron(efx); + efx_reconfigure_port(efx); + } + rtnl_unlock(); + + return err ? err : count; +} + +static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); + +static void sfe4001_fini(struct efx_nic *efx) +{ + EFX_INFO(efx, "%s\n", __func__); + + device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); + sfe4001_poweroff(efx); + i2c_unregister_device(efx->board_info.ioexp_client); + i2c_unregister_device(efx->board_info.hwmon_client); +} /* This board uses an I2C expander to provider power to the PHY, which needs to * be turned on before the PHY can be used. @@ -144,41 +267,14 @@ MODULE_PARM_DESC(phy_flash_cfg, */ int sfe4001_init(struct efx_nic *efx) { - struct i2c_client *hwmon_client, *ioexp_client; - unsigned int count; + struct i2c_client *hwmon_client; int rc; - u8 out; - efx_dword_t reg; hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647); if (!hwmon_client) return -EIO; efx->board_info.hwmon_client = hwmon_client; - ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); - if (!ioexp_client) { - rc = -EIO; - goto fail_hwmon; - } - efx->board_info.ioexp_client = ioexp_client; - - /* 10Xpress has fixed-function LED pins, so there is no board-specific - * blink code. */ - efx->board_info.blink = tenxpress_phy_blink; - - /* Ensure that XGXS and XAUI SerDes are held in reset */ - EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1, - XX_PWRDNB_EN, 1, - XX_RSTPLLAB_EN, 1, - XX_RESETA_EN, 1, - XX_RESETB_EN, 1, - XX_RSTXGXSRX_EN, 1, - XX_RSTXGXSTX_EN, 1); - falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); - udelay(10); - - efx->board_info.fini = sfe4001_fini; - /* Set DSP over-temperature alert threshold */ EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature); rc = i2c_smbus_write_byte_data(hwmon_client, WLHO, @@ -195,78 +291,34 @@ int sfe4001_init(struct efx_nic *efx) goto fail_ioexp; } - /* Clear any previous over-temperature alert */ - rc = i2c_smbus_read_byte_data(hwmon_client, RSL); - if (rc < 0) - goto fail_ioexp; + efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); + if (!efx->board_info.ioexp_client) { + rc = -EIO; + goto fail_hwmon; + } - /* Enable port 0 and port 1 outputs on IO expander */ - rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); + /* 10Xpress has fixed-function LED pins, so there is no board-specific + * blink code. */ + efx->board_info.blink = tenxpress_phy_blink; + + efx->board_info.fini = sfe4001_fini; + + rc = sfe4001_poweron(efx); if (rc) goto fail_ioexp; - rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, - 0xff & ~(1 << P1_SPARE_LBN)); - if (rc) - goto fail_on; - /* Turn all power off then wait 1 sec. This ensures PHY is reset */ - out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | - (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | - (0 << P0_EN_1V0X_LBN)); - rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); + rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); if (rc) goto fail_on; - schedule_timeout_uninterruptible(HZ); - count = 0; - do { - /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ - out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | - (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | - (1 << P0_X_TRST_LBN)); - if (sfe4001_phy_flash_cfg) - out |= 1 << P0_EN_3V3X_LBN; - - rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); - if (rc) - goto fail_on; - msleep(10); - - /* Turn on 1V power rail */ - out &= ~(1 << P0_EN_1V0X_LBN); - rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); - if (rc) - goto fail_on; - - EFX_INFO(efx, "waiting for power (attempt %d)...\n", count); - - schedule_timeout_uninterruptible(HZ); - - /* Check DSP is powered */ - rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); - if (rc < 0) - goto fail_on; - if (rc & (1 << P1_AFE_PWD_LBN)) - goto done; - - /* DSP doesn't look powered in flash config mode */ - if (sfe4001_phy_flash_cfg) - goto done; - } while (++count < 20); - - EFX_INFO(efx, "timed out waiting for power\n"); - rc = -ETIMEDOUT; - goto fail_on; - -done: EFX_INFO(efx, "PHY is powered on\n"); return 0; fail_on: sfe4001_poweroff(efx); fail_ioexp: - i2c_unregister_device(ioexp_client); + i2c_unregister_device(efx->board_info.ioexp_client); fail_hwmon: - i2c_unregister_device(hwmon_client); + i2c_unregister_device(hwmon_client); return rc; } diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h index 34412f3d41c..feef6194237 100644 --- a/drivers/net/sfc/spi.h +++ b/drivers/net/sfc/spi.h @@ -19,53 +19,48 @@ * *************************************************************************/ -/* - * Commands common to all known devices. - * +#define SPI_WRSR 0x01 /* Write status register */ +#define SPI_WRITE 0x02 /* Write data to memory array */ +#define SPI_READ 0x03 /* Read data from memory array */ +#define SPI_WRDI 0x04 /* Reset write enable latch */ +#define SPI_RDSR 0x05 /* Read status register */ +#define SPI_WREN 0x06 /* Set write enable latch */ + +#define SPI_STATUS_WPEN 0x80 /* Write-protect pin enabled */ +#define SPI_STATUS_BP2 0x10 /* Block protection bit 2 */ +#define SPI_STATUS_BP1 0x08 /* Block protection bit 1 */ +#define SPI_STATUS_BP0 0x04 /* Block protection bit 0 */ +#define SPI_STATUS_WEN 0x02 /* State of the write enable latch */ +#define SPI_STATUS_NRDY 0x01 /* Device busy flag */ + +/** + * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device + * @efx: The Efx controller that owns this device + * @device_id: Controller's id for the device + * @size: Size (in bytes) + * @addr_len: Number of address bytes in read/write commands + * @munge_address: Flag whether addresses should be munged. + * Some devices with 9-bit addresses (e.g. AT25040A EEPROM) + * use bit 3 of the command byte as address bit A8, rather + * than having a two-byte address. If this flag is set, then + * commands should be munged in this way. + * @block_size: Write block size (in bytes). + * Write commands are limited to blocks with this size and alignment. + * @read: Read function for the device + * @write: Write function for the device */ - -/* Write status register */ -#define SPI_WRSR 0x01 - -/* Write data to memory array */ -#define SPI_WRITE 0x02 - -/* Read data from memory array */ -#define SPI_READ 0x03 - -/* Reset write enable latch */ -#define SPI_WRDI 0x04 - -/* Read status register */ -#define SPI_RDSR 0x05 - -/* Set write enable latch */ -#define SPI_WREN 0x06 - -/* SST: Enable write to status register */ -#define SPI_SST_EWSR 0x50 - -/* - * Status register bits. Not all bits are supported on all devices. - * - */ - -/* Write-protect pin enabled */ -#define SPI_STATUS_WPEN 0x80 - -/* Block protection bit 2 */ -#define SPI_STATUS_BP2 0x10 - -/* Block protection bit 1 */ -#define SPI_STATUS_BP1 0x08 - -/* Block protection bit 0 */ -#define SPI_STATUS_BP0 0x04 - -/* State of the write enable latch */ -#define SPI_STATUS_WEN 0x02 - -/* Device busy flag */ -#define SPI_STATUS_NRDY 0x01 +struct efx_spi_device { + struct efx_nic *efx; + int device_id; + unsigned int size; + unsigned int addr_len; + unsigned int munge_address:1; + unsigned int block_size; +}; + +int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, + size_t len, size_t *retlen, u8 *buffer); +int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, + size_t len, size_t *retlen, const u8 *buffer); #endif /* EFX_SPI_H */ diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index c0146061c32..d507c93d666 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -65,25 +65,10 @@ #define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) -/* Self test (BIST) control register */ -#define PMA_PMD_BIST_CTRL_REG (0xc014) -#define PMA_PMD_BIST_BER_LBN (2) /* Run BER test */ -#define PMA_PMD_BIST_CONT_LBN (1) /* Run continuous BIST until cleared */ -#define PMA_PMD_BIST_SINGLE_LBN (0) /* Run 1 BIST iteration (self clears) */ -/* Self test status register */ -#define PMA_PMD_BIST_STAT_REG (0xc015) -#define PMA_PMD_BIST_ENX_LBN (3) -#define PMA_PMD_BIST_PMA_LBN (2) -#define PMA_PMD_BIST_RXD_LBN (1) -#define PMA_PMD_BIST_AFE_LBN (0) - /* Special Software reset register */ #define PMA_PMD_EXT_CTRL_REG 49152 #define PMA_PMD_EXT_SSR_LBN 15 -#define BIST_MAX_DELAY (1000) -#define BIST_POLL_DELAY (10) - /* Misc register defines */ #define PCS_CLOCK_CTRL_REG 0xd801 #define PLL312_RST_N_LBN 2 @@ -119,27 +104,12 @@ MODULE_PARM_DESC(crc_error_reset_threshold, "Max number of CRC errors before XAUI reset"); struct tenxpress_phy_data { - enum tenxpress_state state; enum efx_loopback_mode loopback_mode; atomic_t bad_crc_count; - int tx_disabled; + enum efx_phy_mode phy_mode; int bad_lp_tries; }; -static int tenxpress_state_is(struct efx_nic *efx, int state) -{ - struct tenxpress_phy_data *phy_data = efx->phy_data; - return (phy_data != NULL) && (state == phy_data->state); -} - -void tenxpress_set_state(struct efx_nic *efx, - enum tenxpress_state state) -{ - struct tenxpress_phy_data *phy_data = efx->phy_data; - if (phy_data != NULL) - phy_data->state = state; -} - void tenxpress_crc_err(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; @@ -176,8 +146,6 @@ static int tenxpress_phy_check(struct efx_nic *efx) return 0; } -static void tenxpress_reset_xaui(struct efx_nic *efx); - static int tenxpress_init(struct efx_nic *efx) { int rc, reg; @@ -214,15 +182,12 @@ static int tenxpress_phy_init(struct efx_nic *efx) if (!phy_data) return -ENOMEM; efx->phy_data = phy_data; + phy_data->phy_mode = efx->phy_mode; - tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL); - - if (!sfe4001_phy_flash_cfg) { - rc = mdio_clause45_wait_reset_mmds(efx, - TENXPRESS_REQUIRED_DEVS); - if (rc < 0) - goto fail; - } + rc = mdio_clause45_wait_reset_mmds(efx, + TENXPRESS_REQUIRED_DEVS); + if (rc < 0) + goto fail; rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); if (rc < 0) @@ -249,7 +214,10 @@ static int tenxpress_special_reset(struct efx_nic *efx) { int rc, reg; - EFX_TRACE(efx, "%s\n", __func__); + /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so + * a special software reset can glitch the XGMAC sufficiently for stats + * requests to fail. Since we don't ofen special_reset, just lock. */ + spin_lock(&efx->stats_lock); /* Initiate reset */ reg = mdio_clause45_read(efx, efx->mii.phy_id, @@ -258,23 +226,25 @@ static int tenxpress_special_reset(struct efx_nic *efx) mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, PMA_PMD_EXT_CTRL_REG, reg); - msleep(200); + mdelay(200); /* Wait for the blocks to come out of reset */ rc = mdio_clause45_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) - return rc; + goto unlock; /* Try and reconfigure the device */ rc = tenxpress_init(efx); if (rc < 0) - return rc; + goto unlock; - return 0; +unlock: + spin_unlock(&efx->stats_lock); + return rc; } -static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp) +static void tenxpress_set_bad_lp(struct efx_nic *efx, bool bad_lp) { struct tenxpress_phy_data *pd = efx->phy_data; int reg; @@ -311,15 +281,15 @@ static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp) * into a non-10GBT port and if so warn the user that they won't get * link any time soon as we are 10GBT only, unless caller specified * not to do this check (it isn't useful in loopback) */ -static int tenxpress_link_ok(struct efx_nic *efx, int check_lp) +static bool tenxpress_link_ok(struct efx_nic *efx, bool check_lp) { - int ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS); + bool ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS); if (ok) { - tenxpress_set_bad_lp(efx, 0); + tenxpress_set_bad_lp(efx, false); } else if (check_lp) { /* Are we plugged into the wrong sort of link? */ - int bad_lp = 0; + bool bad_lp = false; int phy_id = efx->mii.phy_id; int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_STATUS); @@ -332,7 +302,7 @@ static int tenxpress_link_ok(struct efx_nic *efx, int check_lp) * bit has the advantage of not clearing when autoneg * restarts. */ if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) { - tenxpress_set_bad_lp(efx, 0); + tenxpress_set_bad_lp(efx, false); return ok; } @@ -367,16 +337,19 @@ static void tenxpress_phyxs_loopback(struct efx_nic *efx) static void tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; - int loop_change = LOOPBACK_OUT_OF(phy_data, efx, - TENXPRESS_LOOPBACKS); + bool loop_change = LOOPBACK_OUT_OF(phy_data, efx, + TENXPRESS_LOOPBACKS); - if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL)) + if (efx->phy_mode & PHY_MODE_SPECIAL) { + phy_data->phy_mode = efx->phy_mode; return; + } /* When coming out of transmit disable, coming out of low power * mode, or moving out of any PHY internal loopback mode, * perform a special software reset */ - if ((phy_data->tx_disabled && !efx->tx_disabled) || + if ((efx->phy_mode == PHY_MODE_NORMAL && + phy_data->phy_mode != PHY_MODE_NORMAL) || loop_change) { tenxpress_special_reset(efx); falcon_reset_xaui(efx); @@ -386,9 +359,9 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) mdio_clause45_phy_reconfigure(efx); tenxpress_phyxs_loopback(efx); - phy_data->tx_disabled = efx->tx_disabled; phy_data->loopback_mode = efx->loopback_mode; - efx->link_up = tenxpress_link_ok(efx, 0); + phy_data->phy_mode = efx->phy_mode; + efx->link_up = tenxpress_link_ok(efx, false); efx->link_options = GM_LPA_10000FULL; } @@ -402,16 +375,14 @@ static void tenxpress_phy_clear_interrupt(struct efx_nic *efx) static int tenxpress_phy_check_hw(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; - int phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL); - int link_ok; + bool link_ok; - link_ok = phy_up && tenxpress_link_ok(efx, 1); + link_ok = tenxpress_link_ok(efx, true); if (link_ok != efx->link_up) falcon_xmac_sim_phy_event(efx); - /* Nothing to check if we've already shut down the PHY */ - if (!phy_up) + if (phy_data->phy_mode != PHY_MODE_NORMAL) return 0; if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { @@ -444,7 +415,7 @@ static void tenxpress_phy_fini(struct efx_nic *efx) /* Set the RX and TX LEDs and Link LED flashing. The other LEDs * (which probably aren't wired anyway) are left in AUTO mode */ -void tenxpress_phy_blink(struct efx_nic *efx, int blink) +void tenxpress_phy_blink(struct efx_nic *efx, bool blink) { int reg; @@ -459,52 +430,10 @@ void tenxpress_phy_blink(struct efx_nic *efx, int blink) PMA_PMD_LED_OVERR_REG, reg); } -static void tenxpress_reset_xaui(struct efx_nic *efx) +static int tenxpress_phy_test(struct efx_nic *efx) { - int phy = efx->mii.phy_id; - int clk_ctrl, test_select, soft_rst2; - - /* Real work is done on clock_ctrl other resets are thought to be - * optional but make the reset more reliable - */ - - /* Read */ - clk_ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS, - PCS_CLOCK_CTRL_REG); - test_select = mdio_clause45_read(efx, phy, MDIO_MMD_PCS, - PCS_TEST_SELECT_REG); - soft_rst2 = mdio_clause45_read(efx, phy, MDIO_MMD_PCS, - PCS_SOFT_RST2_REG); - - /* Put in reset */ - test_select &= ~(1 << CLK312_EN_LBN); - mdio_clause45_write(efx, phy, MDIO_MMD_PCS, - PCS_TEST_SELECT_REG, test_select); - - soft_rst2 &= ~((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN)); - mdio_clause45_write(efx, phy, MDIO_MMD_PCS, - PCS_SOFT_RST2_REG, soft_rst2); - - clk_ctrl &= ~(1 << PLL312_RST_N_LBN); - mdio_clause45_write(efx, phy, MDIO_MMD_PCS, - PCS_CLOCK_CTRL_REG, clk_ctrl); - udelay(10); - - /* Remove reset */ - clk_ctrl |= (1 << PLL312_RST_N_LBN); - mdio_clause45_write(efx, phy, MDIO_MMD_PCS, - PCS_CLOCK_CTRL_REG, clk_ctrl); - udelay(10); - - soft_rst2 |= ((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN)); - mdio_clause45_write(efx, phy, MDIO_MMD_PCS, - PCS_SOFT_RST2_REG, soft_rst2); - udelay(10); - - test_select |= (1 << CLK312_EN_LBN); - mdio_clause45_write(efx, phy, MDIO_MMD_PCS, - PCS_TEST_SELECT_REG, test_select); - udelay(10); + /* BIST is automatically run after a special software reset */ + return tenxpress_special_reset(efx); } struct efx_phy_operations falcon_tenxpress_phy_ops = { @@ -513,7 +442,7 @@ struct efx_phy_operations falcon_tenxpress_phy_ops = { .check_hw = tenxpress_phy_check_hw, .fini = tenxpress_phy_fini, .clear_interrupt = tenxpress_phy_clear_interrupt, - .reset_xaui = tenxpress_reset_xaui, + .test = tenxpress_phy_test, .mmds = TENXPRESS_REQUIRED_DEVS, .loopbacks = TENXPRESS_LOOPBACKS, }; diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 5e8374ab28e..da3e9ff339f 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -47,7 +47,7 @@ void efx_stop_queue(struct efx_nic *efx) * We want to be able to nest calls to netif_stop_queue(), since each * channel can have an individual stop on the queue. */ -inline void efx_wake_queue(struct efx_nic *efx) +void efx_wake_queue(struct efx_nic *efx) { local_bh_disable(); if (atomic_dec_and_lock(&efx->netif_stop_count, @@ -59,19 +59,21 @@ inline void efx_wake_queue(struct efx_nic *efx) local_bh_enable(); } -static inline void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, - struct efx_tx_buffer *buffer) +static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, + struct efx_tx_buffer *buffer) { if (buffer->unmap_len) { struct pci_dev *pci_dev = tx_queue->efx->pci_dev; + dma_addr_t unmap_addr = (buffer->dma_addr + buffer->len - + buffer->unmap_len); if (buffer->unmap_single) - pci_unmap_single(pci_dev, buffer->unmap_addr, - buffer->unmap_len, PCI_DMA_TODEVICE); + pci_unmap_single(pci_dev, unmap_addr, buffer->unmap_len, + PCI_DMA_TODEVICE); else - pci_unmap_page(pci_dev, buffer->unmap_addr, - buffer->unmap_len, PCI_DMA_TODEVICE); + pci_unmap_page(pci_dev, unmap_addr, buffer->unmap_len, + PCI_DMA_TODEVICE); buffer->unmap_len = 0; - buffer->unmap_single = 0; + buffer->unmap_single = false; } if (buffer->skb) { @@ -103,13 +105,13 @@ struct efx_tso_header { }; static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, - const struct sk_buff *skb); + struct sk_buff *skb); static void efx_fini_tso(struct efx_tx_queue *tx_queue); static void efx_tsoh_heap_free(struct efx_tx_queue *tx_queue, struct efx_tso_header *tsoh); -static inline void efx_tsoh_free(struct efx_tx_queue *tx_queue, - struct efx_tx_buffer *buffer) +static void efx_tsoh_free(struct efx_tx_queue *tx_queue, + struct efx_tx_buffer *buffer) { if (buffer->tsoh) { if (likely(!buffer->tsoh->unmap_len)) { @@ -136,8 +138,8 @@ static inline void efx_tsoh_free(struct efx_tx_queue *tx_queue, * Returns NETDEV_TX_OK or NETDEV_TX_BUSY * You must hold netif_tx_lock() to call this function. */ -static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue, - const struct sk_buff *skb) +static int efx_enqueue_skb(struct efx_tx_queue *tx_queue, + struct sk_buff *skb) { struct efx_nic *efx = tx_queue->efx; struct pci_dev *pci_dev = efx->pci_dev; @@ -148,7 +150,7 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue, unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign; dma_addr_t dma_addr, unmap_addr = 0; unsigned int dma_len; - unsigned unmap_single; + bool unmap_single; int q_space, i = 0; int rc = NETDEV_TX_OK; @@ -167,7 +169,7 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue, * since this is more efficient on machines with sparse * memory. */ - unmap_single = 1; + unmap_single = true; dma_addr = pci_map_single(pci_dev, skb->data, len, PCI_DMA_TODEVICE); /* Process all fragments */ @@ -213,7 +215,7 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue, EFX_BUG_ON_PARANOID(buffer->tsoh); EFX_BUG_ON_PARANOID(buffer->skb); EFX_BUG_ON_PARANOID(buffer->len); - EFX_BUG_ON_PARANOID(buffer->continuation != 1); + EFX_BUG_ON_PARANOID(!buffer->continuation); EFX_BUG_ON_PARANOID(buffer->unmap_len); dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1); @@ -233,7 +235,6 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue, } while (len); /* Transfer ownership of the unmapping to the final buffer */ - buffer->unmap_addr = unmap_addr; buffer->unmap_single = unmap_single; buffer->unmap_len = unmap_len; unmap_len = 0; @@ -247,14 +248,14 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue, page_offset = fragment->page_offset; i++; /* Map for DMA */ - unmap_single = 0; + unmap_single = false; dma_addr = pci_map_page(pci_dev, page, page_offset, len, PCI_DMA_TODEVICE); } /* Transfer ownership of the skb to the final buffer */ buffer->skb = skb; - buffer->continuation = 0; + buffer->continuation = false; /* Pass off to hardware */ falcon_push_buffers(tx_queue); @@ -287,9 +288,14 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue, } /* Free the fragment we were mid-way through pushing */ - if (unmap_len) - pci_unmap_page(pci_dev, unmap_addr, unmap_len, - PCI_DMA_TODEVICE); + if (unmap_len) { + if (unmap_single) + pci_unmap_single(pci_dev, unmap_addr, unmap_len, + PCI_DMA_TODEVICE); + else + pci_unmap_page(pci_dev, unmap_addr, unmap_len, + PCI_DMA_TODEVICE); + } return rc; } @@ -299,8 +305,8 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue, * This removes packets from the TX queue, up to and including the * specified index. */ -static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, - unsigned int index) +static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, + unsigned int index) { struct efx_nic *efx = tx_queue->efx; unsigned int stop_index, read_ptr; @@ -320,7 +326,7 @@ static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, } efx_dequeue_buffer(tx_queue, buffer); - buffer->continuation = 1; + buffer->continuation = true; buffer->len = 0; ++tx_queue->read_count; @@ -367,8 +373,15 @@ inline int efx_xmit(struct efx_nic *efx, */ int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { - struct efx_nic *efx = net_dev->priv; - return efx_xmit(efx, &efx->tx_queue[0], skb); + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_tx_queue *tx_queue; + + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) + tx_queue = &efx->tx_queue[EFX_TX_QUEUE_OFFLOAD_CSUM]; + else + tx_queue = &efx->tx_queue[EFX_TX_QUEUE_NO_CSUM]; + + return efx_xmit(efx, tx_queue, skb); } void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) @@ -412,30 +425,25 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue) /* Allocate software ring */ txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer); tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL); - if (!tx_queue->buffer) { - rc = -ENOMEM; - goto fail1; - } + if (!tx_queue->buffer) + return -ENOMEM; for (i = 0; i <= efx->type->txd_ring_mask; ++i) - tx_queue->buffer[i].continuation = 1; + tx_queue->buffer[i].continuation = true; /* Allocate hardware ring */ rc = falcon_probe_tx(tx_queue); if (rc) - goto fail2; + goto fail; return 0; - fail2: + fail: kfree(tx_queue->buffer); tx_queue->buffer = NULL; - fail1: - tx_queue->used = 0; - return rc; } -int efx_init_tx_queue(struct efx_tx_queue *tx_queue) +void efx_init_tx_queue(struct efx_tx_queue *tx_queue) { EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue); @@ -446,7 +454,7 @@ int efx_init_tx_queue(struct efx_tx_queue *tx_queue) BUG_ON(tx_queue->stopped); /* Set up TX descriptor ring */ - return falcon_init_tx(tx_queue); + falcon_init_tx(tx_queue); } void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) @@ -461,7 +469,7 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) buffer = &tx_queue->buffer[tx_queue->read_count & tx_queue->efx->type->txd_ring_mask]; efx_dequeue_buffer(tx_queue, buffer); - buffer->continuation = 1; + buffer->continuation = true; buffer->len = 0; ++tx_queue->read_count; @@ -494,7 +502,6 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) kfree(tx_queue->buffer); tx_queue->buffer = NULL; - tx_queue->used = 0; } @@ -509,7 +516,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) /* Number of bytes inserted at the start of a TSO header buffer, * similar to NET_IP_ALIGN. */ -#if defined(__i386__) || defined(__x86_64__) +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS #define TSOH_OFFSET 0 #else #define TSOH_OFFSET NET_IP_ALIGN @@ -533,47 +540,37 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) /** * struct tso_state - TSO state for an SKB - * @remaining_len: Bytes of data we've yet to segment + * @out_len: Remaining length in current segment * @seqnum: Current sequence number + * @ipv4_id: Current IPv4 ID, host endian * @packet_space: Remaining space in current packet - * @ifc: Input fragment cursor. - * Where we are in the current fragment of the incoming SKB. These - * values get updated in place when we split a fragment over - * multiple packets. - * @p: Parameters. - * These values are set once at the start of the TSO send and do - * not get changed as the routine progresses. + * @dma_addr: DMA address of current position + * @in_len: Remaining length in current SKB fragment + * @unmap_len: Length of SKB fragment + * @unmap_addr: DMA address of SKB fragment + * @unmap_single: DMA single vs page mapping flag + * @header_len: Number of bytes of header + * @full_packet_size: Number of bytes to put in each outgoing segment * * The state used during segmentation. It is put into this data structure * just to make it easy to pass into inline functions. */ struct tso_state { - unsigned remaining_len; + /* Output position */ + unsigned out_len; unsigned seqnum; + unsigned ipv4_id; unsigned packet_space; - struct { - /* DMA address of current position */ - dma_addr_t dma_addr; - /* Remaining length */ - unsigned int len; - /* DMA address and length of the whole fragment */ - unsigned int unmap_len; - dma_addr_t unmap_addr; - struct page *page; - unsigned page_off; - } ifc; - - struct { - /* The number of bytes of header */ - unsigned int header_length; - - /* The number of bytes to put in each outgoing segment. */ - int full_packet_size; - - /* Current IPv4 ID, host endian. */ - unsigned ipv4_id; - } p; + /* Input position */ + dma_addr_t dma_addr; + unsigned in_len; + unsigned unmap_len; + dma_addr_t unmap_addr; + bool unmap_single; + + unsigned header_len; + int full_packet_size; }; @@ -581,11 +578,24 @@ struct tso_state { * Verify that our various assumptions about sk_buffs and the conditions * under which TSO will be attempted hold true. */ -static inline void efx_tso_check_safe(const struct sk_buff *skb) +static void efx_tso_check_safe(struct sk_buff *skb) { - EFX_BUG_ON_PARANOID(skb->protocol != htons(ETH_P_IP)); + __be16 protocol = skb->protocol; + EFX_BUG_ON_PARANOID(((struct ethhdr *)skb->data)->h_proto != - skb->protocol); + protocol); + if (protocol == htons(ETH_P_8021Q)) { + /* Find the encapsulated protocol; reset network header + * and transport header based on that. */ + struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; + protocol = veh->h_vlan_encapsulated_proto; + skb_set_network_header(skb, sizeof(*veh)); + if (protocol == htons(ETH_P_IP)) + skb_set_transport_header(skb, sizeof(*veh) + + 4 * ip_hdr(skb)->ihl); + } + + EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IP)); EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data) + (tcp_hdr(skb)->doff << 2u)) > @@ -685,18 +695,14 @@ efx_tsoh_heap_free(struct efx_tx_queue *tx_queue, struct efx_tso_header *tsoh) * @tx_queue: Efx TX queue * @dma_addr: DMA address of fragment * @len: Length of fragment - * @skb: Only non-null for end of last segment - * @end_of_packet: True if last fragment in a packet - * @unmap_addr: DMA address of fragment for unmapping - * @unmap_len: Only set this in last segment of a fragment + * @final_buffer: The final buffer inserted into the queue * * Push descriptors onto the TX queue. Return 0 on success or 1 if * @tx_queue full. */ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, dma_addr_t dma_addr, unsigned len, - const struct sk_buff *skb, int end_of_packet, - dma_addr_t unmap_addr, unsigned unmap_len) + struct efx_tx_buffer **final_buffer) { struct efx_tx_buffer *buffer; struct efx_nic *efx = tx_queue->efx; @@ -724,8 +730,10 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, fill_level = (tx_queue->insert_count - tx_queue->old_read_count); q_space = efx->type->txd_ring_mask - 1 - fill_level; - if (unlikely(q_space-- <= 0)) + if (unlikely(q_space-- <= 0)) { + *final_buffer = NULL; return 1; + } smp_mb(); --tx_queue->stopped; } @@ -742,7 +750,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, EFX_BUG_ON_PARANOID(buffer->len); EFX_BUG_ON_PARANOID(buffer->unmap_len); EFX_BUG_ON_PARANOID(buffer->skb); - EFX_BUG_ON_PARANOID(buffer->continuation != 1); + EFX_BUG_ON_PARANOID(!buffer->continuation); EFX_BUG_ON_PARANOID(buffer->tsoh); buffer->dma_addr = dma_addr; @@ -765,10 +773,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, EFX_BUG_ON_PARANOID(!len); buffer->len = len; - buffer->skb = skb; - buffer->continuation = !end_of_packet; - buffer->unmap_addr = unmap_addr; - buffer->unmap_len = unmap_len; + *final_buffer = buffer; return 0; } @@ -780,8 +785,8 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, * a single fragment, and we know it doesn't cross a page boundary. It * also allows us to not worry about end-of-packet etc. */ -static inline void efx_tso_put_header(struct efx_tx_queue *tx_queue, - struct efx_tso_header *tsoh, unsigned len) +static void efx_tso_put_header(struct efx_tx_queue *tx_queue, + struct efx_tso_header *tsoh, unsigned len) { struct efx_tx_buffer *buffer; @@ -791,7 +796,7 @@ static inline void efx_tso_put_header(struct efx_tx_queue *tx_queue, EFX_BUG_ON_PARANOID(buffer->len); EFX_BUG_ON_PARANOID(buffer->unmap_len); EFX_BUG_ON_PARANOID(buffer->skb); - EFX_BUG_ON_PARANOID(buffer->continuation != 1); + EFX_BUG_ON_PARANOID(!buffer->continuation); EFX_BUG_ON_PARANOID(buffer->tsoh); buffer->len = len; buffer->dma_addr = tsoh->dma_addr; @@ -805,6 +810,7 @@ static inline void efx_tso_put_header(struct efx_tx_queue *tx_queue, static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) { struct efx_tx_buffer *buffer; + dma_addr_t unmap_addr; /* Work backwards until we hit the original insert pointer value */ while (tx_queue->insert_count != tx_queue->write_count) { @@ -814,11 +820,18 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) efx_tsoh_free(tx_queue, buffer); EFX_BUG_ON_PARANOID(buffer->skb); buffer->len = 0; - buffer->continuation = 1; + buffer->continuation = true; if (buffer->unmap_len) { - pci_unmap_page(tx_queue->efx->pci_dev, - buffer->unmap_addr, - buffer->unmap_len, PCI_DMA_TODEVICE); + unmap_addr = (buffer->dma_addr + buffer->len - + buffer->unmap_len); + if (buffer->unmap_single) + pci_unmap_single(tx_queue->efx->pci_dev, + unmap_addr, buffer->unmap_len, + PCI_DMA_TODEVICE); + else + pci_unmap_page(tx_queue->efx->pci_dev, + unmap_addr, buffer->unmap_len, + PCI_DMA_TODEVICE); buffer->unmap_len = 0; } } @@ -826,50 +839,57 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) /* Parse the SKB header and initialise state. */ -static inline void tso_start(struct tso_state *st, const struct sk_buff *skb) +static void tso_start(struct tso_state *st, const struct sk_buff *skb) { /* All ethernet/IP/TCP headers combined size is TCP header size * plus offset of TCP header relative to start of packet. */ - st->p.header_length = ((tcp_hdr(skb)->doff << 2u) - + PTR_DIFF(tcp_hdr(skb), skb->data)); - st->p.full_packet_size = (st->p.header_length - + skb_shinfo(skb)->gso_size); + st->header_len = ((tcp_hdr(skb)->doff << 2u) + + PTR_DIFF(tcp_hdr(skb), skb->data)); + st->full_packet_size = st->header_len + skb_shinfo(skb)->gso_size; - st->p.ipv4_id = ntohs(ip_hdr(skb)->id); + st->ipv4_id = ntohs(ip_hdr(skb)->id); st->seqnum = ntohl(tcp_hdr(skb)->seq); EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg); EFX_BUG_ON_PARANOID(tcp_hdr(skb)->syn); EFX_BUG_ON_PARANOID(tcp_hdr(skb)->rst); - st->packet_space = st->p.full_packet_size; - st->remaining_len = skb->len - st->p.header_length; + st->packet_space = st->full_packet_size; + st->out_len = skb->len - st->header_len; + st->unmap_len = 0; + st->unmap_single = false; } - -/** - * tso_get_fragment - record fragment details and map for DMA - * @st: TSO state - * @efx: Efx NIC - * @data: Pointer to fragment data - * @len: Length of fragment - * - * Record fragment details and map for DMA. Return 0 on success, or - * -%ENOMEM if DMA mapping fails. - */ -static inline int tso_get_fragment(struct tso_state *st, struct efx_nic *efx, - int len, struct page *page, int page_off) +static int tso_get_fragment(struct tso_state *st, struct efx_nic *efx, + skb_frag_t *frag) { + st->unmap_addr = pci_map_page(efx->pci_dev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + if (likely(!pci_dma_mapping_error(efx->pci_dev, st->unmap_addr))) { + st->unmap_single = false; + st->unmap_len = frag->size; + st->in_len = frag->size; + st->dma_addr = st->unmap_addr; + return 0; + } + return -ENOMEM; +} - st->ifc.unmap_addr = pci_map_page(efx->pci_dev, page, page_off, - len, PCI_DMA_TODEVICE); - if (likely(!pci_dma_mapping_error(efx->pci_dev, st->ifc.unmap_addr))) { - st->ifc.unmap_len = len; - st->ifc.len = len; - st->ifc.dma_addr = st->ifc.unmap_addr; - st->ifc.page = page; - st->ifc.page_off = page_off; +static int tso_get_head_fragment(struct tso_state *st, struct efx_nic *efx, + const struct sk_buff *skb) +{ + int hl = st->header_len; + int len = skb_headlen(skb) - hl; + + st->unmap_addr = pci_map_single(efx->pci_dev, skb->data + hl, + len, PCI_DMA_TODEVICE); + if (likely(!pci_dma_mapping_error(efx->pci_dev, st->unmap_addr))) { + st->unmap_single = true; + st->unmap_len = len; + st->in_len = len; + st->dma_addr = st->unmap_addr; return 0; } return -ENOMEM; @@ -886,36 +906,45 @@ static inline int tso_get_fragment(struct tso_state *st, struct efx_nic *efx, * of fragment or end-of-packet. Return 0 on success, 1 if not enough * space in @tx_queue. */ -static inline int tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue, - const struct sk_buff *skb, - struct tso_state *st) +static int tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue, + const struct sk_buff *skb, + struct tso_state *st) { - + struct efx_tx_buffer *buffer; int n, end_of_packet, rc; - if (st->ifc.len == 0) + if (st->in_len == 0) return 0; if (st->packet_space == 0) return 0; - EFX_BUG_ON_PARANOID(st->ifc.len <= 0); + EFX_BUG_ON_PARANOID(st->in_len <= 0); EFX_BUG_ON_PARANOID(st->packet_space <= 0); - n = min(st->ifc.len, st->packet_space); + n = min(st->in_len, st->packet_space); st->packet_space -= n; - st->remaining_len -= n; - st->ifc.len -= n; - st->ifc.page_off += n; - end_of_packet = st->remaining_len == 0 || st->packet_space == 0; - - rc = efx_tx_queue_insert(tx_queue, st->ifc.dma_addr, n, - st->remaining_len ? NULL : skb, - end_of_packet, st->ifc.unmap_addr, - st->ifc.len ? 0 : st->ifc.unmap_len); - - st->ifc.dma_addr += n; + st->out_len -= n; + st->in_len -= n; + + rc = efx_tx_queue_insert(tx_queue, st->dma_addr, n, &buffer); + if (likely(rc == 0)) { + if (st->out_len == 0) + /* Transfer ownership of the skb */ + buffer->skb = skb; + + end_of_packet = st->out_len == 0 || st->packet_space == 0; + buffer->continuation = !end_of_packet; + + if (st->in_len == 0) { + /* Transfer ownership of the pci mapping */ + buffer->unmap_len = st->unmap_len; + buffer->unmap_single = st->unmap_single; + st->unmap_len = 0; + } + } + st->dma_addr += n; return rc; } @@ -929,9 +958,9 @@ static inline int tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue, * Generate a new header and prepare for the new packet. Return 0 on * success, or -1 if failed to alloc header. */ -static inline int tso_start_new_packet(struct efx_tx_queue *tx_queue, - const struct sk_buff *skb, - struct tso_state *st) +static int tso_start_new_packet(struct efx_tx_queue *tx_queue, + const struct sk_buff *skb, + struct tso_state *st) { struct efx_tso_header *tsoh; struct iphdr *tsoh_iph; @@ -940,7 +969,7 @@ static inline int tso_start_new_packet(struct efx_tx_queue *tx_queue, u8 *header; /* Allocate a DMA-mapped header buffer. */ - if (likely(TSOH_SIZE(st->p.header_length) <= TSOH_STD_SIZE)) { + if (likely(TSOH_SIZE(st->header_len) <= TSOH_STD_SIZE)) { if (tx_queue->tso_headers_free == NULL) { if (efx_tsoh_block_alloc(tx_queue)) return -1; @@ -951,7 +980,7 @@ static inline int tso_start_new_packet(struct efx_tx_queue *tx_queue, tsoh->unmap_len = 0; } else { tx_queue->tso_long_headers++; - tsoh = efx_tsoh_heap_alloc(tx_queue, st->p.header_length); + tsoh = efx_tsoh_heap_alloc(tx_queue, st->header_len); if (unlikely(!tsoh)) return -1; } @@ -961,33 +990,32 @@ static inline int tso_start_new_packet(struct efx_tx_queue *tx_queue, tsoh_iph = (struct iphdr *)(header + SKB_IPV4_OFF(skb)); /* Copy and update the headers. */ - memcpy(header, skb->data, st->p.header_length); + memcpy(header, skb->data, st->header_len); tsoh_th->seq = htonl(st->seqnum); st->seqnum += skb_shinfo(skb)->gso_size; - if (st->remaining_len > skb_shinfo(skb)->gso_size) { + if (st->out_len > skb_shinfo(skb)->gso_size) { /* This packet will not finish the TSO burst. */ - ip_length = st->p.full_packet_size - ETH_HDR_LEN(skb); + ip_length = st->full_packet_size - ETH_HDR_LEN(skb); tsoh_th->fin = 0; tsoh_th->psh = 0; } else { /* This packet will be the last in the TSO burst. */ - ip_length = (st->p.header_length - ETH_HDR_LEN(skb) - + st->remaining_len); + ip_length = st->header_len - ETH_HDR_LEN(skb) + st->out_len; tsoh_th->fin = tcp_hdr(skb)->fin; tsoh_th->psh = tcp_hdr(skb)->psh; } tsoh_iph->tot_len = htons(ip_length); /* Linux leaves suitable gaps in the IP ID space for us to fill. */ - tsoh_iph->id = htons(st->p.ipv4_id); - st->p.ipv4_id++; + tsoh_iph->id = htons(st->ipv4_id); + st->ipv4_id++; st->packet_space = skb_shinfo(skb)->gso_size; ++tx_queue->tso_packets; /* Form a descriptor for this header. */ - efx_tso_put_header(tx_queue, tsoh, st->p.header_length); + efx_tso_put_header(tx_queue, tsoh, st->header_len); return 0; } @@ -1005,11 +1033,11 @@ static inline int tso_start_new_packet(struct efx_tx_queue *tx_queue, * %NETDEV_TX_OK or %NETDEV_TX_BUSY. */ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, - const struct sk_buff *skb) + struct sk_buff *skb) { + struct efx_nic *efx = tx_queue->efx; int frag_i, rc, rc2 = NETDEV_TX_OK; struct tso_state state; - skb_frag_t *f; /* Verify TSO is safe - these checks should never fail. */ efx_tso_check_safe(skb); @@ -1021,29 +1049,16 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, /* Assume that skb header area contains exactly the headers, and * all payload is in the frag list. */ - if (skb_headlen(skb) == state.p.header_length) { + if (skb_headlen(skb) == state.header_len) { /* Grab the first payload fragment. */ EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags < 1); frag_i = 0; - f = &skb_shinfo(skb)->frags[frag_i]; - rc = tso_get_fragment(&state, tx_queue->efx, - f->size, f->page, f->page_offset); + rc = tso_get_fragment(&state, efx, + skb_shinfo(skb)->frags + frag_i); if (rc) goto mem_err; } else { - /* It may look like this code fragment assumes that the - * skb->data portion does not cross a page boundary, but - * that is not the case. It is guaranteed to be direct - * mapped memory, and therefore is physically contiguous, - * and so DMA will work fine. kmap_atomic() on this region - * will just return the direct mapping, so that will work - * too. - */ - int page_off = (unsigned long)skb->data & (PAGE_SIZE - 1); - int hl = state.p.header_length; - rc = tso_get_fragment(&state, tx_queue->efx, - skb_headlen(skb) - hl, - virt_to_page(skb->data), page_off + hl); + rc = tso_get_head_fragment(&state, efx, skb); if (rc) goto mem_err; frag_i = -1; @@ -1058,13 +1073,12 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, goto stop; /* Move onto the next fragment? */ - if (state.ifc.len == 0) { + if (state.in_len == 0) { if (++frag_i >= skb_shinfo(skb)->nr_frags) /* End of payload reached. */ break; - f = &skb_shinfo(skb)->frags[frag_i]; - rc = tso_get_fragment(&state, tx_queue->efx, - f->size, f->page, f->page_offset); + rc = tso_get_fragment(&state, efx, + skb_shinfo(skb)->frags + frag_i); if (rc) goto mem_err; } @@ -1082,8 +1096,7 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, return NETDEV_TX_OK; mem_err: - EFX_ERR(tx_queue->efx, "Out of memory for TSO headers, or PCI mapping" - " error\n"); + EFX_ERR(efx, "Out of memory for TSO headers, or PCI mapping error\n"); dev_kfree_skb_any((struct sk_buff *)skb); goto unwind; @@ -1092,9 +1105,19 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, /* Stop the queue if it wasn't stopped before. */ if (tx_queue->stopped == 1) - efx_stop_queue(tx_queue->efx); + efx_stop_queue(efx); unwind: + /* Free the DMA mapping we were in the process of writing out */ + if (state.unmap_len) { + if (state.unmap_single) + pci_unmap_single(efx->pci_dev, state.unmap_addr, + state.unmap_len, PCI_DMA_TODEVICE); + else + pci_unmap_page(efx->pci_dev, state.unmap_addr, + state.unmap_len, PCI_DMA_TODEVICE); + } + efx_enqueue_unwind(tx_queue); return rc2; } diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h index 1526a73b4b5..5e1cc234e42 100644 --- a/drivers/net/sfc/tx.h +++ b/drivers/net/sfc/tx.h @@ -15,7 +15,7 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); -int efx_init_tx_queue(struct efx_tx_queue *tx_queue); +void efx_init_tx_queue(struct efx_tx_queue *tx_queue); void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index 35ab19c27f8..fa7b49d6928 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -20,14 +20,10 @@ /* XAUI resets if link not detected */ #define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS -/* SNAP frames have TOBE_DISC set */ -#define EFX_WORKAROUND_5475 EFX_WORKAROUND_ALWAYS /* RX PCIe double split performance issue */ #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS /* TX pkt parser problem with <= 16 byte TXes */ #define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS -/* XGXS and XAUI reset sequencing in SW */ -#define EFX_WORKAROUND_9388 EFX_WORKAROUND_ALWAYS /* Low rate CRC errors require XAUI reset */ #define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index f3684ad2888..276151df3a7 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c @@ -40,7 +40,7 @@ void xfp_set_led(struct efx_nic *p, int led, int mode) } struct xfp_phy_data { - int tx_disabled; + enum efx_phy_mode phy_mode; }; #define XFP_MAX_RESET_TIME 500 @@ -93,7 +93,7 @@ static int xfp_phy_init(struct efx_nic *efx) " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid), MDIO_ID_REV(devid)); - phy_data->tx_disabled = efx->tx_disabled; + phy_data->phy_mode = efx->phy_mode; rc = xfp_reset_phy(efx); @@ -136,13 +136,14 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) struct xfp_phy_data *phy_data = efx->phy_data; /* Reset the PHY when moving from tx off to tx on */ - if (phy_data->tx_disabled && !efx->tx_disabled) + if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) && + (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) xfp_reset_phy(efx); mdio_clause45_transmit_disable(efx); mdio_clause45_phy_reconfigure(efx); - phy_data->tx_disabled = efx->tx_disabled; + phy_data->phy_mode = efx->phy_mode; efx->link_up = xfp_link_ok(efx); efx->link_options = GM_LPA_10000FULL; } @@ -151,7 +152,7 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) static void xfp_phy_fini(struct efx_nic *efx) { /* Clobber the LED if it was blinking */ - efx->board_info.blink(efx, 0); + efx->board_info.blink(efx, false); /* Free the context block */ kfree(efx->phy_data); @@ -164,7 +165,6 @@ struct efx_phy_operations falcon_xfp_phy_ops = { .check_hw = xfp_phy_check_hw, .fini = xfp_phy_fini, .clear_interrupt = xfp_phy_clear_interrupt, - .reset_xaui = efx_port_dummy_op_void, .mmds = XFP_REQUIRED_DEVS, .loopbacks = XFP_LOOPBACKS, }; diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 1a04814291c..a24bb68887a 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1140,7 +1140,7 @@ static int sh_mdio_init(struct net_device *ndev, int id) /* Hook up MII support for ethtool */ mdp->mii_bus->name = "sh_mii"; - mdp->mii_bus->dev = &ndev->dev; + mdp->mii_bus->parent = &ndev->dev; mdp->mii_bus->id[0] = id; /* PHY IRQ */ @@ -1166,7 +1166,7 @@ out_free_irq: kfree(mdp->mii_bus->irq); out_free_bus: - kfree(mdp->mii_bus); + free_mdio_bitbang(mdp->mii_bus); out_free_bitbang: kfree(bitbang); diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c index ea85de91823..79e665e0853 100644 --- a/drivers/net/skfp/pmf.c +++ b/drivers/net/skfp/pmf.c @@ -44,17 +44,10 @@ static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req, int set, int local); static int port_to_mib(struct s_smc *smc, int p); -#define MOFFSS(e) ((int)&(((struct fddi_mib *)0)->e)) -#define MOFFSA(e) ((int) (((struct fddi_mib *)0)->e)) - -#define MOFFMS(e) ((int)&(((struct fddi_mib_m *)0)->e)) -#define MOFFMA(e) ((int) (((struct fddi_mib_m *)0)->e)) - -#define MOFFAS(e) ((int)&(((struct fddi_mib_a *)0)->e)) -#define MOFFAA(e) ((int) (((struct fddi_mib_a *)0)->e)) - -#define MOFFPS(e) ((int)&(((struct fddi_mib_p *)0)->e)) -#define MOFFPA(e) ((int) (((struct fddi_mib_p *)0)->e)) +#define MOFFSS(e) offsetof(struct fddi_mib, e) +#define MOFFMS(e) offsetof(struct fddi_mib_m, e) +#define MOFFAS(e) offsetof(struct fddi_mib_a, e) +#define MOFFPS(e) offsetof(struct fddi_mib_p, e) #define AC_G 0x01 /* Get */ @@ -87,8 +80,8 @@ static const struct s_p_tab { { SMT_P100D,AC_G, MOFFSS(fddiSMTOpVersionId), "S" } , { SMT_P100E,AC_G, MOFFSS(fddiSMTHiVersionId), "S" } , { SMT_P100F,AC_G, MOFFSS(fddiSMTLoVersionId), "S" } , - { SMT_P1010,AC_G, MOFFSA(fddiSMTManufacturerData), "D" } , - { SMT_P1011,AC_GR, MOFFSA(fddiSMTUserData), "D" } , + { SMT_P1010,AC_G, MOFFSS(fddiSMTManufacturerData), "D" } , + { SMT_P1011,AC_GR, MOFFSS(fddiSMTUserData), "D" } , { SMT_P1012,AC_G, MOFFSS(fddiSMTMIBVersionId), "S" } , /* StationConfigGrp */ @@ -103,7 +96,7 @@ static const struct s_p_tab { { SMT_P101D,AC_GR, MOFFSS(fddiSMTTT_Notify), "wS" } , { SMT_P101E,AC_GR, MOFFSS(fddiSMTStatRptPolicy), "bB" } , { SMT_P101F,AC_GR, MOFFSS(fddiSMTTrace_MaxExpiration),"lL" } , - { SMT_P1020,AC_G, MOFFSA(fddiSMTPORTIndexes), "II" } , + { SMT_P1020,AC_G, MOFFSS(fddiSMTPORTIndexes), "II" } , { SMT_P1021,AC_G, MOFFSS(fddiSMTMACIndexes), "I" } , { SMT_P1022,AC_G, MOFFSS(fddiSMTBypassPresent), "F" } , @@ -117,8 +110,8 @@ static const struct s_p_tab { /* MIBOperationGrp */ { SMT_P1032,AC_GROUP } , - { SMT_P1033,AC_G, MOFFSA(fddiSMTTimeStamp),"P" } , - { SMT_P1034,AC_G, MOFFSA(fddiSMTTransitionTimeStamp),"P" } , + { SMT_P1033,AC_G, MOFFSS(fddiSMTTimeStamp),"P" } , + { SMT_P1034,AC_G, MOFFSS(fddiSMTTransitionTimeStamp),"P" } , /* NOTE : SMT_P1035 is already swapped ! SMT_P_SETCOUNT */ { SMT_P1035,AC_G, MOFFSS(fddiSMTSetCount),"4P" } , { SMT_P1036,AC_G, MOFFSS(fddiSMTLastSetStationId),"8" } , @@ -129,7 +122,7 @@ static const struct s_p_tab { * PRIVATE EXTENSIONS * only accessible locally to get/set passwd */ - { SMT_P10F0,AC_GR, MOFFSA(fddiPRPMFPasswd), "8" } , + { SMT_P10F0,AC_GR, MOFFSS(fddiPRPMFPasswd), "8" } , { SMT_P10F1,AC_GR, MOFFSS(fddiPRPMFStation), "8" } , #ifdef ESS { SMT_P10F2,AC_GR, MOFFSS(fddiESSPayload), "lL" } , @@ -245,7 +238,7 @@ static const struct s_p_tab { { SMT_P400E,AC_GR, MOFFPS(fddiPORTConnectionPolicies),"bB" } , { SMT_P400F,AC_G, MOFFPS(fddiPORTMacIndicated), "2" } , { SMT_P4010,AC_G, MOFFPS(fddiPORTCurrentPath), "E" } , - { SMT_P4011,AC_GR, MOFFPA(fddiPORTRequestedPaths), "l4" } , + { SMT_P4011,AC_GR, MOFFPS(fddiPORTRequestedPaths), "l4" } , { SMT_P4012,AC_G, MOFFPS(fddiPORTMACPlacement), "S" } , { SMT_P4013,AC_G, MOFFPS(fddiPORTAvailablePaths), "B" } , { SMT_P4016,AC_G, MOFFPS(fddiPORTPMDClass), "E" } , diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 2e26dced13a..43f4c730be4 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -319,6 +319,7 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) struct skge_port *skge = netdev_priv(dev); const struct skge_hw *hw = skge->hw; u32 supported = skge_supported_modes(hw); + int err = 0; if (ecmd->autoneg == AUTONEG_ENABLE) { ecmd->advertising = supported; @@ -367,8 +368,14 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) skge->autoneg = ecmd->autoneg; skge->advertising = ecmd->advertising; - if (netif_running(dev)) - skge_phy_reset(skge); + if (netif_running(dev)) { + skge_down(dev); + err = skge_up(dev); + if (err) { + dev_close(dev); + return err; + } + } return (0); } @@ -494,7 +501,7 @@ static int skge_set_ring_param(struct net_device *dev, struct ethtool_ringparam *p) { struct skge_port *skge = netdev_priv(dev); - int err; + int err = 0; if (p->rx_pending == 0 || p->rx_pending > MAX_RX_RING_SIZE || p->tx_pending < TX_LOW_WATER || p->tx_pending > MAX_TX_RING_SIZE) @@ -510,7 +517,7 @@ static int skge_set_ring_param(struct net_device *dev, dev_close(dev); } - return 0; + return err; } static u32 skge_get_msglevel(struct net_device *netdev) @@ -593,6 +600,7 @@ static int skge_set_pauseparam(struct net_device *dev, { struct skge_port *skge = netdev_priv(dev); struct ethtool_pauseparam old; + int err = 0; skge_get_pauseparam(dev, &old); @@ -609,8 +617,14 @@ static int skge_set_pauseparam(struct net_device *dev, skge->flow_control = FLOW_MODE_NONE; } - if (netif_running(dev)) - skge_phy_reset(skge); + if (netif_running(dev)) { + skge_down(dev); + err = skge_up(dev); + if (err) { + dev_close(dev); + return err; + } + } return 0; } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index e24b25ca1c6..3813d15e2df 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3034,7 +3034,8 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; - if (wol->wolopts & ~sky2_wol_supported(sky2->hw)) + if ((wol->wolopts & ~sky2_wol_supported(sky2->hw)) + || !device_can_wakeup(&hw->pdev->dev)) return -EOPNOTSUPP; sky2->wol = wol->wolopts; @@ -3045,6 +3046,8 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) sky2_write32(hw, B0_CTST, sky2->wol ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF); + device_set_wakeup_enable(&hw->pdev->dev, sky2->wol); + if (!netif_running(dev)) sky2_wol_init(sky2); return 0; @@ -3732,27 +3735,63 @@ static int sky2_get_eeprom_len(struct net_device *dev) return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8); } -static u32 sky2_vpd_read(struct sky2_hw *hw, int cap, u16 offset) +static int sky2_vpd_wait(const struct sky2_hw *hw, int cap, u16 busy) { - u32 val; + unsigned long start = jiffies; - sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset); + while ( (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F) == busy) { + /* Can take up to 10.6 ms for write */ + if (time_after(jiffies, start + HZ/4)) { + dev_err(&hw->pdev->dev, PFX "VPD cycle timed out"); + return -ETIMEDOUT; + } + mdelay(1); + } - do { - offset = sky2_pci_read16(hw, cap + PCI_VPD_ADDR); - } while (!(offset & PCI_VPD_ADDR_F)); + return 0; +} + +static int sky2_vpd_read(struct sky2_hw *hw, int cap, void *data, + u16 offset, size_t length) +{ + int rc = 0; + + while (length > 0) { + u32 val; + + sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset); + rc = sky2_vpd_wait(hw, cap, 0); + if (rc) + break; + + val = sky2_pci_read32(hw, cap + PCI_VPD_DATA); + + memcpy(data, &val, min(sizeof(val), length)); + offset += sizeof(u32); + data += sizeof(u32); + length -= sizeof(u32); + } - val = sky2_pci_read32(hw, cap + PCI_VPD_DATA); - return val; + return rc; } -static void sky2_vpd_write(struct sky2_hw *hw, int cap, u16 offset, u32 val) +static int sky2_vpd_write(struct sky2_hw *hw, int cap, const void *data, + u16 offset, unsigned int length) { - sky2_pci_write16(hw, cap + PCI_VPD_DATA, val); - sky2_pci_write32(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F); - do { - offset = sky2_pci_read16(hw, cap + PCI_VPD_ADDR); - } while (offset & PCI_VPD_ADDR_F); + unsigned int i; + int rc = 0; + + for (i = 0; i < length; i += sizeof(u32)) { + u32 val = *(u32 *)(data + i); + + sky2_pci_write32(hw, cap + PCI_VPD_DATA, val); + sky2_pci_write32(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F); + + rc = sky2_vpd_wait(hw, cap, PCI_VPD_ADDR_F); + if (rc) + break; + } + return rc; } static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, @@ -3760,24 +3799,13 @@ static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom { struct sky2_port *sky2 = netdev_priv(dev); int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD); - int length = eeprom->len; - u16 offset = eeprom->offset; if (!cap) return -EINVAL; eeprom->magic = SKY2_EEPROM_MAGIC; - while (length > 0) { - u32 val = sky2_vpd_read(sky2->hw, cap, offset); - int n = min_t(int, length, sizeof(val)); - - memcpy(data, &val, n); - length -= n; - data += n; - offset += n; - } - return 0; + return sky2_vpd_read(sky2->hw, cap, data, eeprom->offset, eeprom->len); } static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, @@ -3785,8 +3813,6 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom { struct sky2_port *sky2 = netdev_priv(dev); int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD); - int length = eeprom->len; - u16 offset = eeprom->offset; if (!cap) return -EINVAL; @@ -3794,21 +3820,11 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom if (eeprom->magic != SKY2_EEPROM_MAGIC) return -EINVAL; - while (length > 0) { - u32 val; - int n = min_t(int, length, sizeof(val)); - - if (n < sizeof(val)) - val = sky2_vpd_read(sky2->hw, cap, offset); - memcpy(&val, data, n); - - sky2_vpd_write(sky2->hw, cap, offset, val); + /* Partial writes not supported */ + if ((eeprom->offset & 3) || (eeprom->len & 3)) + return -EINVAL; - length -= n; - data += n; - offset += n; - } - return 0; + return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len); } @@ -4166,16 +4182,67 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) return err; } -static int __devinit pci_wake_enabled(struct pci_dev *dev) +/* + * Read and parse the first part of Vital Product Data + */ +#define VPD_SIZE 128 +#define VPD_MAGIC 0x82 + +static void __devinit sky2_vpd_info(struct sky2_hw *hw) { - int pm = pci_find_capability(dev, PCI_CAP_ID_PM); - u16 value; + int cap = pci_find_capability(hw->pdev, PCI_CAP_ID_VPD); + const u8 *p; + u8 *vpd_buf = NULL; + u16 len; + static struct vpd_tag { + char tag[2]; + char *label; + } vpd_tags[] = { + { "PN", "Part Number" }, + { "EC", "Engineering Level" }, + { "MN", "Manufacturer" }, + }; - if (!pm) - return 0; - if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value)) - return 0; - return value & PCI_PM_CTRL_PME_ENABLE; + if (!cap) + goto out; + + vpd_buf = kmalloc(VPD_SIZE, GFP_KERNEL); + if (!vpd_buf) + goto out; + + if (sky2_vpd_read(hw, cap, vpd_buf, 0, VPD_SIZE)) + goto out; + + if (vpd_buf[0] != VPD_MAGIC) + goto out; + len = vpd_buf[1]; + if (len == 0 || len > VPD_SIZE - 4) + goto out; + p = vpd_buf + 3; + dev_info(&hw->pdev->dev, "%.*s\n", len, p); + p += len; + + while (p < vpd_buf + VPD_SIZE - 4) { + int i; + + if (!memcmp("RW", p, 2)) /* end marker */ + break; + + len = p[2]; + if (len > (p - vpd_buf) - 4) + break; + + for (i = 0; i < ARRAY_SIZE(vpd_tags); i++) { + if (!memcmp(vpd_tags[i].tag, p, 2)) { + printk(KERN_DEBUG " %s: %.*s\n", + vpd_tags[i].label, len, p + 3); + break; + } + } + p += len + 3; + } +out: + kfree(vpd_buf); } /* This driver supports yukon2 chipset only */ @@ -4238,7 +4305,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, } } - wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0; + wol_default = device_may_wakeup(&pdev->dev) ? WAKE_MAGIC : 0; err = -ENOMEM; hw = kzalloc(sizeof(*hw), GFP_KERNEL); @@ -4276,13 +4343,13 @@ static int __devinit sky2_probe(struct pci_dev *pdev, if (err) goto err_out_iounmap; - dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-2 %s rev %d\n", - DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0), - pdev->irq, sky2_name(hw->chip_id, buf1, sizeof(buf1)), - hw->chip_rev); + dev_info(&pdev->dev, "Yukon-2 %s chip revision %d\n", + sky2_name(hw->chip_id, buf1, sizeof(buf1)), hw->chip_rev); sky2_reset(hw); + sky2_vpd_info(hw); + dev = sky2_init_netdev(hw, 0, using_dac, wol_default); if (!dev) { err = -ENOMEM; @@ -4533,6 +4600,8 @@ static struct pci_driver sky2_driver = { static int __init sky2_init_module(void) { + pr_info(PFX "driver version " DRV_VERSION "\n"); + sky2_debug_init(); return pci_register_driver(&sky2_driver); } diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index c5871624f97..8aa7460ef0e 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -183,7 +183,7 @@ static void smc911x_reset(struct net_device *dev) unsigned int reg, timeout=0, resets=1; unsigned long flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); /* Take out of PM setting first */ if ((SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_) == 0) { @@ -272,7 +272,7 @@ static void smc911x_enable(struct net_device *dev) unsigned mask, cfg, cr; unsigned long flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); SMC_SET_MAC_ADDR(lp, dev->dev_addr); @@ -329,7 +329,7 @@ static void smc911x_shutdown(struct net_device *dev) unsigned cr; unsigned long flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __func__); /* Disable IRQ's */ SMC_SET_INT_EN(lp, 0); @@ -348,7 +348,7 @@ static inline void smc911x_drop_pkt(struct net_device *dev) struct smc911x_local *lp = netdev_priv(dev); unsigned int fifo_count, timeout, reg; - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __FUNCTION__); + DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __func__); fifo_count = SMC_GET_RX_FIFO_INF(lp) & 0xFFFF; if (fifo_count <= 4) { /* Manually dump the packet data */ @@ -382,7 +382,7 @@ static inline void smc911x_rcv(struct net_device *dev) unsigned char *data; DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", - dev->name, __FUNCTION__); + dev->name, __func__); status = SMC_GET_RX_STS_FIFO(lp); DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x \n", dev->name, (status & 0x3fff0000) >> 16, status & 0xc000ffff); @@ -460,7 +460,7 @@ static void smc911x_hardware_send_pkt(struct net_device *dev) unsigned char *buf; unsigned long flags; - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __func__); BUG_ON(lp->pending_tx_skb == NULL); skb = lp->pending_tx_skb; @@ -524,7 +524,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", - dev->name, __FUNCTION__); + dev->name, __func__); BUG_ON(lp->pending_tx_skb != NULL); @@ -596,7 +596,7 @@ static void smc911x_tx(struct net_device *dev) unsigned int tx_status; DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", - dev->name, __FUNCTION__); + dev->name, __func__); /* Collect the TX status */ while (((SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16) != 0) { @@ -647,7 +647,7 @@ static int smc911x_phy_read(struct net_device *dev, int phyaddr, int phyreg) SMC_GET_MII(lp, phyreg, phyaddr, phydata); DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%02x, phydata=0x%04x\n", - __FUNCTION__, phyaddr, phyreg, phydata); + __func__, phyaddr, phyreg, phydata); return phydata; } @@ -661,7 +661,7 @@ static void smc911x_phy_write(struct net_device *dev, int phyaddr, int phyreg, struct smc911x_local *lp = netdev_priv(dev); DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", - __FUNCTION__, phyaddr, phyreg, phydata); + __func__, phyaddr, phyreg, phydata); SMC_SET_MII(lp, phyreg, phyaddr, phydata); } @@ -676,7 +676,7 @@ static void smc911x_phy_detect(struct net_device *dev) int phyaddr; unsigned int cfg, id1, id2; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); lp->phy_type = 0; @@ -685,8 +685,10 @@ static void smc911x_phy_detect(struct net_device *dev) * PHY#1 to PHY#31, and then PHY#0 last. */ switch(lp->version) { - case 0x115: - case 0x117: + case CHIP_9115: + case CHIP_9117: + case CHIP_9215: + case CHIP_9217: cfg = SMC_GET_HW_CFG(lp); if (cfg & HW_CFG_EXT_PHY_DET_) { cfg &= ~HW_CFG_PHY_CLK_SEL_; @@ -722,6 +724,9 @@ static void smc911x_phy_detect(struct net_device *dev) break; } } + if (phyaddr < 32) + /* Found an external PHY */ + break; } default: /* Internal media only */ @@ -746,7 +751,7 @@ static int smc911x_phy_fixed(struct net_device *dev) int phyaddr = lp->mii.phy_id; int bmcr; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); /* Enter Link Disable state */ SMC_GET_PHY_BMCR(lp, phyaddr, bmcr); @@ -793,7 +798,7 @@ static int smc911x_phy_reset(struct net_device *dev, int phy) unsigned long flags; unsigned int reg; - DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__); spin_lock_irqsave(&lp->lock, flags); reg = SMC_GET_PMT_CTRL(lp); @@ -852,7 +857,7 @@ static void smc911x_phy_check_media(struct net_device *dev, int init) int phyaddr = lp->mii.phy_id; unsigned int bmcr, cr; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { /* duplex state has changed */ @@ -892,7 +897,7 @@ static void smc911x_phy_configure(struct work_struct *work) int status; unsigned long flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__); /* * We should not be called if phy_type is zero. @@ -985,7 +990,7 @@ static void smc911x_phy_interrupt(struct net_device *dev) int phyaddr = lp->mii.phy_id; int status; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); if (lp->phy_type == 0) return; @@ -1013,7 +1018,7 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) unsigned int rx_overrun=0, cr, pkts; unsigned long flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); spin_lock_irqsave(&lp->lock, flags); @@ -1174,8 +1179,6 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) spin_unlock_irqrestore(&lp->lock, flags); - DBG(3, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout); - return IRQ_HANDLED; } @@ -1188,7 +1191,7 @@ smc911x_tx_dma_irq(int dma, void *data) struct sk_buff *skb = lp->current_tx_skb; unsigned long flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: TX DMA irq handler\n", dev->name); /* Clear the DMA interrupt sources */ @@ -1224,7 +1227,7 @@ smc911x_rx_dma_irq(int dma, void *data) unsigned long flags; unsigned int pkts; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, "%s: RX DMA irq handler\n", dev->name); /* Clear the DMA interrupt sources */ SMC_DMA_ACK_IRQ(dev, dma); @@ -1272,7 +1275,7 @@ static void smc911x_timeout(struct net_device *dev) int status, mask; unsigned long flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); spin_lock_irqsave(&lp->lock, flags); status = SMC_GET_INT(lp); @@ -1310,7 +1313,7 @@ static void smc911x_set_multicast_list(struct net_device *dev) unsigned int mcr, update_multicast = 0; unsigned long flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); spin_lock_irqsave(&lp->lock, flags); SMC_GET_MAC_CR(lp, mcr); @@ -1412,7 +1415,7 @@ smc911x_open(struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); /* * Check that the address is valid. If its not, refuse @@ -1420,7 +1423,7 @@ smc911x_open(struct net_device *dev) * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ if (!is_valid_ether_addr(dev->dev_addr)) { - PRINTK("%s: no valid ethernet hw addr\n", __FUNCTION__); + PRINTK("%s: no valid ethernet hw addr\n", __func__); return -EINVAL; } @@ -1449,7 +1452,7 @@ static int smc911x_close(struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); netif_stop_queue(dev); netif_carrier_off(dev); @@ -1483,7 +1486,7 @@ smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) int ret, status; unsigned long flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); cmd->maxtxpkt = 1; cmd->maxrxpkt = 1; @@ -1621,7 +1624,7 @@ static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev) for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) { if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) { PRINTK("%s: %s timeout waiting for EEPROM to respond\n", - dev->name, __FUNCTION__); + dev->name, __func__); return -EFAULT; } mdelay(1); @@ -1629,7 +1632,7 @@ static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev) } if (timeout == 0) { PRINTK("%s: %s timeout waiting for EEPROM CMD not busy\n", - dev->name, __FUNCTION__); + dev->name, __func__); return -ETIMEDOUT; } return 0; @@ -1742,7 +1745,7 @@ static int __init smc911x_findirq(struct net_device *dev) int timeout = 20; unsigned long cookie; - DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); cookie = probe_irq_on(); @@ -1808,7 +1811,7 @@ static int __init smc911x_probe(struct net_device *dev) const char *version_string; unsigned long irq_flags; - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); /* First, see if the endian word is recognized */ val = SMC_GET_BYTE_TEST(lp); @@ -2058,7 +2061,7 @@ static int smc911x_drv_probe(struct platform_device *pdev) unsigned int *addr; int ret; - DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENODEV; @@ -2129,7 +2132,7 @@ static int smc911x_drv_remove(struct platform_device *pdev) struct smc911x_local *lp = netdev_priv(ndev); struct resource *res; - DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); platform_set_drvdata(pdev, NULL); unregister_netdev(ndev); @@ -2159,7 +2162,7 @@ static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state) struct net_device *ndev = platform_get_drvdata(dev); struct smc911x_local *lp = netdev_priv(ndev); - DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); if (ndev) { if (netif_running(ndev)) { netif_device_detach(ndev); @@ -2177,7 +2180,7 @@ static int smc911x_drv_resume(struct platform_device *dev) { struct net_device *ndev = platform_get_drvdata(dev); - DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__); + DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); if (ndev) { struct smc911x_local *lp = netdev_priv(ndev); diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 2abfc284519..bf6240f23f5 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -666,10 +666,13 @@ smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr, #define LAN911X_INTERNAL_PHY_ID (0x0007C000) /* Chip ID values */ -#define CHIP_9115 0x115 -#define CHIP_9116 0x116 -#define CHIP_9117 0x117 -#define CHIP_9118 0x118 +#define CHIP_9115 0x0115 +#define CHIP_9116 0x0116 +#define CHIP_9117 0x0117 +#define CHIP_9118 0x0118 +#define CHIP_9215 0x115A +#define CHIP_9217 0x117A +#define CHIP_9218 0x118A struct chip_id { u16 id; @@ -681,6 +684,9 @@ static const struct chip_id chip_ids[] = { { CHIP_9116, "LAN9116" }, { CHIP_9117, "LAN9117" }, { CHIP_9118, "LAN9118" }, + { CHIP_9215, "LAN9215" }, + { CHIP_9217, "LAN9217" }, + { CHIP_9218, "LAN9218" }, { 0, NULL }, }; diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 24768c10cad..c70870e0fd6 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -270,7 +270,7 @@ static void smc_reset(struct net_device *dev) unsigned int ctl, cfg; struct sk_buff *pending_skb; - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + DBG(2, "%s: %s\n", dev->name, __func__); /* Disable all interrupts, block TX tasklet */ spin_lock_irq(&lp->lock); @@ -363,7 +363,7 @@ static void smc_enable(struct net_device *dev) void __iomem *ioaddr = lp->base; int mask; - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + DBG(2, "%s: %s\n", dev->name, __func__); /* see the header file for options in TCR/RCR DEFAULT */ SMC_SELECT_BANK(lp, 0); @@ -397,7 +397,7 @@ static void smc_shutdown(struct net_device *dev) void __iomem *ioaddr = lp->base; struct sk_buff *pending_skb; - DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); + DBG(2, "%s: %s\n", CARDNAME, __func__); /* no more interrupts for me */ spin_lock_irq(&lp->lock); @@ -430,7 +430,7 @@ static inline void smc_rcv(struct net_device *dev) void __iomem *ioaddr = lp->base; unsigned int packet_number, status, packet_len; - DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + DBG(3, "%s: %s\n", dev->name, __func__); packet_number = SMC_GET_RXFIFO(lp); if (unlikely(packet_number & RXFIFO_REMPTY)) { @@ -577,7 +577,7 @@ static void smc_hardware_send_pkt(unsigned long data) unsigned int packet_no, len; unsigned char *buf; - DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + DBG(3, "%s: %s\n", dev->name, __func__); if (!smc_special_trylock(&lp->lock)) { netif_stop_queue(dev); @@ -662,7 +662,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) void __iomem *ioaddr = lp->base; unsigned int numPages, poll_count, status; - DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + DBG(3, "%s: %s\n", dev->name, __func__); BUG_ON(lp->pending_tx_skb != NULL); @@ -734,7 +734,7 @@ static void smc_tx(struct net_device *dev) void __iomem *ioaddr = lp->base; unsigned int saved_packet, packet_no, tx_status, pkt_len; - DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + DBG(3, "%s: %s\n", dev->name, __func__); /* If the TX FIFO is empty then nothing to do */ packet_no = SMC_GET_TXFIFO(lp); @@ -856,7 +856,7 @@ static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg) SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO)); DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", - __FUNCTION__, phyaddr, phyreg, phydata); + __func__, phyaddr, phyreg, phydata); SMC_SELECT_BANK(lp, 2); return phydata; @@ -883,7 +883,7 @@ static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg, SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO)); DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", - __FUNCTION__, phyaddr, phyreg, phydata); + __func__, phyaddr, phyreg, phydata); SMC_SELECT_BANK(lp, 2); } @@ -896,7 +896,7 @@ static void smc_phy_detect(struct net_device *dev) struct smc_local *lp = netdev_priv(dev); int phyaddr; - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + DBG(2, "%s: %s\n", dev->name, __func__); lp->phy_type = 0; @@ -935,7 +935,7 @@ static int smc_phy_fixed(struct net_device *dev) int phyaddr = lp->mii.phy_id; int bmcr, cfg1; - DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + DBG(3, "%s: %s\n", dev->name, __func__); /* Enter Link Disable state */ cfg1 = smc_phy_read(dev, phyaddr, PHY_CFG1_REG); @@ -1168,7 +1168,7 @@ static void smc_phy_interrupt(struct net_device *dev) int phyaddr = lp->mii.phy_id; int phy18; - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + DBG(2, "%s: %s\n", dev->name, __func__); if (lp->phy_type == 0) return; @@ -1236,7 +1236,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id) int status, mask, timeout, card_stats; int saved_pointer; - DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + DBG(3, "%s: %s\n", dev->name, __func__); spin_lock(&lp->lock); @@ -1358,7 +1358,7 @@ static void smc_timeout(struct net_device *dev) void __iomem *ioaddr = lp->base; int status, mask, eph_st, meminfo, fifo; - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + DBG(2, "%s: %s\n", dev->name, __func__); spin_lock_irq(&lp->lock); status = SMC_GET_INT(lp); @@ -1402,7 +1402,7 @@ static void smc_set_multicast_list(struct net_device *dev) unsigned char multicast_table[8]; int update_multicast = 0; - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + DBG(2, "%s: %s\n", dev->name, __func__); if (dev->flags & IFF_PROMISC) { DBG(2, "%s: RCR_PRMS\n", dev->name); @@ -1505,7 +1505,7 @@ smc_open(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + DBG(2, "%s: %s\n", dev->name, __func__); /* * Check that the address is valid. If its not, refuse @@ -1513,14 +1513,16 @@ smc_open(struct net_device *dev) * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ if (!is_valid_ether_addr(dev->dev_addr)) { - PRINTK("%s: no valid ethernet hw addr\n", __FUNCTION__); + PRINTK("%s: no valid ethernet hw addr\n", __func__); return -EINVAL; } /* Setup the default Register Modes */ lp->tcr_cur_mode = TCR_DEFAULT; lp->rcr_cur_mode = RCR_DEFAULT; - lp->rpc_cur_mode = RPC_DEFAULT; + lp->rpc_cur_mode = RPC_DEFAULT | + lp->cfg.leda << RPC_LSXA_SHFT | + lp->cfg.ledb << RPC_LSXB_SHFT; /* * If we are not using a MII interface, we need to @@ -1557,7 +1559,7 @@ static int smc_close(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + DBG(2, "%s: %s\n", dev->name, __func__); netif_stop_queue(dev); netif_carrier_off(dev); @@ -1700,7 +1702,7 @@ static int __init smc_findirq(struct smc_local *lp) int timeout = 20; unsigned long cookie; - DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); + DBG(2, "%s: %s\n", CARDNAME, __func__); cookie = probe_irq_on(); @@ -1778,7 +1780,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr, const char *version_string; DECLARE_MAC_BUF(mac); - DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); + DBG(2, "%s: %s\n", CARDNAME, __func__); /* First, see if the high byte is 0x33 */ val = SMC_CURRENT_BANK(lp); @@ -1961,7 +1963,8 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr, if (dev->dma != (unsigned char)-1) printk(" DMA %d", dev->dma); - printk("%s%s\n", nowait ? " [nowait]" : "", + printk("%s%s\n", + lp->cfg.flags & SMC91X_NOWAIT ? " [nowait]" : "", THROTTLE_TX_PKTS ? " [throttle_tx]" : ""); if (!is_valid_ether_addr(dev->dev_addr)) { @@ -2157,6 +2160,11 @@ static int smc_drv_probe(struct platform_device *pdev) lp->cfg.flags |= (nowait) ? SMC91X_NOWAIT : 0; } + if (!lp->cfg.leda && !lp->cfg.ledb) { + lp->cfg.leda = RPC_LSA_DEFAULT; + lp->cfg.ledb = RPC_LSB_DEFAULT; + } + ndev->dma = (unsigned char)-1; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 997e7f1d5c6..a07cc9351c6 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -43,7 +43,8 @@ #if defined(CONFIG_ARCH_LUBBOCK) ||\ defined(CONFIG_MACH_MAINSTONE) ||\ defined(CONFIG_MACH_ZYLONITE) ||\ - defined(CONFIG_MACH_LITTLETON) + defined(CONFIG_MACH_LITTLETON) ||\ + defined(CONFIG_ARCH_VIPER) #include <asm/mach-types.h> @@ -446,6 +447,8 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define SMC_CAN_USE_32BIT 1 #define SMC_NOWAIT 1 +#define SMC_IO_SHIFT (lp->io_shift) + #define SMC_inb(a, r) readb((a) + (r)) #define SMC_inw(a, r) readw((a) + (r)) #define SMC_inl(a, r) readl((a) + (r)) @@ -778,14 +781,6 @@ smc_pxa_dma_irq(int dma, void *dummy) #define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode #define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb #define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb -#define RPC_LED_100_10 (0x00) // LED = 100Mbps OR's with 10Mbps link detect -#define RPC_LED_RES (0x01) // LED = Reserved -#define RPC_LED_10 (0x02) // LED = 10Mbps link detect -#define RPC_LED_FD (0x03) // LED = Full Duplex Mode -#define RPC_LED_TX_RX (0x04) // LED = TX or RX packet occurred -#define RPC_LED_100 (0x05) // LED = 100Mbps link dectect -#define RPC_LED_TX (0x06) // LED = TX packet occurred -#define RPC_LED_RX (0x07) // LED = RX packet occurred #ifndef RPC_LSA_DEFAULT #define RPC_LSA_DEFAULT RPC_LED_100 @@ -794,7 +789,7 @@ smc_pxa_dma_irq(int dma, void *dummy) #define RPC_LSB_DEFAULT RPC_LED_FD #endif -#define RPC_DEFAULT (RPC_ANEG | (RPC_LSA_DEFAULT << RPC_LSXA_SHFT) | (RPC_LSB_DEFAULT << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX) +#define RPC_DEFAULT (RPC_ANEG | RPC_SPEED | RPC_DPLX) /* Bank 0 0x0C is reserved */ diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 0e4a88d1632..018d0fca942 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1,7 +1,6 @@ -/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $ - * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. +/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * - * Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1997, 1998, 1999, 2003, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/module.h> @@ -23,6 +22,9 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/auxio.h> #include <asm/byteorder.h> @@ -32,15 +34,14 @@ #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/pgtable.h> -#include <asm/sbus.h> #include <asm/system.h> #include "sunbmac.h" #define DRV_NAME "sunbmac" -#define DRV_VERSION "2.0" -#define DRV_RELDATE "11/24/03" -#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" +#define DRV_VERSION "2.1" +#define DRV_RELDATE "August 26, 2008" +#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; @@ -96,8 +97,8 @@ static int qec_global_reset(void __iomem *gregs) static void qec_init(struct bigmac *bp) { + struct of_device *qec_op = bp->qec_op; void __iomem *gregs = bp->gregs; - struct sbus_dev *qec_sdev = bp->qec_sdev; u8 bsizes = bp->bigmac_bursts; u32 regval; @@ -112,13 +113,13 @@ static void qec_init(struct bigmac *bp) sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE); /* All of memsize is given to bigmac. */ - sbus_writel(qec_sdev->reg_addrs[1].reg_size, + sbus_writel(resource_size(&qec_op->resource[1]), gregs + GLOB_MSIZE); /* Half to the transmitter, half to the receiver. */ - sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1, + sbus_writel(resource_size(&qec_op->resource[1]) >> 1, gregs + GLOB_TSIZE); - sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1, + sbus_writel(resource_size(&qec_op->resource[1]) >> 1, gregs + GLOB_RSIZE); } @@ -239,9 +240,10 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq) skb_reserve(skb, 34); bb->be_rxd[i].rx_addr = - sbus_map_single(bp->bigmac_sdev, skb->data, - RX_BUF_ALLOC_SIZE - 34, - SBUS_DMA_FROMDEVICE); + dma_map_single(&bp->bigmac_op->dev, + skb->data, + RX_BUF_ALLOC_SIZE - 34, + DMA_FROM_DEVICE); bb->be_rxd[i].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); } @@ -776,9 +778,9 @@ static void bigmac_tx(struct bigmac *bp) skb = bp->tx_skbs[elem]; bp->enet_stats.tx_packets++; bp->enet_stats.tx_bytes += skb->len; - sbus_unmap_single(bp->bigmac_sdev, - this->tx_addr, skb->len, - SBUS_DMA_TODEVICE); + dma_unmap_single(&bp->bigmac_op->dev, + this->tx_addr, skb->len, + DMA_TO_DEVICE); DTX(("skb(%p) ", skb)); bp->tx_skbs[elem] = NULL; @@ -831,18 +833,19 @@ static void bigmac_rx(struct bigmac *bp) drops++; goto drop_it; } - sbus_unmap_single(bp->bigmac_sdev, - this->rx_addr, - RX_BUF_ALLOC_SIZE - 34, - SBUS_DMA_FROMDEVICE); + dma_unmap_single(&bp->bigmac_op->dev, + this->rx_addr, + RX_BUF_ALLOC_SIZE - 34, + DMA_FROM_DEVICE); bp->rx_skbs[elem] = new_skb; new_skb->dev = bp->dev; skb_put(new_skb, ETH_FRAME_LEN); skb_reserve(new_skb, 34); - this->rx_addr = sbus_map_single(bp->bigmac_sdev, - new_skb->data, - RX_BUF_ALLOC_SIZE - 34, - SBUS_DMA_FROMDEVICE); + this->rx_addr = + dma_map_single(&bp->bigmac_op->dev, + new_skb->data, + RX_BUF_ALLOC_SIZE - 34, + DMA_FROM_DEVICE); this->rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); @@ -857,13 +860,13 @@ static void bigmac_rx(struct bigmac *bp) } skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - sbus_dma_sync_single_for_cpu(bp->bigmac_sdev, - this->rx_addr, len, - SBUS_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&bp->bigmac_op->dev, + this->rx_addr, len, + DMA_FROM_DEVICE); skb_copy_to_linear_data(copy_skb, (unsigned char *)skb->data, len); - sbus_dma_sync_single_for_device(bp->bigmac_sdev, - this->rx_addr, len, - SBUS_DMA_FROMDEVICE); + dma_sync_single_for_device(&bp->bigmac_op->dev, + this->rx_addr, len, + DMA_FROM_DEVICE); /* Reuse original ring buffer. */ this->rx_flags = @@ -959,7 +962,8 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 mapping; len = skb->len; - mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE); + mapping = dma_map_single(&bp->bigmac_op->dev, skb->data, + len, DMA_TO_DEVICE); /* Avoid a race... */ spin_lock_irq(&bp->lock); @@ -1051,12 +1055,8 @@ static void bigmac_set_multicast(struct net_device *dev) /* Ethtool support... */ static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct bigmac *bp = dev->priv; - strcpy(info->driver, "sunbmac"); strcpy(info->version, "2.0"); - sprintf(info->bus_info, "SBUS:%d", - bp->qec_sdev->slot); } static u32 bigmac_get_link(struct net_device *dev) @@ -1075,14 +1075,15 @@ static const struct ethtool_ops bigmac_ethtool_ops = { .get_link = bigmac_get_link, }; -static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) +static int __devinit bigmac_ether_init(struct of_device *op, + struct of_device *qec_op) { - struct net_device *dev; static int version_printed; - struct bigmac *bp; + struct net_device *dev; u8 bsizes, bsizes_more; - int i; DECLARE_MAC_BUF(mac); + struct bigmac *bp; + int i; /* Get a new device struct for this interface. */ dev = alloc_etherdev(sizeof(struct bigmac)); @@ -1092,32 +1093,21 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) if (version_printed++ == 0) printk(KERN_INFO "%s", version); - dev->base_addr = (long) qec_sdev; for (i = 0; i < 6; i++) dev->dev_addr[i] = idprom->id_ethaddr[i]; /* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */ - bp = dev->priv; - bp->qec_sdev = qec_sdev; - bp->bigmac_sdev = qec_sdev->child; + bp = netdev_priv(dev); + bp->qec_op = qec_op; + bp->bigmac_op = op; - SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); spin_lock_init(&bp->lock); - /* Verify the registers we expect, are actually there. */ - if ((bp->bigmac_sdev->num_registers != 3) || - (bp->qec_sdev->num_registers != 2)) { - printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n", - bp->qec_sdev->num_registers, - bp->bigmac_sdev->num_registers); - printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n"); - goto fail_and_cleanup; - } - /* Map in QEC global control registers. */ - bp->gregs = sbus_ioremap(&bp->qec_sdev->resource[0], 0, - GLOB_REG_SIZE, "BigMAC QEC GLobal Regs"); + bp->gregs = of_ioremap(&qec_op->resource[0], 0, + GLOB_REG_SIZE, "BigMAC QEC GLobal Regs"); if (!bp->gregs) { printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n"); goto fail_and_cleanup; @@ -1134,13 +1124,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) goto fail_and_cleanup; /* Get supported SBUS burst sizes. */ - bsizes = prom_getintdefault(bp->qec_sdev->prom_node, - "burst-sizes", - 0xff); - - bsizes_more = prom_getintdefault(bp->qec_sdev->bus->prom_node, - "burst-sizes", - 0xff); + bsizes = of_getintprop_default(qec_op->node, "burst-sizes", 0xff); + bsizes_more = of_getintprop_default(qec_op->node, "burst-sizes", 0xff); bsizes &= 0xff; if (bsizes_more != 0xff) @@ -1154,16 +1139,16 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) qec_init(bp); /* Map in the BigMAC channel registers. */ - bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0, - CREG_REG_SIZE, "BigMAC QEC Channel Regs"); + bp->creg = of_ioremap(&op->resource[0], 0, + CREG_REG_SIZE, "BigMAC QEC Channel Regs"); if (!bp->creg) { printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n"); goto fail_and_cleanup; } /* Map in the BigMAC control registers. */ - bp->bregs = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0, - BMAC_REG_SIZE, "BigMAC Primary Regs"); + bp->bregs = of_ioremap(&op->resource[1], 0, + BMAC_REG_SIZE, "BigMAC Primary Regs"); if (!bp->bregs) { printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n"); goto fail_and_cleanup; @@ -1172,8 +1157,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) /* Map in the BigMAC transceiver registers, this is how you poke at * the BigMAC's PHY. */ - bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0, - TCVR_REG_SIZE, "BigMAC Transceiver Regs"); + bp->tregs = of_ioremap(&op->resource[2], 0, + TCVR_REG_SIZE, "BigMAC Transceiver Regs"); if (!bp->tregs) { printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n"); goto fail_and_cleanup; @@ -1183,17 +1168,17 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) bigmac_stop(bp); /* Allocate transmit/receive descriptor DVMA block. */ - bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev, - PAGE_SIZE, - &bp->bblock_dvma); + bp->bmac_block = dma_alloc_coherent(&bp->bigmac_op->dev, + PAGE_SIZE, + &bp->bblock_dvma, GFP_ATOMIC); if (bp->bmac_block == NULL || bp->bblock_dvma == 0) { printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n"); goto fail_and_cleanup; } /* Get the board revision of this BigMAC. */ - bp->board_rev = prom_getintdefault(bp->bigmac_sdev->prom_node, - "board-version", 1); + bp->board_rev = of_getintprop_default(bp->bigmac_op->node, + "board-version", 1); /* Init auto-negotiation timer state. */ init_timer(&bp->bigmac_timer); @@ -1217,7 +1202,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) dev->watchdog_timeo = 5*HZ; /* Finish net device registration. */ - dev->irq = bp->bigmac_sdev->irqs[0]; + dev->irq = bp->bigmac_op->irqs[0]; dev->dma = 0; if (register_netdev(dev)) { @@ -1225,7 +1210,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) goto fail_and_cleanup; } - dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp); + dev_set_drvdata(&bp->bigmac_op->dev, bp); printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n", dev->name, print_mac(mac, dev->dev_addr)); @@ -1236,66 +1221,67 @@ fail_and_cleanup: /* Something went wrong, undo whatever we did so far. */ /* Free register mappings if any. */ if (bp->gregs) - sbus_iounmap(bp->gregs, GLOB_REG_SIZE); + of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE); if (bp->creg) - sbus_iounmap(bp->creg, CREG_REG_SIZE); + of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE); if (bp->bregs) - sbus_iounmap(bp->bregs, BMAC_REG_SIZE); + of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE); if (bp->tregs) - sbus_iounmap(bp->tregs, TCVR_REG_SIZE); + of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE); if (bp->bmac_block) - sbus_free_consistent(bp->bigmac_sdev, - PAGE_SIZE, - bp->bmac_block, - bp->bblock_dvma); + dma_free_coherent(&bp->bigmac_op->dev, + PAGE_SIZE, + bp->bmac_block, + bp->bblock_dvma); /* This also frees the co-located 'dev->priv' */ free_netdev(dev); return -ENODEV; } -/* QEC can be the parent of either QuadEthernet or - * a BigMAC. We want the latter. +/* QEC can be the parent of either QuadEthernet or a BigMAC. We want + * the latter. */ -static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit bigmac_sbus_probe(struct of_device *op, + const struct of_device_id *match) { - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - struct device_node *dp = dev->node; + struct device *parent = op->dev.parent; + struct of_device *qec_op; - if (!strcmp(dp->name, "be")) - sdev = sdev->parent; + qec_op = to_of_device(parent); - return bigmac_ether_init(sdev); + return bigmac_ether_init(op, qec_op); } -static int __devexit bigmac_sbus_remove(struct of_device *dev) +static int __devexit bigmac_sbus_remove(struct of_device *op) { - struct bigmac *bp = dev_get_drvdata(&dev->dev); + struct bigmac *bp = dev_get_drvdata(&op->dev); + struct device *parent = op->dev.parent; struct net_device *net_dev = bp->dev; + struct of_device *qec_op; - unregister_netdevice(net_dev); + qec_op = to_of_device(parent); - sbus_iounmap(bp->gregs, GLOB_REG_SIZE); - sbus_iounmap(bp->creg, CREG_REG_SIZE); - sbus_iounmap(bp->bregs, BMAC_REG_SIZE); - sbus_iounmap(bp->tregs, TCVR_REG_SIZE); - sbus_free_consistent(bp->bigmac_sdev, - PAGE_SIZE, - bp->bmac_block, - bp->bblock_dvma); + unregister_netdev(net_dev); + + of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE); + of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE); + of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE); + of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE); + dma_free_coherent(&op->dev, + PAGE_SIZE, + bp->bmac_block, + bp->bblock_dvma); free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id bigmac_sbus_match[] = { - { - .name = "qec", - }, +static const struct of_device_id bigmac_sbus_match[] = { { .name = "be", }, @@ -1313,7 +1299,7 @@ static struct of_platform_driver bigmac_sbus_driver = { static int __init bigmac_init(void) { - return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type); + return of_register_driver(&bigmac_sbus_driver, &of_bus_type); } static void __exit bigmac_exit(void) diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h index b563d3c2993..8840bc0b840 100644 --- a/drivers/net/sunbmac.h +++ b/drivers/net/sunbmac.h @@ -329,8 +329,8 @@ struct bigmac { unsigned int timer_ticks; struct net_device_stats enet_stats; - struct sbus_dev *qec_sdev; - struct sbus_dev *bigmac_sdev; + struct of_device *qec_op; + struct of_device *bigmac_op; struct net_device *dev; }; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 7d5561b8241..f860ea15039 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -409,6 +409,7 @@ static int change_mtu(struct net_device *dev, int new_mtu); static int eeprom_read(void __iomem *ioaddr, int location); static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int mdio_wait_link(struct net_device *dev, int wait); static int netdev_open(struct net_device *dev); static void check_duplex(struct net_device *dev); static void netdev_timer(unsigned long data); @@ -785,6 +786,24 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val return; } +static int mdio_wait_link(struct net_device *dev, int wait) +{ + int bmsr; + int phy_id; + struct netdev_private *np; + + np = netdev_priv(dev); + phy_id = np->phys[0]; + + do { + bmsr = mdio_read(dev, phy_id, MII_BMSR); + if (bmsr & 0x0004) + return 0; + mdelay(1); + } while (--wait > 0); + return -1; +} + static int netdev_open(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); @@ -1393,41 +1412,51 @@ static void netdev_error(struct net_device *dev, int intr_status) int speed; if (intr_status & LinkChange) { - if (np->an_enable) { - mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE); - mii_lpa= mdio_read (dev, np->phys[0], MII_LPA); - mii_advertise &= mii_lpa; - printk (KERN_INFO "%s: Link changed: ", dev->name); - if (mii_advertise & ADVERTISE_100FULL) { - np->speed = 100; - printk ("100Mbps, full duplex\n"); - } else if (mii_advertise & ADVERTISE_100HALF) { - np->speed = 100; - printk ("100Mbps, half duplex\n"); - } else if (mii_advertise & ADVERTISE_10FULL) { - np->speed = 10; - printk ("10Mbps, full duplex\n"); - } else if (mii_advertise & ADVERTISE_10HALF) { - np->speed = 10; - printk ("10Mbps, half duplex\n"); - } else - printk ("\n"); + if (mdio_wait_link(dev, 10) == 0) { + printk(KERN_INFO "%s: Link up\n", dev->name); + if (np->an_enable) { + mii_advertise = mdio_read(dev, np->phys[0], + MII_ADVERTISE); + mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); + mii_advertise &= mii_lpa; + printk(KERN_INFO "%s: Link changed: ", + dev->name); + if (mii_advertise & ADVERTISE_100FULL) { + np->speed = 100; + printk("100Mbps, full duplex\n"); + } else if (mii_advertise & ADVERTISE_100HALF) { + np->speed = 100; + printk("100Mbps, half duplex\n"); + } else if (mii_advertise & ADVERTISE_10FULL) { + np->speed = 10; + printk("10Mbps, full duplex\n"); + } else if (mii_advertise & ADVERTISE_10HALF) { + np->speed = 10; + printk("10Mbps, half duplex\n"); + } else + printk("\n"); + } else { + mii_ctl = mdio_read(dev, np->phys[0], MII_BMCR); + speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; + np->speed = speed; + printk(KERN_INFO "%s: Link changed: %dMbps ,", + dev->name, speed); + printk("%s duplex.\n", + (mii_ctl & BMCR_FULLDPLX) ? + "full" : "half"); + } + check_duplex(dev); + if (np->flowctrl && np->mii_if.full_duplex) { + iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200, + ioaddr + MulticastFilter1+2); + iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl, + ioaddr + MACCtrl0); + } + netif_carrier_on(dev); } else { - mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR); - speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; - np->speed = speed; - printk (KERN_INFO "%s: Link changed: %dMbps ,", - dev->name, speed); - printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ? - "full" : "half"); - } - check_duplex (dev); - if (np->flowctrl && np->mii_if.full_duplex) { - iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200, - ioaddr + MulticastFilter1+2); - iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl, - ioaddr + MACCtrl0); + printk(KERN_INFO "%s: Link down\n", dev->name); + netif_carrier_off(dev); } } if (intr_status & StatsMax) { diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index b79d5f018f7..f1ebeb5f65b 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -3,7 +3,7 @@ * "Happy Meal Ethernet" found on SunSwift SBUS cards. * * Copyright (C) 1996, 1998, 1999, 2002, 2003, - 2006 David S. Miller (davem@davemloft.net) + * 2006, 2008 David S. Miller (davem@davemloft.net) * * Changes : * 2000/11/11 Willy Tarreau <willy AT meta-x.org> @@ -34,6 +34,7 @@ #include <linux/skbuff.h> #include <linux/mm.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> #include <asm/system.h> #include <asm/io.h> @@ -41,8 +42,9 @@ #include <asm/byteorder.h> #ifdef CONFIG_SPARC +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/idprom.h> -#include <asm/sbus.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/prom.h> @@ -60,8 +62,8 @@ #include "sunhme.h" #define DRV_NAME "sunhme" -#define DRV_VERSION "3.00" -#define DRV_RELDATE "June 23, 2006" +#define DRV_VERSION "3.10" +#define DRV_RELDATE "August 26, 2008" #define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = @@ -251,13 +253,13 @@ static u32 pci_hme_read_desc32(hme32 *p) #define hme_read_desc32(__hp, __p) \ ((__hp)->read_desc32(__p)) #define hme_dma_map(__hp, __ptr, __size, __dir) \ - ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir))) + ((__hp)->dma_map((__hp)->dma_dev, (__ptr), (__size), (__dir))) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ - ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir))) + ((__hp)->dma_unmap((__hp)->dma_dev, (__addr), (__size), (__dir))) #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ - ((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))) + ((__hp)->dma_sync_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))) #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ - ((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))) + ((__hp)->dma_sync_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))) #else #ifdef CONFIG_SBUS /* SBUS only compilation */ @@ -277,13 +279,13 @@ do { (__txd)->tx_addr = (__force hme32)(u32)(__addr); \ } while(0) #define hme_read_desc32(__hp, __p) ((__force u32)(hme32)*(__p)) #define hme_dma_map(__hp, __ptr, __size, __dir) \ - sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) + dma_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ - sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) + dma_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ - sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) + dma_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ - sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) + dma_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)) #else /* PCI only compilation */ #define hme_write32(__hp, __reg, __val) \ @@ -305,36 +307,17 @@ static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p) return le32_to_cpup((__le32 *)p); } #define hme_dma_map(__hp, __ptr, __size, __dir) \ - pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) + pci_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ - pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) + pci_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ - pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) + pci_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ - pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) + pci_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)) #endif #endif -#ifdef SBUS_DMA_BIDIRECTIONAL -# define DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL -#else -# define DMA_BIDIRECTIONAL 0 -#endif - -#ifdef SBUS_DMA_FROMDEVICE -# define DMA_FROMDEVICE SBUS_DMA_FROMDEVICE -#else -# define DMA_TODEVICE 1 -#endif - -#ifdef SBUS_DMA_TODEVICE -# define DMA_TODEVICE SBUS_DMA_TODEVICE -#else -# define DMA_FROMDEVICE 2 -#endif - - /* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */ static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit) { @@ -1224,7 +1207,8 @@ static void happy_meal_clean_rings(struct happy_meal *hp) rxd = &hp->happy_block->happy_meal_rxd[i]; dma_addr = hme_read_desc32(hp, &rxd->rx_addr); - hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE); + dma_unmap_single(hp->dma_dev, dma_addr, + RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); hp->rx_skbs[i] = NULL; } @@ -1242,10 +1226,10 @@ static void happy_meal_clean_rings(struct happy_meal *hp) for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { txd = &hp->happy_block->happy_meal_txd[i]; dma_addr = hme_read_desc32(hp, &txd->tx_addr); - hme_dma_unmap(hp, dma_addr, - (hme_read_desc32(hp, &txd->tx_flags) - & TXFLAG_SIZE), - DMA_TODEVICE); + dma_unmap_single(hp->dma_dev, dma_addr, + (hme_read_desc32(hp, &txd->tx_flags) + & TXFLAG_SIZE), + DMA_TO_DEVICE); if (frag != skb_shinfo(skb)->nr_frags) i++; @@ -1287,7 +1271,8 @@ static void happy_meal_init_rings(struct happy_meal *hp) skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); hme_write_rxd(hp, &hb->happy_meal_rxd[i], (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)), - hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE)); + dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE, + DMA_FROM_DEVICE)); skb_reserve(skb, RX_OFFSET); } @@ -1593,7 +1578,7 @@ static int happy_meal_init(struct happy_meal *hp) if ((hp->happy_bursts & DMA_BURST64) && ((hp->happy_flags & HFLAG_PCI) != 0 #ifdef CONFIG_SBUS - || sbus_can_burst64(hp->happy_dev) + || sbus_can_burst64() #endif || 0)) { u32 gcfg = GREG_CFG_BURST64; @@ -1603,11 +1588,13 @@ static int happy_meal_init(struct happy_meal *hp) * do not. -DaveM */ #ifdef CONFIG_SBUS - if ((hp->happy_flags & HFLAG_PCI) == 0 && - sbus_can_dma_64bit(hp->happy_dev)) { - sbus_set_sbus64(hp->happy_dev, - hp->happy_bursts); - gcfg |= GREG_CFG_64BIT; + if ((hp->happy_flags & HFLAG_PCI) == 0) { + struct of_device *op = hp->happy_dev; + if (sbus_can_dma_64bit()) { + sbus_set_sbus64(&op->dev, + hp->happy_bursts); + gcfg |= GREG_CFG_64BIT; + } } #endif @@ -1966,7 +1953,7 @@ static void happy_meal_tx(struct happy_meal *hp) dma_len = hme_read_desc32(hp, &this->tx_flags); dma_len &= TXFLAG_SIZE; - hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE); + dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); elem = NEXT_TX(elem); this = &txbase[elem]; @@ -2044,13 +2031,14 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) drops++; goto drop_it; } - hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE); + dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); hp->rx_skbs[elem] = new_skb; new_skb->dev = dev; skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), - hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE)); + dma_map_single(hp->dma_dev, new_skb->data, RX_BUF_ALLOC_SIZE, + DMA_FROM_DEVICE)); skb_reserve(new_skb, RX_OFFSET); /* Trim the original skb for the netif. */ @@ -2065,10 +2053,9 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE); + dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE); skb_copy_from_linear_data(skb, copy_skb->data, len); - hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE); - + dma_sync_single_for_device(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE); /* Reuse original ring buffer. */ hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), @@ -2300,7 +2287,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 mapping, len; len = skb->len; - mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE); + mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE); tx_flags |= (TXFLAG_SOP | TXFLAG_EOP); hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], (tx_flags | (len & TXFLAG_SIZE)), @@ -2314,7 +2301,8 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) * Otherwise we could race with the device. */ first_len = skb_headlen(skb); - first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE); + first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len, + DMA_TO_DEVICE); entry = NEXT_TX(entry); for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { @@ -2322,10 +2310,9 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 len, mapping, this_txflags; len = this_frag->size; - mapping = hme_dma_map(hp, - ((void *) page_address(this_frag->page) + - this_frag->page_offset), - len, DMA_TODEVICE); + mapping = dma_map_page(hp->dma_dev, this_frag->page, + this_frag->page_offset, len, + DMA_TO_DEVICE); this_txflags = tx_flags; if (frag == skb_shinfo(skb)->nr_frags - 1) this_txflags |= TXFLAG_EOP; @@ -2493,9 +2480,12 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info } #ifdef CONFIG_SBUS else { - struct sbus_dev *sdev = hp->happy_dev; - sprintf(info->bus_info, "SBUS:%d", - sdev->slot); + const struct linux_prom_registers *regs; + struct of_device *op = hp->happy_dev; + regs = of_get_property(op->node, "regs", NULL); + if (regs) + sprintf(info->bus_info, "SBUS:%d", + regs->which_io); } #endif } @@ -2521,63 +2511,21 @@ static const struct ethtool_ops hme_ethtool_ops = { static int hme_version_printed; #ifdef CONFIG_SBUS -void __devinit quattro_get_ranges(struct quattro *qp) -{ - struct sbus_dev *sdev = qp->quattro_dev; - int err; - - err = prom_getproperty(sdev->prom_node, - "ranges", - (char *)&qp->ranges[0], - sizeof(qp->ranges)); - if (err == 0 || err == -1) { - qp->nranges = 0; - return; - } - qp->nranges = (err / sizeof(struct linux_prom_ranges)); -} - -static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp) -{ - struct sbus_dev *sdev = hp->happy_dev; - int rng; - - for (rng = 0; rng < qp->nranges; rng++) { - struct linux_prom_ranges *rngp = &qp->ranges[rng]; - int reg; - - for (reg = 0; reg < 5; reg++) { - if (sdev->reg_addrs[reg].which_io == - rngp->ot_child_space) - break; - } - if (reg == 5) - continue; - - sdev->reg_addrs[reg].which_io = rngp->ot_parent_space; - sdev->reg_addrs[reg].phys_addr += rngp->ot_parent_base; - } -} - /* Given a happy meal sbus device, find it's quattro parent. * If none exist, allocate and return a new one. * * Return NULL on failure. */ -static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev) +static struct quattro * __devinit quattro_sbus_find(struct of_device *child) { - struct sbus_dev *sdev; + struct device *parent = child->dev.parent; + struct of_device *op; struct quattro *qp; - int i; - for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - for (i = 0, sdev = qp->quattro_dev; - (sdev != NULL) && (i < 4); - sdev = sdev->next, i++) { - if (sdev == goal_sdev) - return qp; - } - } + op = to_of_device(parent); + qp = dev_get_drvdata(&op->dev); + if (qp) + return qp; qp = kmalloc(sizeof(struct quattro), GFP_KERNEL); if (qp != NULL) { @@ -2586,10 +2534,11 @@ static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev) for (i = 0; i < 4; i++) qp->happy_meals[i] = NULL; - qp->quattro_dev = goal_sdev; + qp->quattro_dev = child; qp->next = qfe_sbus_list; qfe_sbus_list = qp; - quattro_get_ranges(qp); + + dev_set_drvdata(&op->dev, qp); } return qp; } @@ -2602,10 +2551,10 @@ static void __init quattro_sbus_register_irqs(void) struct quattro *qp; for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - struct sbus_dev *sdev = qp->quattro_dev; + struct of_device *op = qp->quattro_dev; int err; - err = request_irq(sdev->irqs[0], + err = request_irq(op->irqs[0], quattro_sbus_interrupt, IRQF_SHARED, "Quattro", qp); @@ -2621,9 +2570,9 @@ static void quattro_sbus_free_irqs(void) struct quattro *qp; for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - struct sbus_dev *sdev = qp->quattro_dev; + struct of_device *op = qp->quattro_dev; - free_irq(sdev->irqs[0], qp); + free_irq(op->irqs[0], qp); } } #endif /* CONFIG_SBUS */ @@ -2660,9 +2609,9 @@ static struct quattro * __devinit quattro_pci_find(struct pci_dev *pdev) #endif /* CONFIG_PCI */ #ifdef CONFIG_SBUS -static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe) +static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) { - struct device_node *dp = sdev->ofdev.node; + struct device_node *dp = op->node, *sbus_dp; struct quattro *qp = NULL; struct happy_meal *hp; struct net_device *dev; @@ -2671,7 +2620,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe DECLARE_MAC_BUF(mac); if (is_qfe) { - qp = quattro_sbus_find(sdev); + qp = quattro_sbus_find(op); if (qp == NULL) goto err_out; for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) @@ -2685,7 +2634,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe dev = alloc_etherdev(sizeof(struct happy_meal)); if (!dev) goto err_out; - SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2713,56 +2662,50 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe memcpy(dev->dev_addr, idprom->id_ethaddr, 6); } - hp = dev->priv; + hp = netdev_priv(dev); - hp->happy_dev = sdev; + hp->happy_dev = op; + hp->dma_dev = &op->dev; spin_lock_init(&hp->happy_lock); err = -ENODEV; - if (sdev->num_registers != 5) { - printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n", - sdev->num_registers); - goto err_out_free_netdev; - } - if (qp != NULL) { hp->qfe_parent = qp; hp->qfe_ent = qfe_slot; qp->happy_meals[qfe_slot] = dev; - quattro_apply_ranges(qp, hp); } - hp->gregs = sbus_ioremap(&sdev->resource[0], 0, - GREG_REG_SIZE, "HME Global Regs"); + hp->gregs = of_ioremap(&op->resource[0], 0, + GREG_REG_SIZE, "HME Global Regs"); if (!hp->gregs) { printk(KERN_ERR "happymeal: Cannot map global registers.\n"); goto err_out_free_netdev; } - hp->etxregs = sbus_ioremap(&sdev->resource[1], 0, - ETX_REG_SIZE, "HME TX Regs"); + hp->etxregs = of_ioremap(&op->resource[1], 0, + ETX_REG_SIZE, "HME TX Regs"); if (!hp->etxregs) { printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n"); goto err_out_iounmap; } - hp->erxregs = sbus_ioremap(&sdev->resource[2], 0, - ERX_REG_SIZE, "HME RX Regs"); + hp->erxregs = of_ioremap(&op->resource[2], 0, + ERX_REG_SIZE, "HME RX Regs"); if (!hp->erxregs) { printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n"); goto err_out_iounmap; } - hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0, - BMAC_REG_SIZE, "HME BIGMAC Regs"); + hp->bigmacregs = of_ioremap(&op->resource[3], 0, + BMAC_REG_SIZE, "HME BIGMAC Regs"); if (!hp->bigmacregs) { printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n"); goto err_out_iounmap; } - hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0, - TCVR_REG_SIZE, "HME Tranceiver Regs"); + hp->tcvregs = of_ioremap(&op->resource[4], 0, + TCVR_REG_SIZE, "HME Tranceiver Regs"); if (!hp->tcvregs) { printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n"); goto err_out_iounmap; @@ -2781,13 +2724,18 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe if (qp != NULL) hp->happy_flags |= HFLAG_QUATTRO; + sbus_dp = to_of_device(op->dev.parent)->node; + if (is_qfe) + sbus_dp = to_of_device(op->dev.parent->parent)->node; + /* Get the supported DVMA burst sizes from our Happy SBUS. */ - hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node, + hp->happy_bursts = of_getintprop_default(sbus_dp, "burst-sizes", 0x00); - hp->happy_block = sbus_alloc_consistent(hp->happy_dev, - PAGE_SIZE, - &hp->hblock_dvma); + hp->happy_block = dma_alloc_coherent(hp->dma_dev, + PAGE_SIZE, + &hp->hblock_dvma, + GFP_ATOMIC); err = -ENOMEM; if (!hp->happy_block) { printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n"); @@ -2816,19 +2764,13 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe /* Happy Meal can do it all... */ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - dev->irq = sdev->irqs[0]; + dev->irq = op->irqs[0]; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) - /* Hook up PCI register/dma accessors. */ + /* Hook up SBUS register/descriptor accessors. */ hp->read_desc32 = sbus_hme_read_desc32; hp->write_txd = sbus_hme_write_txd; hp->write_rxd = sbus_hme_write_rxd; - hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single; - hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single; - hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) - sbus_dma_sync_single_for_cpu; - hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) - sbus_dma_sync_single_for_device; hp->read32 = sbus_hme_read32; hp->write32 = sbus_hme_write32; #endif @@ -2843,10 +2785,10 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe if (register_netdev(hp->dev)) { printk(KERN_ERR "happymeal: Cannot register net device, " "aborting.\n"); - goto err_out_free_consistent; + goto err_out_free_coherent; } - dev_set_drvdata(&sdev->ofdev.dev, hp); + dev_set_drvdata(&op->dev, hp); if (qfe_slot != -1) printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ", @@ -2859,23 +2801,23 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe return 0; -err_out_free_consistent: - sbus_free_consistent(hp->happy_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); +err_out_free_coherent: + dma_free_coherent(hp->dma_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); err_out_iounmap: if (hp->gregs) - sbus_iounmap(hp->gregs, GREG_REG_SIZE); + of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE); if (hp->etxregs) - sbus_iounmap(hp->etxregs, ETX_REG_SIZE); + of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE); if (hp->erxregs) - sbus_iounmap(hp->erxregs, ERX_REG_SIZE); + of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE); if (hp->bigmacregs) - sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); + of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE); if (hp->tcvregs) - sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); + of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE); err_out_free_netdev: free_netdev(dev); @@ -3035,6 +2977,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, memset(hp, 0, sizeof(*hp)); hp->happy_dev = pdev; + hp->dma_dev = &pdev->dev; spin_lock_init(&hp->happy_lock); @@ -3121,7 +3064,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, #endif hp->happy_block = (struct hmeal_init_block *) - pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma); + dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &hp->hblock_dvma, GFP_KERNEL); err = -ENODEV; if (!hp->happy_block) { @@ -3151,16 +3094,10 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) - /* Hook up PCI register/dma accessors. */ + /* Hook up PCI register/descriptor accessors. */ hp->read_desc32 = pci_hme_read_desc32; hp->write_txd = pci_hme_write_txd; hp->write_rxd = pci_hme_write_rxd; - hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single; - hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single; - hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) - pci_dma_sync_single_for_cpu; - hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) - pci_dma_sync_single_for_device; hp->read32 = pci_hme_read32; hp->write32 = pci_hme_write32; #endif @@ -3231,10 +3168,8 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev) unregister_netdev(net_dev); - pci_free_consistent(hp->happy_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); + dma_free_coherent(hp->dma_dev, PAGE_SIZE, + hp->happy_block, hp->hblock_dvma); iounmap(hp->gregs); pci_release_regions(hp->happy_dev); @@ -3279,46 +3214,45 @@ static void happy_meal_pci_exit(void) #endif #ifdef CONFIG_SBUS -static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit hme_sbus_probe(struct of_device *op, const struct of_device_id *match) { - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - struct device_node *dp = dev->node; + struct device_node *dp = op->node; const char *model = of_get_property(dp, "model", NULL); int is_qfe = (match->data != NULL); if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) is_qfe = 1; - return happy_meal_sbus_probe_one(sdev, is_qfe); + return happy_meal_sbus_probe_one(op, is_qfe); } -static int __devexit hme_sbus_remove(struct of_device *dev) +static int __devexit hme_sbus_remove(struct of_device *op) { - struct happy_meal *hp = dev_get_drvdata(&dev->dev); + struct happy_meal *hp = dev_get_drvdata(&op->dev); struct net_device *net_dev = hp->dev; unregister_netdev(net_dev); /* XXX qfe parent interrupt... */ - sbus_iounmap(hp->gregs, GREG_REG_SIZE); - sbus_iounmap(hp->etxregs, ETX_REG_SIZE); - sbus_iounmap(hp->erxregs, ERX_REG_SIZE); - sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); - sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); - sbus_free_consistent(hp->happy_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); + of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE); + of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE); + of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE); + of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE); + of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE); + dma_free_coherent(hp->dma_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id hme_sbus_match[] = { +static const struct of_device_id hme_sbus_match[] = { { .name = "SUNW,hme", }, @@ -3346,7 +3280,7 @@ static int __init happy_meal_sbus_init(void) { int err; - err = of_register_driver(&hme_sbus_driver, &sbus_bus_type); + err = of_register_driver(&hme_sbus_driver, &of_bus_type); if (!err) quattro_sbus_register_irqs(); diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h index 4da5539fac7..efd2ca0fcad 100644 --- a/drivers/net/sunhme.h +++ b/drivers/net/sunhme.h @@ -405,14 +405,11 @@ struct happy_meal { u32 (*read_desc32)(hme32 *); void (*write_txd)(struct happy_meal_txd *, u32, u32); void (*write_rxd)(struct happy_meal_rxd *, u32, u32); - u32 (*dma_map)(void *, void *, long, int); - void (*dma_unmap)(void *, u32, long, int); - void (*dma_sync_for_cpu)(void *, u32, long, int); - void (*dma_sync_for_device)(void *, u32, long, int); #endif - /* This is either a sbus_dev or a pci_dev. */ + /* This is either an of_device or a pci_dev. */ void *happy_dev; + struct device *dma_dev; spinlock_t happy_lock; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 4e994f87469..704301a5a7f 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -91,6 +91,9 @@ static char lancestr[] = "LANCE"; #include <linux/skbuff.h> #include <linux/ethtool.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/system.h> #include <asm/io.h> @@ -98,7 +101,6 @@ static char lancestr[] = "LANCE"; #include <asm/pgtable.h> #include <asm/byteorder.h> /* Used by the checksum routines */ #include <asm/idprom.h> -#include <asm/sbus.h> #include <asm/prom.h> #include <asm/auxio.h> /* For tpe-link-test? setting */ #include <asm/irq.h> @@ -248,7 +250,7 @@ struct lance_private { int rx_new, tx_new; int rx_old, tx_old; - struct sbus_dma *ledma; /* If set this points to ledma */ + struct of_device *ledma; /* If set this points to ledma */ char tpe; /* cable-selection is TPE */ char auto_select; /* cable-selection by carrier */ char burst_sizes; /* ledma SBus burst sizes */ @@ -263,7 +265,8 @@ struct lance_private { char *name; dma_addr_t init_block_dvma; struct net_device *dev; /* Backpointer */ - struct sbus_dev *sdev; + struct of_device *op; + struct of_device *lebuffer; struct timer_list multicast_timer; }; @@ -1272,27 +1275,29 @@ static void lance_set_multicast_retry(unsigned long _opaque) static void lance_free_hwresources(struct lance_private *lp) { if (lp->lregs) - sbus_iounmap(lp->lregs, LANCE_REG_SIZE); + of_iounmap(&lp->op->resource[0], lp->lregs, LANCE_REG_SIZE); + if (lp->dregs) { + struct of_device *ledma = lp->ledma; + + of_iounmap(&ledma->resource[0], lp->dregs, + resource_size(&ledma->resource[0])); + } if (lp->init_block_iomem) { - sbus_iounmap(lp->init_block_iomem, - sizeof(struct lance_init_block)); + of_iounmap(&lp->lebuffer->resource[0], lp->init_block_iomem, + sizeof(struct lance_init_block)); } else if (lp->init_block_mem) { - sbus_free_consistent(lp->sdev, - sizeof(struct lance_init_block), - lp->init_block_mem, - lp->init_block_dvma); + dma_free_coherent(&lp->op->dev, + sizeof(struct lance_init_block), + lp->init_block_mem, + lp->init_block_dvma); } } /* Ethtool support... */ static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct lance_private *lp = netdev_priv(dev); - strcpy(info->driver, "sunlance"); strcpy(info->version, "2.02"); - sprintf(info->bus_info, "SBUS:%d", - lp->sdev->slot); } static u32 sparc_lance_get_link(struct net_device *dev) @@ -1308,16 +1313,16 @@ static const struct ethtool_ops sparc_lance_ethtool_ops = { .get_link = sparc_lance_get_link, }; -static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, - struct sbus_dma *ledma, - struct sbus_dev *lebuffer) +static int __devinit sparc_lance_probe_one(struct of_device *op, + struct of_device *ledma, + struct of_device *lebuffer) { + struct device_node *dp = op->node; static unsigned version_printed; - struct device_node *dp = sdev->ofdev.node; - struct net_device *dev; struct lance_private *lp; - int i; + struct net_device *dev; DECLARE_MAC_BUF(mac); + int i; dev = alloc_etherdev(sizeof(struct lance_private) + 8); if (!dev) @@ -1338,14 +1343,27 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, dev->dev_addr[i] = idprom->id_ethaddr[i]; /* Get the IO region */ - lp->lregs = sbus_ioremap(&sdev->resource[0], 0, - LANCE_REG_SIZE, lancestr); + lp->lregs = of_ioremap(&op->resource[0], 0, + LANCE_REG_SIZE, lancestr); if (!lp->lregs) { printk(KERN_ERR "SunLance: Cannot map registers.\n"); goto fail; } - lp->sdev = sdev; + lp->ledma = ledma; + if (lp->ledma) { + lp->dregs = of_ioremap(&ledma->resource[0], 0, + resource_size(&ledma->resource[0]), + "ledma"); + if (!lp->dregs) { + printk(KERN_ERR "SunLance: Cannot map " + "ledma registers.\n"); + goto fail; + } + } + + lp->op = op; + lp->lebuffer = lebuffer; if (lebuffer) { /* sanity check */ if (lebuffer->resource[0].start & 7) { @@ -1353,8 +1371,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, goto fail; } lp->init_block_iomem = - sbus_ioremap(&lebuffer->resource[0], 0, - sizeof(struct lance_init_block), "lebuffer"); + of_ioremap(&lebuffer->resource[0], 0, + sizeof(struct lance_init_block), "lebuffer"); if (!lp->init_block_iomem) { printk(KERN_ERR "SunLance: Cannot map PIO buffer.\n"); goto fail; @@ -1366,9 +1384,10 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, lp->tx = lance_tx_pio; } else { lp->init_block_mem = - sbus_alloc_consistent(sdev, sizeof(struct lance_init_block), - &lp->init_block_dvma); - if (!lp->init_block_mem || lp->init_block_dvma == 0) { + dma_alloc_coherent(&op->dev, + sizeof(struct lance_init_block), + &lp->init_block_dvma, GFP_ATOMIC); + if (!lp->init_block_mem) { printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n"); goto fail; } @@ -1383,13 +1402,13 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, LE_C3_BCON)); lp->name = lancestr; - lp->ledma = ledma; lp->burst_sizes = 0; if (lp->ledma) { - struct device_node *ledma_dp = ledma->sdev->ofdev.node; - const char *prop; + struct device_node *ledma_dp = ledma->node; + struct device_node *sbus_dp; unsigned int sbmask; + const char *prop; u32 csr; /* Find burst-size property for ledma */ @@ -1397,7 +1416,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, "burst-sizes", 0); /* ledma may be capable of fast bursts, but sbus may not. */ - sbmask = of_getintprop_default(ledma_dp, "burst-sizes", + sbus_dp = ledma_dp->parent; + sbmask = of_getintprop_default(sbus_dp, "burst-sizes", DMA_BURSTBITS); lp->burst_sizes &= sbmask; @@ -1435,8 +1455,6 @@ no_link_test: lp->tpe = 1; } - lp->dregs = ledma->regs; - /* Reset ledma */ csr = sbus_readl(lp->dregs + DMA_CSR); sbus_writel(csr | DMA_RST_ENET, lp->dregs + DMA_CSR); @@ -1446,7 +1464,7 @@ no_link_test: lp->dregs = NULL; lp->dev = dev; - SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; @@ -1455,9 +1473,7 @@ no_link_test: dev->set_multicast_list = &lance_set_multicast; dev->ethtool_ops = &sparc_lance_ethtool_ops; - dev->irq = sdev->irqs[0]; - - dev->dma = 0; + dev->irq = op->irqs[0]; /* We cannot sleep if the chip is busy during a * multicast list update event, because such events @@ -1473,7 +1489,7 @@ no_link_test: goto fail; } - dev_set_drvdata(&sdev->ofdev.dev, lp); + dev_set_drvdata(&op->dev, lp); printk(KERN_INFO "%s: LANCE %s\n", dev->name, print_mac(mac, dev->dev_addr)); @@ -1486,80 +1502,25 @@ fail: return -ENODEV; } -/* On 4m, find the associated dma for the lance chip */ -static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev) -{ - struct sbus_dma *p; - - for_each_dvma(p) { - if (p->sdev == sdev) - return p; - } - return NULL; -} - -#ifdef CONFIG_SUN4 - -#include <asm/sun4paddr.h> -#include <asm/machines.h> - -/* Find all the lance cards on the system and initialize them */ -static struct sbus_dev sun4_sdev; -static int __devinit sparc_lance_init(void) -{ - if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) || - (idprom->id_machtype == (SM_SUN4|SM_4_470))) { - memset(&sun4_sdev, 0, sizeof(struct sbus_dev)); - sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr; - sun4_sdev.irqs[0] = 6; - return sparc_lance_probe_one(&sun4_sdev, NULL, NULL); - } - return -ENODEV; -} - -static int __exit sunlance_sun4_remove(void) +static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match) { - struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev); - struct net_device *net_dev = lp->dev; - - unregister_netdev(net_dev); - - lance_free_hwresources(lp); - - free_netdev(net_dev); - - dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL); - - return 0; -} - -#else /* !CONFIG_SUN4 */ - -static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct of_device *parent = to_of_device(op->dev.parent); + struct device_node *parent_dp = parent->node; int err; - if (sdev->parent) { - struct of_device *parent = &sdev->parent->ofdev; - - if (!strcmp(parent->node->name, "ledma")) { - struct sbus_dma *ledma = find_ledma(to_sbus_device(&parent->dev)); - - err = sparc_lance_probe_one(sdev, ledma, NULL); - } else if (!strcmp(parent->node->name, "lebuffer")) { - err = sparc_lance_probe_one(sdev, NULL, to_sbus_device(&parent->dev)); - } else - err = sparc_lance_probe_one(sdev, NULL, NULL); + if (!strcmp(parent_dp->name, "ledma")) { + err = sparc_lance_probe_one(op, parent, NULL); + } else if (!strcmp(parent_dp->name, "lebuffer")) { + err = sparc_lance_probe_one(op, NULL, parent); } else - err = sparc_lance_probe_one(sdev, NULL, NULL); + err = sparc_lance_probe_one(op, NULL, NULL); return err; } -static int __devexit sunlance_sbus_remove(struct of_device *dev) +static int __devexit sunlance_sbus_remove(struct of_device *op) { - struct lance_private *lp = dev_get_drvdata(&dev->dev); + struct lance_private *lp = dev_get_drvdata(&op->dev); struct net_device *net_dev = lp->dev; unregister_netdev(net_dev); @@ -1568,12 +1529,12 @@ static int __devexit sunlance_sbus_remove(struct of_device *dev) free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id sunlance_sbus_match[] = { +static const struct of_device_id sunlance_sbus_match[] = { { .name = "le", }, @@ -1593,17 +1554,12 @@ static struct of_platform_driver sunlance_sbus_driver = { /* Find all the lance cards on the system and initialize them */ static int __init sparc_lance_init(void) { - return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type); + return of_register_driver(&sunlance_sbus_driver, &of_bus_type); } -#endif /* !CONFIG_SUN4 */ static void __exit sparc_lance_exit(void) { -#ifdef CONFIG_SUN4 - sunlance_sun4_remove(); -#else of_unregister_driver(&sunlance_sbus_driver); -#endif } module_init(sparc_lance_init); diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index e811331d460..f63644744ff 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -3,7 +3,7 @@ * controller out there can be most efficiently programmed * if you make it look like a LANCE. * - * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 1999, 2003, 2006, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/module.h> @@ -24,13 +24,15 @@ #include <linux/skbuff.h> #include <linux/ethtool.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/system.h> #include <asm/io.h> #include <asm/dma.h> #include <asm/byteorder.h> #include <asm/idprom.h> -#include <asm/sbus.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/auxio.h> @@ -40,8 +42,8 @@ #include "sunqe.h" #define DRV_NAME "sunqe" -#define DRV_VERSION "4.0" -#define DRV_RELDATE "June 23, 2006" +#define DRV_VERSION "4.1" +#define DRV_RELDATE "August 27, 2008" #define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = @@ -690,12 +692,18 @@ static void qe_set_multicast(struct net_device *dev) /* Ethtool support... */ static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { + const struct linux_prom_registers *regs; struct sunqe *qep = dev->priv; + struct of_device *op; strcpy(info->driver, "sunqe"); strcpy(info->version, "3.0"); - sprintf(info->bus_info, "SBUS:%d", - qep->qe_sdev->slot); + + op = qep->op; + regs = of_get_property(op->node, "reg", NULL); + if (regs) + sprintf(info->bus_info, "SBUS:%d", regs->which_io); + } static u32 qe_get_link(struct net_device *dev) @@ -717,11 +725,11 @@ static const struct ethtool_ops qe_ethtool_ops = { }; /* This is only called once at boot time for each card probed. */ -static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev) +static void qec_init_once(struct sunqec *qecp, struct of_device *op) { u8 bsizes = qecp->qec_bursts; - if (sbus_can_burst64(qsdev) && (bsizes & DMA_BURST64)) { + if (sbus_can_burst64() && (bsizes & DMA_BURST64)) { sbus_writel(GLOB_CTRL_B64, qecp->gregs + GLOB_CTRL); } else if (bsizes & DMA_BURST32) { sbus_writel(GLOB_CTRL_B32, qecp->gregs + GLOB_CTRL); @@ -735,15 +743,15 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev) sbus_writel(GLOB_PSIZE_2048, qecp->gregs + GLOB_PSIZE); /* Set the local memsize register, divided up to one piece per QE channel. */ - sbus_writel((qsdev->reg_addrs[1].reg_size >> 2), + sbus_writel((resource_size(&op->resource[1]) >> 2), qecp->gregs + GLOB_MSIZE); /* Divide up the local QEC memory amongst the 4 QE receiver and * transmitter FIFOs. Basically it is (total / 2 / num_channels). */ - sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1, + sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1, qecp->gregs + GLOB_TSIZE); - sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1, + sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1, qecp->gregs + GLOB_RSIZE); } @@ -767,24 +775,21 @@ static u8 __devinit qec_get_burst(struct device_node *dp) return bsizes; } -static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev) +static struct sunqec * __devinit get_qec(struct of_device *child) { - struct sbus_dev *qec_sdev = child_sdev->parent; + struct of_device *op = to_of_device(child->dev.parent); struct sunqec *qecp; - for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) { - if (qecp->qec_sdev == qec_sdev) - break; - } + qecp = dev_get_drvdata(&op->dev); if (!qecp) { qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL); if (qecp) { u32 ctrl; - qecp->qec_sdev = qec_sdev; - qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0, - GLOB_REG_SIZE, - "QEC Global Registers"); + qecp->op = op; + qecp->gregs = of_ioremap(&op->resource[0], 0, + GLOB_REG_SIZE, + "QEC Global Registers"); if (!qecp->gregs) goto fail; @@ -799,16 +804,18 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev) if (qec_global_reset(qecp->gregs)) goto fail; - qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node); + qecp->qec_bursts = qec_get_burst(op->node); - qec_init_once(qecp, qec_sdev); + qec_init_once(qecp, op); - if (request_irq(qec_sdev->irqs[0], &qec_interrupt, + if (request_irq(op->irqs[0], &qec_interrupt, IRQF_SHARED, "qec", (void *) qecp)) { printk(KERN_ERR "qec: Can't register irq.\n"); goto fail; } + dev_set_drvdata(&op->dev, qecp); + qecp->next_module = root_qec_dev; root_qec_dev = qecp; } @@ -818,17 +825,17 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev) fail: if (qecp->gregs) - sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); + of_iounmap(&op->resource[0], qecp->gregs, GLOB_REG_SIZE); kfree(qecp); return NULL; } -static int __devinit qec_ether_init(struct sbus_dev *sdev) +static int __devinit qec_ether_init(struct of_device *op) { static unsigned version_printed; struct net_device *dev; - struct sunqe *qe; struct sunqec *qecp; + struct sunqe *qe; int i, res; if (version_printed++ == 0) @@ -842,49 +849,42 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) qe = netdev_priv(dev); - i = of_getintprop_default(sdev->ofdev.node, "channel#", -1); - if (i == -1) { - struct sbus_dev *td = sdev->parent->child; - i = 0; - while (td != sdev) { - td = td->next; - i++; - } - } + res = -ENODEV; + + i = of_getintprop_default(op->node, "channel#", -1); + if (i == -1) + goto fail; qe->channel = i; spin_lock_init(&qe->lock); - res = -ENODEV; - qecp = get_qec(sdev); + qecp = get_qec(op); if (!qecp) goto fail; qecp->qes[qe->channel] = qe; qe->dev = dev; qe->parent = qecp; - qe->qe_sdev = sdev; + qe->op = op; res = -ENOMEM; - qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0, - CREG_REG_SIZE, "QEC Channel Registers"); + qe->qcregs = of_ioremap(&op->resource[0], 0, + CREG_REG_SIZE, "QEC Channel Registers"); if (!qe->qcregs) { printk(KERN_ERR "qe: Cannot map channel registers.\n"); goto fail; } - qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0, - MREGS_REG_SIZE, "QE MACE Registers"); + qe->mregs = of_ioremap(&op->resource[1], 0, + MREGS_REG_SIZE, "QE MACE Registers"); if (!qe->mregs) { printk(KERN_ERR "qe: Cannot map MACE registers.\n"); goto fail; } - qe->qe_block = sbus_alloc_consistent(qe->qe_sdev, - PAGE_SIZE, - &qe->qblock_dvma); - qe->buffers = sbus_alloc_consistent(qe->qe_sdev, - sizeof(struct sunqe_buffers), - &qe->buffers_dvma); + qe->qe_block = dma_alloc_coherent(&op->dev, PAGE_SIZE, + &qe->qblock_dvma, GFP_ATOMIC); + qe->buffers = dma_alloc_coherent(&op->dev, sizeof(struct sunqe_buffers), + &qe->buffers_dvma, GFP_ATOMIC); if (qe->qe_block == NULL || qe->qblock_dvma == 0 || qe->buffers == NULL || qe->buffers_dvma == 0) goto fail; @@ -892,7 +892,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) /* Stop this QE. */ qe_stop(qe); - SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); dev->open = qe_open; dev->stop = qe_close; @@ -900,7 +900,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) dev->set_multicast_list = qe_set_multicast; dev->tx_timeout = qe_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->irq = sdev->irqs[0]; + dev->irq = op->irqs[0]; dev->dma = 0; dev->ethtool_ops = &qe_ethtool_ops; @@ -908,7 +908,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) if (res) goto fail; - dev_set_drvdata(&sdev->ofdev.dev, qe); + dev_set_drvdata(&op->dev, qe); printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel); for (i = 0; i < 6; i++) @@ -922,58 +922,50 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) fail: if (qe->qcregs) - sbus_iounmap(qe->qcregs, CREG_REG_SIZE); + of_iounmap(&op->resource[0], qe->qcregs, CREG_REG_SIZE); if (qe->mregs) - sbus_iounmap(qe->mregs, MREGS_REG_SIZE); + of_iounmap(&op->resource[1], qe->mregs, MREGS_REG_SIZE); if (qe->qe_block) - sbus_free_consistent(qe->qe_sdev, - PAGE_SIZE, - qe->qe_block, - qe->qblock_dvma); + dma_free_coherent(&op->dev, PAGE_SIZE, + qe->qe_block, qe->qblock_dvma); if (qe->buffers) - sbus_free_consistent(qe->qe_sdev, - sizeof(struct sunqe_buffers), - qe->buffers, - qe->buffers_dvma); + dma_free_coherent(&op->dev, + sizeof(struct sunqe_buffers), + qe->buffers, + qe->buffers_dvma); free_netdev(dev); return res; } -static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit qec_sbus_probe(struct of_device *op, const struct of_device_id *match) { - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - - return qec_ether_init(sdev); + return qec_ether_init(op); } -static int __devexit qec_sbus_remove(struct of_device *dev) +static int __devexit qec_sbus_remove(struct of_device *op) { - struct sunqe *qp = dev_get_drvdata(&dev->dev); + struct sunqe *qp = dev_get_drvdata(&op->dev); struct net_device *net_dev = qp->dev; unregister_netdev(net_dev); - sbus_iounmap(qp->qcregs, CREG_REG_SIZE); - sbus_iounmap(qp->mregs, MREGS_REG_SIZE); - sbus_free_consistent(qp->qe_sdev, - PAGE_SIZE, - qp->qe_block, - qp->qblock_dvma); - sbus_free_consistent(qp->qe_sdev, - sizeof(struct sunqe_buffers), - qp->buffers, - qp->buffers_dvma); + of_iounmap(&op->resource[0], qp->qcregs, CREG_REG_SIZE); + of_iounmap(&op->resource[1], qp->mregs, MREGS_REG_SIZE); + dma_free_coherent(&op->dev, PAGE_SIZE, + qp->qe_block, qp->qblock_dvma); + dma_free_coherent(&op->dev, sizeof(struct sunqe_buffers), + qp->buffers, qp->buffers_dvma); free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id qec_sbus_match[] = { +static const struct of_device_id qec_sbus_match[] = { { .name = "qe", }, @@ -991,7 +983,7 @@ static struct of_platform_driver qec_sbus_driver = { static int __init qec_init(void) { - return of_register_driver(&qec_sbus_driver, &sbus_bus_type); + return of_register_driver(&qec_sbus_driver, &of_bus_type); } static void __exit qec_exit(void) @@ -1000,11 +992,11 @@ static void __exit qec_exit(void) while (root_qec_dev) { struct sunqec *next = root_qec_dev->next_module; + struct of_device *op = root_qec_dev->op; - free_irq(root_qec_dev->qec_sdev->irqs[0], - (void *) root_qec_dev); - sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE); - + free_irq(op->irqs[0], (void *) root_qec_dev); + of_iounmap(&op->resource[0], root_qec_dev->gregs, + GLOB_REG_SIZE); kfree(root_qec_dev); root_qec_dev = next; diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h index 347c8ddc159..5813a7b2faa 100644 --- a/drivers/net/sunqe.h +++ b/drivers/net/sunqe.h @@ -314,7 +314,7 @@ struct sunqec { void __iomem *gregs; /* QEC Global Registers */ struct sunqe *qes[4]; /* Each child MACE */ unsigned int qec_bursts; /* Support burst sizes */ - struct sbus_dev *qec_sdev; /* QEC's SBUS device */ + struct of_device *op; /* QEC's OF device */ struct sunqec *next_module; /* List of all QECs in system */ }; @@ -342,7 +342,7 @@ struct sunqe { __u32 buffers_dvma; /* DVMA visible address. */ struct sunqec *parent; u8 mconfig; /* Base MACE mconfig value */ - struct sbus_dev *qe_sdev; /* QE's SBUS device struct */ + struct of_device *op; /* QE's OF device struct */ struct net_device *dev; /* QE's netdevice struct */ int channel; /* Who am I? */ }; diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index 6415ce15c2e..a720065553d 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -1,6 +1,6 @@ /* sunvnet.c: Sun LDOM Virtual Network Driver. * - * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> */ #include <linux/module.h> @@ -1260,7 +1260,7 @@ static int vnet_port_remove(struct vio_dev *vdev) return 0; } -static struct vio_device_id vnet_port_match[] = { +static const struct vio_device_id vnet_port_match[] = { { .type = "vnet-port", }, diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 8487ace9d2e..df20cafff7d 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -424,7 +424,7 @@ struct tc35815_local { */ spinlock_t lock; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; struct phy_device *phy_dev; int duplex; int speed; @@ -704,13 +704,13 @@ static int tc_mii_probe(struct net_device *dev) /* find the first phy */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { - if (lp->mii_bus.phy_map[phy_addr]) { + if (lp->mii_bus->phy_map[phy_addr]) { if (phydev) { printk(KERN_ERR "%s: multiple PHYs found\n", dev->name); return -EINVAL; } - phydev = lp->mii_bus.phy_map[phy_addr]; + phydev = lp->mii_bus->phy_map[phy_addr]; break; } } @@ -762,23 +762,29 @@ static int tc_mii_init(struct net_device *dev) int err; int i; - lp->mii_bus.name = "tc35815_mii_bus"; - lp->mii_bus.read = tc_mdio_read; - lp->mii_bus.write = tc_mdio_write; - snprintf(lp->mii_bus.id, MII_BUS_ID_SIZE, "%x", - (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn); - lp->mii_bus.priv = dev; - lp->mii_bus.dev = &lp->pci_dev->dev; - lp->mii_bus.irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); - if (!lp->mii_bus.irq) { + lp->mii_bus = mdiobus_alloc(); + if (lp->mii_bus == NULL) { err = -ENOMEM; goto err_out; } + lp->mii_bus->name = "tc35815_mii_bus"; + lp->mii_bus->read = tc_mdio_read; + lp->mii_bus->write = tc_mdio_write; + snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", + (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn); + lp->mii_bus->priv = dev; + lp->mii_bus->parent = &lp->pci_dev->dev; + lp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!lp->mii_bus->irq) { + err = -ENOMEM; + goto err_out_free_mii_bus; + } + for (i = 0; i < PHY_MAX_ADDR; i++) - lp->mii_bus.irq[i] = PHY_POLL; + lp->mii_bus->irq[i] = PHY_POLL; - err = mdiobus_register(&lp->mii_bus); + err = mdiobus_register(lp->mii_bus); if (err) goto err_out_free_mdio_irq; err = tc_mii_probe(dev); @@ -787,9 +793,11 @@ static int tc_mii_init(struct net_device *dev) return 0; err_out_unregister_bus: - mdiobus_unregister(&lp->mii_bus); + mdiobus_unregister(lp->mii_bus); err_out_free_mdio_irq: - kfree(lp->mii_bus.irq); + kfree(lp->mii_bus->irq); +err_out_free_mii_bus: + mdiobus_free(lp->mii_bus); err_out: return err; } @@ -961,8 +969,9 @@ static void __devexit tc35815_remove_one(struct pci_dev *pdev) struct tc35815_local *lp = netdev_priv(dev); phy_disconnect(lp->phy_dev); - mdiobus_unregister(&lp->mii_bus); - kfree(lp->mii_bus.irq); + mdiobus_unregister(lp->mii_bus); + kfree(lp->mii_bus->irq); + mdiobus_free(lp->mii_bus); unregister_netdev(dev); free_netdev(dev); pci_set_drvdata(pdev, NULL); diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h index 7db48f1cd94..efaf84d9757 100644 --- a/drivers/net/tehuti.h +++ b/drivers/net/tehuti.h @@ -539,22 +539,22 @@ struct txd_desc { #define ERR(fmt, args...) printk(KERN_ERR fmt, ## args) #define DBG2(fmt, args...) \ - printk(KERN_ERR "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args) + printk(KERN_ERR "%s:%-5d: " fmt, __func__, __LINE__, ## args) #define BDX_ASSERT(x) BUG_ON(x) #ifdef DEBUG #define ENTER do { \ - printk(KERN_ERR "%s:%-5d: ENTER\n", __FUNCTION__, __LINE__); \ + printk(KERN_ERR "%s:%-5d: ENTER\n", __func__, __LINE__); \ } while (0) #define RET(args...) do { \ - printk(KERN_ERR "%s:%-5d: RETURN\n", __FUNCTION__, __LINE__); \ + printk(KERN_ERR "%s:%-5d: RETURN\n", __func__, __LINE__); \ return args; } while (0) #define DBG(fmt, args...) \ - printk(KERN_ERR "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args) + printk(KERN_ERR "%s:%-5d: " fmt, __func__, __LINE__, ## args) #else #define ENTER do { } while (0) #define RET(args...) return args diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 71d2c5cfdad..eb9f8f3638e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -876,7 +876,7 @@ static void tg3_mdio_config(struct tg3 *tp) { u32 val; - if (tp->mdio_bus.phy_map[PHY_ADDR]->interface != + if (tp->mdio_bus->phy_map[PHY_ADDR]->interface != PHY_INTERFACE_MODE_RGMII) return; @@ -920,9 +920,9 @@ static void tg3_mdio_config(struct tg3 *tp) static void tg3_mdio_start(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { - mutex_lock(&tp->mdio_bus.mdio_lock); + mutex_lock(&tp->mdio_bus->mdio_lock); tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED; - mutex_unlock(&tp->mdio_bus.mdio_lock); + mutex_unlock(&tp->mdio_bus->mdio_lock); } tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; @@ -936,9 +936,9 @@ static void tg3_mdio_start(struct tg3 *tp) static void tg3_mdio_stop(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { - mutex_lock(&tp->mdio_bus.mdio_lock); + mutex_lock(&tp->mdio_bus->mdio_lock); tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED; - mutex_unlock(&tp->mdio_bus.mdio_lock); + mutex_unlock(&tp->mdio_bus->mdio_lock); } } @@ -947,7 +947,6 @@ static int tg3_mdio_init(struct tg3 *tp) int i; u32 reg; struct phy_device *phydev; - struct mii_bus *mdio_bus = &tp->mdio_bus; tg3_mdio_start(tp); @@ -955,21 +954,23 @@ static int tg3_mdio_init(struct tg3 *tp) (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)) return 0; - memset(mdio_bus, 0, sizeof(*mdio_bus)); + tp->mdio_bus = mdiobus_alloc(); + if (tp->mdio_bus == NULL) + return -ENOMEM; - mdio_bus->name = "tg3 mdio bus"; - snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x", + tp->mdio_bus->name = "tg3 mdio bus"; + snprintf(tp->mdio_bus->id, MII_BUS_ID_SIZE, "%x", (tp->pdev->bus->number << 8) | tp->pdev->devfn); - mdio_bus->priv = tp; - mdio_bus->dev = &tp->pdev->dev; - mdio_bus->read = &tg3_mdio_read; - mdio_bus->write = &tg3_mdio_write; - mdio_bus->reset = &tg3_mdio_reset; - mdio_bus->phy_mask = ~(1 << PHY_ADDR); - mdio_bus->irq = &tp->mdio_irq[0]; + tp->mdio_bus->priv = tp; + tp->mdio_bus->parent = &tp->pdev->dev; + tp->mdio_bus->read = &tg3_mdio_read; + tp->mdio_bus->write = &tg3_mdio_write; + tp->mdio_bus->reset = &tg3_mdio_reset; + tp->mdio_bus->phy_mask = ~(1 << PHY_ADDR); + tp->mdio_bus->irq = &tp->mdio_irq[0]; for (i = 0; i < PHY_MAX_ADDR; i++) - mdio_bus->irq[i] = PHY_POLL; + tp->mdio_bus->irq[i] = PHY_POLL; /* The bus registration will look for all the PHYs on the mdio bus. * Unfortunately, it does not ensure the PHY is powered up before @@ -979,7 +980,7 @@ static int tg3_mdio_init(struct tg3 *tp) if (tg3_readphy(tp, MII_BMCR, ®) || (reg & BMCR_PDOWN)) tg3_bmcr_reset(tp); - i = mdiobus_register(mdio_bus); + i = mdiobus_register(tp->mdio_bus); if (i) { printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n", tp->dev->name, i); @@ -988,7 +989,7 @@ static int tg3_mdio_init(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; switch (phydev->phy_id) { case TG3_PHY_ID_BCM50610: @@ -1014,7 +1015,8 @@ static void tg3_mdio_fini(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED; - mdiobus_unregister(&tp->mdio_bus); + mdiobus_unregister(tp->mdio_bus); + mdiobus_free(tp->mdio_bus); tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED; } } @@ -1220,7 +1222,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) u32 old_tx_mode = tp->tx_mode; if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) - autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg; + autoneg = tp->mdio_bus->phy_map[PHY_ADDR]->autoneg; else autoneg = tp->link_config.autoneg; @@ -1257,7 +1259,7 @@ static void tg3_adjust_link(struct net_device *dev) u8 oldflowctrl, linkmesg = 0; u32 mac_mode, lcl_adv, rmt_adv; struct tg3 *tp = netdev_priv(dev); - struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + struct phy_device *phydev = tp->mdio_bus->phy_map[PHY_ADDR]; spin_lock(&tp->lock); @@ -1334,7 +1336,7 @@ static int tg3_phy_init(struct tg3 *tp) /* Bring the PHY back to a known state. */ tg3_bmcr_reset(tp); - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; /* Attach the MAC to the PHY. */ phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link, @@ -1367,7 +1369,7 @@ static void tg3_phy_start(struct tg3 *tp) if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return; - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; if (tp->link_config.phy_is_low_power) { tp->link_config.phy_is_low_power = 0; @@ -1387,13 +1389,13 @@ static void tg3_phy_stop(struct tg3 *tp) if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return; - phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]); + phy_stop(tp->mdio_bus->phy_map[PHY_ADDR]); } static void tg3_phy_fini(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) { - phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]); + phy_disconnect(tp->mdio_bus->phy_map[PHY_ADDR]); tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED; } } @@ -2049,7 +2051,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) struct phy_device *phydev; u32 advertising; - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; tp->link_config.phy_is_low_power = 1; @@ -3861,10 +3863,7 @@ static void tg3_tx(struct tg3 *tp) return; } - pci_unmap_single(tp->pdev, - pci_unmap_addr(ri, mapping), - skb_headlen(skb), - PCI_DMA_TODEVICE); + skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); ri->skb = NULL; @@ -3874,12 +3873,6 @@ static void tg3_tx(struct tg3 *tp) ri = &tp->tx_buffers[sw_idx]; if (unlikely(ri->skb != NULL || sw_idx == hw_idx)) tx_bug = 1; - - pci_unmap_page(tp->pdev, - pci_unmap_addr(ri, mapping), - skb_shinfo(skb)->frags[i].size, - PCI_DMA_TODEVICE); - sw_idx = NEXT_TX(sw_idx); } @@ -4633,12 +4626,16 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, } else { /* New SKB is guaranteed to be linear. */ entry = *start; - new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, - PCI_DMA_TODEVICE); + ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE); + new_addr = skb_shinfo(new_skb)->dma_maps[0]; + /* Make sure new skb does not cross any 4G boundaries. * Drop the packet if it does. */ - if (tg3_4g_overflow_test(new_addr, new_skb->len)) { + if (ret || tg3_4g_overflow_test(new_addr, new_skb->len)) { + if (!ret) + skb_dma_unmap(&tp->pdev->dev, new_skb, + DMA_TO_DEVICE); ret = -1; dev_kfree_skb(new_skb); new_skb = NULL; @@ -4652,18 +4649,8 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, /* Now clean up the sw ring entries. */ i = 0; while (entry != last_plus_one) { - int len; - - if (i == 0) - len = skb_headlen(skb); - else - len = skb_shinfo(skb)->frags[i-1].size; - pci_unmap_single(tp->pdev, - pci_unmap_addr(&tp->tx_buffers[entry], mapping), - len, PCI_DMA_TODEVICE); if (i == 0) { tp->tx_buffers[entry].skb = new_skb; - pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, new_addr); } else { tp->tx_buffers[entry].skb = NULL; } @@ -4671,6 +4658,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, i++; } + skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); dev_kfree_skb(skb); return ret; @@ -4705,8 +4693,9 @@ static void tg3_set_txd(struct tg3 *tp, int entry, static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - dma_addr_t mapping; u32 len, entry, base_flags, mss; + struct skb_shared_info *sp; + dma_addr_t mapping; len = skb_headlen(skb); @@ -4765,11 +4754,16 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) (vlan_tx_tag_get(skb) << 16)); #endif - /* Queue skb data, a.k.a. the main skb fragment. */ - mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); + if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) { + dev_kfree_skb(skb); + goto out_unlock; + } + + sp = skb_shinfo(skb); + + mapping = sp->dma_maps[0]; tp->tx_buffers[entry].skb = skb; - pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); tg3_set_txd(tp, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); @@ -4785,13 +4779,8 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = pci_map_page(tp->pdev, - frag->page, - frag->page_offset, - len, PCI_DMA_TODEVICE); - + mapping = sp->dma_maps[i + 1]; tp->tx_buffers[entry].skb = NULL; - pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); tg3_set_txd(tp, entry, mapping, len, base_flags, (i == last) | (mss << 1)); @@ -4859,9 +4848,10 @@ tg3_tso_bug_end: static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - dma_addr_t mapping; u32 len, entry, base_flags, mss; + struct skb_shared_info *sp; int would_hit_hwbug; + dma_addr_t mapping; len = skb_headlen(skb); @@ -4942,11 +4932,16 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) (vlan_tx_tag_get(skb) << 16)); #endif - /* Queue skb data, a.k.a. the main skb fragment. */ - mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); + if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) { + dev_kfree_skb(skb); + goto out_unlock; + } + + sp = skb_shinfo(skb); + + mapping = sp->dma_maps[0]; tp->tx_buffers[entry].skb = skb; - pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); would_hit_hwbug = 0; @@ -4969,13 +4964,9 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = pci_map_page(tp->pdev, - frag->page, - frag->page_offset, - len, PCI_DMA_TODEVICE); + mapping = sp->dma_maps[i + 1]; tp->tx_buffers[entry].skb = NULL; - pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); if (tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; @@ -5128,7 +5119,6 @@ static void tg3_free_rings(struct tg3 *tp) for (i = 0; i < TG3_TX_RING_SIZE; ) { struct tx_ring_info *txp; struct sk_buff *skb; - int j; txp = &tp->tx_buffers[i]; skb = txp->skb; @@ -5138,22 +5128,11 @@ static void tg3_free_rings(struct tg3 *tp) continue; } - pci_unmap_single(tp->pdev, - pci_unmap_addr(txp, mapping), - skb_headlen(skb), - PCI_DMA_TODEVICE); - txp->skb = NULL; + skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); - i++; + txp->skb = NULL; - for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) { - txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)]; - pci_unmap_page(tp->pdev, - pci_unmap_addr(txp, mapping), - skb_shinfo(skb)->frags[j].size, - PCI_DMA_TODEVICE); - i++; - } + i += skb_shinfo(skb)->nr_frags + 1; dev_kfree_skb_any(skb); } @@ -8977,7 +8956,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return -EAGAIN; - return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); + return phy_ethtool_gset(tp->mdio_bus->phy_map[PHY_ADDR], cmd); } cmd->supported = (SUPPORTED_Autoneg); @@ -9018,7 +8997,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return -EAGAIN; - return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); + return phy_ethtool_sset(tp->mdio_bus->phy_map[PHY_ADDR], cmd); } if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { @@ -9166,7 +9145,7 @@ static int tg3_nway_reset(struct net_device *dev) if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return -EAGAIN; - r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]); + r = phy_start_aneg(tp->mdio_bus->phy_map[PHY_ADDR]); } else { u32 bmcr; @@ -9283,7 +9262,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam u32 newadv; struct phy_device *phydev; - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; if (epause->rx_pause) { if (epause->tx_pause) @@ -10265,7 +10244,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return -EAGAIN; - return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd); + return phy_mii_ioctl(tp->mdio_bus->phy_map[PHY_ADDR], data, cmd); } switch(cmd) { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index f5b8cab8d4b..be252abe898 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2197,7 +2197,6 @@ struct ring_info { struct tx_ring_info { struct sk_buff *skb; - DECLARE_PCI_UNMAP_ADDR(mapping) u32 prev_vlan_tag; }; @@ -2557,7 +2556,7 @@ struct tg3 { int msi_cap; int pcix_cap; - struct mii_bus mdio_bus; + struct mii_bus *mdio_bus; int mdio_irq[PHY_MAX_ADDR]; /* PHY info */ diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index ec871f64676..c41d6876136 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -29,7 +29,8 @@ * * Tigran Aivazian <tigran@sco.com>: TLan_PciProbe() now uses * new PCI BIOS interface. - * Alan Cox <alan@redhat.com>: Fixed the out of memory + * Alan Cox <alan@lxorguk.ukuu.org.uk>: + * Fixed the out of memory * handling. * * Torben Mathiasen <torben.mathiasen@compaq.com> New Maintainer! diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index fa73e6eed6b..ed50d288e49 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -25,7 +25,7 @@ * To do: * 1. Multicast support. * - * Initial 2.5 cleanup Alan Cox <alan@redhat.com> 2002/10/28 + * Initial 2.5 cleanup Alan Cox <alan@lxorguk.ukuu.org.uk> 2002/10/28 */ #include <linux/module.h> diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 43fde99b24a..eb1da6f0b08 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -263,7 +263,7 @@ static inline void tsi108_write_tbi(struct tsi108_prv_data *data, return; udelay(10); } - printk(KERN_ERR "%s function time out \n", __FUNCTION__); + printk(KERN_ERR "%s function time out \n", __func__); } static int mii_speed(struct mii_if_info *mii) @@ -1059,7 +1059,7 @@ static void tsi108_stop_ethernet(struct net_device *dev) return; udelay(10); } - printk(KERN_ERR "%s function time out \n", __FUNCTION__); + printk(KERN_ERR "%s function time out \n", __func__); } static void tsi108_reset_ether(struct tsi108_prv_data * data) @@ -1244,7 +1244,7 @@ static void tsi108_init_phy(struct net_device *dev) udelay(10); } if (i == 0) - printk(KERN_ERR "%s function time out \n", __FUNCTION__); + printk(KERN_ERR "%s function time out \n", __func__); if (data->phy_type == TSI108_PHY_BCM54XX) { tsi108_write_mii(data, 0x09, 0x0300); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 9281d06d5aa..124d5d690dd 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1418,7 +1418,6 @@ static int de_close (struct net_device *dev) de_free_rings(de); de_adapter_sleep(de); - pci_disable_device(de->pdev); return 0; } @@ -1689,6 +1688,7 @@ static void __devinit de21040_get_mac_address (struct de_private *de) unsigned i; dw32 (ROMCmd, 0); /* Reset the pointer with a dummy write. */ + udelay(5); for (i = 0; i < 6; i++) { int value, boguscnt = 100000; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 617ef41bdfe..6444cbec0bd 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -832,7 +832,7 @@ struct de4x5_private { s32 csr14; /* Saved SIA TX/RX Register */ s32 csr15; /* Saved SIA General Register */ int save_cnt; /* Flag if state already saved */ - struct sk_buff *skb; /* Save the (re-ordered) skb's */ + struct sk_buff_head queue; /* Save the (re-ordered) skb's */ } cache; struct de4x5_srom srom; /* A copy of the SROM */ int cfrv; /* Card CFRV copy */ @@ -1128,6 +1128,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) printk(" which has an Ethernet PROM CRC error.\n"); return -ENXIO; } else { + skb_queue_head_init(&lp->cache.queue); lp->cache.gepc = GEP_INIT; lp->asBit = GEP_SLNK; lp->asPolarity = GEP_SLNK; @@ -1487,7 +1488,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) } } else if (skb->len > 0) { /* If we already have stuff queued locally, use that first */ - if (lp->cache.skb && !lp->interrupt) { + if (!skb_queue_empty(&lp->cache.queue) && !lp->interrupt) { de4x5_put_cache(dev, skb); skb = de4x5_get_cache(dev); } @@ -1580,7 +1581,7 @@ de4x5_interrupt(int irq, void *dev_id) /* Load the TX ring with any locally stored packets */ if (!test_and_set_bit(0, (void *)&lp->cache.lock)) { - while (lp->cache.skb && !netif_queue_stopped(dev) && lp->tx_enable) { + while (!skb_queue_empty(&lp->cache.queue) && !netif_queue_stopped(dev) && lp->tx_enable) { de4x5_queue_pkt(de4x5_get_cache(dev), dev); } lp->cache.lock = 0; @@ -3679,11 +3680,7 @@ de4x5_free_tx_buffs(struct net_device *dev) } /* Unload the locally queued packets */ - while (lp->cache.skb) { - dev_kfree_skb(de4x5_get_cache(dev)); - } - - return; + __skb_queue_purge(&lp->cache.queue); } /* @@ -3781,43 +3778,24 @@ static void de4x5_put_cache(struct net_device *dev, struct sk_buff *skb) { struct de4x5_private *lp = netdev_priv(dev); - struct sk_buff *p; - - if (lp->cache.skb) { - for (p=lp->cache.skb; p->next; p=p->next); - p->next = skb; - } else { - lp->cache.skb = skb; - } - skb->next = NULL; - return; + __skb_queue_tail(&lp->cache.queue, skb); } static void de4x5_putb_cache(struct net_device *dev, struct sk_buff *skb) { struct de4x5_private *lp = netdev_priv(dev); - struct sk_buff *p = lp->cache.skb; - - lp->cache.skb = skb; - skb->next = p; - return; + __skb_queue_head(&lp->cache.queue, skb); } static struct sk_buff * de4x5_get_cache(struct net_device *dev) { struct de4x5_private *lp = netdev_priv(dev); - struct sk_buff *p = lp->cache.skb; - if (p) { - lp->cache.skb = p->next; - p->next = NULL; - } - - return p; + return __skb_dequeue(&lp->cache.queue); } /* diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 656200472fa..8e46a513a25 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -23,7 +23,7 @@ Marcelo Tosatti <marcelo@conectiva.com.br> : Made it compile in 2.3 (device to net_device) - Alan Cox <alan@redhat.com> : + Alan Cox <alan@lxorguk.ukuu.org.uk> : Cleaned up for kernel merge. Removed the back compatibility support Reformatted, fixing spelling etc as I went @@ -49,7 +49,7 @@ support. Updated PCI resource allocation. Do not forget to unmap PCI mapped skbs. - Alan Cox <alan@redhat.com> + Alan Cox <alan@lxorguk.ukuu.org.uk> Added new PCI identifiers provided by Clear Zhang at ALi for their 1563 ethernet device. diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 8f944e57fd5..c87747bb24c 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -400,7 +400,7 @@ static struct enet_addr_container *get_enet_addr_container(void) enet_addr_cont = kmalloc(sizeof(struct enet_addr_container), GFP_KERNEL); if (!enet_addr_cont) { ugeth_err("%s: No memory for enet_addr_container object.", - __FUNCTION__); + __func__); return NULL; } @@ -427,7 +427,7 @@ static int hw_add_addr_in_paddr(struct ucc_geth_private *ugeth, struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; if (!(paddr_num < NUM_OF_PADDRS)) { - ugeth_warn("%s: Illegal paddr_num.", __FUNCTION__); + ugeth_warn("%s: Illegal paddr_num.", __func__); return -EINVAL; } @@ -447,7 +447,7 @@ static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num) struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt; if (!(paddr_num < NUM_OF_PADDRS)) { - ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__); + ugeth_warn("%s: Illagel paddr_num.", __func__); return -EINVAL; } @@ -1441,7 +1441,7 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) u32 upsmr, maccfg2, tbiBaseAddress; u16 value; - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); ug_info = ugeth->ug_info; ug_regs = ugeth->ug_regs; @@ -1504,7 +1504,7 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) if (ret_val != 0) { if (netif_msg_probe(ugeth)) ugeth_err("%s: Preamble length must be between 3 and 7 inclusive.", - __FUNCTION__); + __func__); return ret_val; } @@ -1744,7 +1744,7 @@ static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode) /* check if the UCC number is in range. */ if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { if (netif_msg_probe(ugeth)) - ugeth_err("%s: ucc_num out of range.", __FUNCTION__); + ugeth_err("%s: ucc_num out of range.", __func__); return -EINVAL; } @@ -1773,7 +1773,7 @@ static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode) /* check if the UCC number is in range. */ if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { if (netif_msg_probe(ugeth)) - ugeth_err("%s: ucc_num out of range.", __FUNCTION__); + ugeth_err("%s: ucc_num out of range.", __func__); return -EINVAL; } @@ -2062,7 +2062,7 @@ static int ugeth_82xx_filtering_add_addr_in_paddr(struct ucc_geth_private *ugeth ugeth_warn ("%s: multicast address added to paddr will have no " "effect - is this what you wanted?", - __FUNCTION__); + __func__); ugeth->indAddrRegUsed[paddr_num] = 1; /* mark this paddr as used */ /* store address in our database */ @@ -2278,7 +2278,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) struct phy_device *phydev = ugeth->phydev; u32 tempval; - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); /* Disable the controller */ ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); @@ -2315,7 +2315,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) (uf_info->bd_mem_part == MEM_PART_MURAM))) { if (netif_msg_probe(ugeth)) ugeth_err("%s: Bad memory partition value.", - __FUNCTION__); + __func__); return -EINVAL; } @@ -2327,7 +2327,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) if (netif_msg_probe(ugeth)) ugeth_err ("%s: Rx BD ring length must be multiple of 4, no smaller than 8.", - __FUNCTION__); + __func__); return -EINVAL; } } @@ -2338,7 +2338,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) if (netif_msg_probe(ugeth)) ugeth_err ("%s: Tx BD ring length must be no smaller than 2.", - __FUNCTION__); + __func__); return -EINVAL; } } @@ -2349,21 +2349,21 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) if (netif_msg_probe(ugeth)) ugeth_err ("%s: max_rx_buf_length must be non-zero multiple of 128.", - __FUNCTION__); + __func__); return -EINVAL; } /* num Tx queues */ if (ug_info->numQueuesTx > NUM_TX_QUEUES) { if (netif_msg_probe(ugeth)) - ugeth_err("%s: number of tx queues too large.", __FUNCTION__); + ugeth_err("%s: number of tx queues too large.", __func__); return -EINVAL; } /* num Rx queues */ if (ug_info->numQueuesRx > NUM_RX_QUEUES) { if (netif_msg_probe(ugeth)) - ugeth_err("%s: number of rx queues too large.", __FUNCTION__); + ugeth_err("%s: number of rx queues too large.", __func__); return -EINVAL; } @@ -2374,7 +2374,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) ugeth_err ("%s: VLAN priority table entry must not be" " larger than number of Rx queues.", - __FUNCTION__); + __func__); return -EINVAL; } } @@ -2386,7 +2386,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) ugeth_err ("%s: IP priority table entry must not be" " larger than number of Rx queues.", - __FUNCTION__); + __func__); return -EINVAL; } } @@ -2394,7 +2394,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) if (ug_info->cam && !ug_info->ecamptr) { if (netif_msg_probe(ugeth)) ugeth_err("%s: If cam mode is chosen, must supply cam ptr.", - __FUNCTION__); + __func__); return -EINVAL; } @@ -2404,7 +2404,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) if (netif_msg_probe(ugeth)) ugeth_err("%s: Number of station addresses greater than 1 " "not allowed in extended parsing mode.", - __FUNCTION__); + __func__); return -EINVAL; } @@ -2418,7 +2418,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) /* Initialize the general fast UCC block. */ if (ucc_fast_init(uf_info, &ugeth->uccf)) { if (netif_msg_probe(ugeth)) - ugeth_err("%s: Failed to init uccf.", __FUNCTION__); + ugeth_err("%s: Failed to init uccf.", __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2448,7 +2448,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) u8 __iomem *endOfRing; u8 numThreadsRxNumerical, numThreadsTxNumerical; - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); uccf = ugeth->uccf; ug_info = ugeth->ug_info; uf_info = &ug_info->uf_info; @@ -2474,7 +2474,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) default: if (netif_msg_ifup(ugeth)) ugeth_err("%s: Bad number of Rx threads value.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -EINVAL; break; @@ -2499,7 +2499,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) default: if (netif_msg_ifup(ugeth)) ugeth_err("%s: Bad number of Tx threads value.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -EINVAL; break; @@ -2553,7 +2553,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (ret_val != 0) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: IPGIFG initialization parameter too large.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return ret_val; } @@ -2571,7 +2571,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (ret_val != 0) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Half Duplex initialization parameter too large.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return ret_val; } @@ -2626,7 +2626,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate memory for Tx bd rings.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2662,7 +2662,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate memory for Rx bd rings.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2678,7 +2678,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (ugeth->tx_skbuff[j] == NULL) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Could not allocate tx_skbuff", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2710,7 +2710,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (ugeth->rx_skbuff[j] == NULL) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Could not allocate rx_skbuff", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2744,7 +2744,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2767,7 +2767,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for p_thread_data_tx.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2797,7 +2797,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2841,7 +2841,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for p_scheduler.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2892,7 +2892,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for" " p_tx_fw_statistics_pram.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2932,7 +2932,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2954,7 +2954,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for p_thread_data_rx.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2978,7 +2978,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for" - " p_rx_fw_statistics_pram.", __FUNCTION__); + " p_rx_fw_statistics_pram.", __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3001,7 +3001,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for" - " p_rx_irq_coalescing_tbl.", __FUNCTION__); + " p_rx_irq_coalescing_tbl.", __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3070,7 +3070,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3147,7 +3147,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (!ug_info->extendedFilteringChainPointer) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Null Extended Filtering Chain Pointer.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -EINVAL; } @@ -3161,7 +3161,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for" - " p_exf_glbl_param.", __FUNCTION__); + " p_exf_glbl_param.", __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3209,7 +3209,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate memory for" - " p_UccInitEnetParamShadows.", __FUNCTION__); + " p_UccInitEnetParamShadows.", __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3244,7 +3244,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Invalid largest External Lookup Key Size.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -EINVAL; } @@ -3271,7 +3271,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ug_info->riscRx, 1)) != 0) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Can not fill p_init_enet_param_shadow.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return ret_val; } @@ -3287,7 +3287,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ug_info->riscTx, 0)) != 0) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Can not fill p_init_enet_param_shadow.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return ret_val; } @@ -3297,7 +3297,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Can not fill Rx bds with buffers.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return ret_val; } @@ -3309,7 +3309,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err ("%s: Can not allocate DPRAM memory for p_init_enet_pram.", - __FUNCTION__); + __func__); ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3360,7 +3360,7 @@ static void ucc_geth_timeout(struct net_device *dev) { struct ucc_geth_private *ugeth = netdev_priv(dev); - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); dev->stats.tx_errors++; @@ -3386,7 +3386,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 bd_status; u8 txQ = 0; - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); spin_lock_irq(&ugeth->lock); @@ -3459,7 +3459,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit u8 *bdBuffer; struct net_device *dev; - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); dev = ugeth->dev; @@ -3481,7 +3481,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit (bd_status & R_ERRORS_FATAL)) { if (netif_msg_rx_err(ugeth)) ugeth_err("%s, %d: ERROR!!! skb - 0x%08x", - __FUNCTION__, __LINE__, (u32) skb); + __func__, __LINE__, (u32) skb); if (skb) dev_kfree_skb_any(skb); @@ -3507,7 +3507,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit skb = get_new_skb(ugeth, bd); if (!skb) { if (netif_msg_rx_err(ugeth)) - ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); + ugeth_warn("%s: No Rx Data Buffer", __func__); dev->stats.rx_dropped++; break; } @@ -3613,7 +3613,7 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) register u32 tx_mask; u8 i; - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); uccf = ugeth->uccf; ug_info = ugeth->ug_info; @@ -3683,13 +3683,13 @@ static int ucc_geth_open(struct net_device *dev) struct ucc_geth_private *ugeth = netdev_priv(dev); int err; - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); /* Test station address */ if (dev->dev_addr[0] & ENET_GROUP_ADDR) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Multicast address used for station address" - " - is this what you wanted?", __FUNCTION__); + " - is this what you wanted?", __func__); return -EINVAL; } @@ -3772,7 +3772,7 @@ static int ucc_geth_close(struct net_device *dev) { struct ucc_geth_private *ugeth = netdev_priv(dev); - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); napi_disable(&ugeth->napi); @@ -3840,7 +3840,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, }; - ugeth_vdbg("%s: IN", __FUNCTION__); + ugeth_vdbg("%s: IN", __func__); prop = of_get_property(np, "cell-index", NULL); if (!prop) { @@ -3857,7 +3857,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma if (ug_info == NULL) { if (netif_msg_probe(&debug)) ugeth_err("%s: [%d] Missing additional data!", - __FUNCTION__, ucc_num); + __func__, ucc_num); return -ENODEV; } diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c index 6d9e7ad9fda..c001d261366 100644 --- a/drivers/net/ucc_geth_mii.c +++ b/drivers/net/ucc_geth_mii.c @@ -141,8 +141,7 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma struct resource res; int k, err = 0; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - + new_bus = mdiobus_alloc(); if (NULL == new_bus) return -ENOMEM; @@ -187,7 +186,7 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma new_bus->priv = (void __force *)regs; - new_bus->dev = device; + new_bus->parent = device; dev_set_drvdata(device, new_bus); /* Read MII management master from device tree */ @@ -235,7 +234,7 @@ bus_register_fail: ioremap_fail: kfree(new_bus->irq); reg_map_fail: - kfree(new_bus); + mdiobus_free(new_bus); return err; } @@ -251,7 +250,7 @@ static int uec_mdio_remove(struct of_device *ofdev) iounmap((void __iomem *)bus->priv); bus->priv = NULL; - kfree(bus); + mdiobus_free(bus); return 0; } diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 0973b6e3702..8ee21030e9a 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -188,6 +188,14 @@ config USB_NET_DM9601 This option adds support for Davicom DM9601 based USB 1.1 10/100 Ethernet adapters. +config USB_NET_SMSC95XX + tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices" + depends on USB_USBNET + select CRC32 + help + This option adds support for SMSC LAN95XX based USB 2.0 + 10/100 Ethernet adapters. + config USB_NET_GL620A tristate "GeneSys GL620USB-A based cables" depends on USB_USBNET diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index 24800c157f9..88a87eeb376 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_USB_HSO) += hso.o obj-$(CONFIG_USB_NET_AX8817X) += asix.o obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o obj-$(CONFIG_USB_NET_DM9601) += dm9601.o +obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o obj-$(CONFIG_USB_NET_NET1080) += net1080.o obj-$(CONFIG_USB_NET_PLUSB) += plusb.o @@ -19,6 +20,3 @@ obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o obj-$(CONFIG_USB_USBNET) += usbnet.o -ifeq ($(CONFIG_USB_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 22c17bbacb6..466a89e2444 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -456,7 +456,7 @@ static void catc_tx_timeout(struct net_device *netdev) { struct catc *catc = netdev_priv(netdev); - warn("Transmit timed out."); + dev_warn(&netdev->dev, "Transmit timed out.\n"); usb_unlink_urb(catc->tx_urb); } @@ -847,7 +847,8 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id dbg("64k Memory\n"); break; default: - warn("Couldn't detect memory size, assuming 32k"); + dev_warn(&intf->dev, + "Couldn't detect memory size, assuming 32k\n"); case 0x87654321: catc_set_reg(catc, TxBufCount, 4); catc_set_reg(catc, RxBufCount, 16); @@ -953,7 +954,8 @@ static int __init catc_init(void) { int result = usb_register(&catc_driver); if (result == 0) - info(DRIVER_VERSION " " DRIVER_DESC); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); return result; } diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 6e42b5a8c22..1164c52e2c0 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -92,9 +92,6 @@ #define HSO_NET_TX_TIMEOUT (HZ*10) -/* Serial port defines and structs. */ -#define HSO_SERIAL_FLAG_RX_SENT 0 - #define HSO_SERIAL_MAGIC 0x48534f31 /* Number of ttys to handle */ @@ -179,6 +176,12 @@ struct hso_net { unsigned long flags; }; +enum rx_ctrl_state{ + RX_IDLE, + RX_SENT, + RX_PENDING +}; + struct hso_serial { struct hso_device *parent; int magic; @@ -205,7 +208,7 @@ struct hso_serial { struct usb_endpoint_descriptor *in_endp; struct usb_endpoint_descriptor *out_endp; - unsigned long flags; + enum rx_ctrl_state rx_state; u8 rts_state; u8 dtr_state; unsigned tx_urb_used:1; @@ -216,6 +219,15 @@ struct hso_serial { spinlock_t serial_lock; int (*write_data) (struct hso_serial *serial); + /* Hacks required to get flow control + * working on the serial receive buffers + * so as not to drop characters on the floor. + */ + int curr_rx_urb_idx; + u16 curr_rx_urb_offset; + u8 rx_urb_filled[MAX_RX_URBS]; + struct tasklet_struct unthrottle_tasklet; + struct work_struct retry_unthrottle_workqueue; }; struct hso_device { @@ -271,7 +283,7 @@ struct hso_device { static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static void ctrl_callback(struct urb *urb); -static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial); +static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial); static void hso_kick_transmit(struct hso_serial *serial); /* Helper functions */ static int hso_mux_submit_intr_urb(struct hso_shared_int *mux_int, @@ -287,6 +299,8 @@ static int hso_start_net_device(struct hso_device *hso_dev); static void hso_free_shared_int(struct hso_shared_int *shared_int); static int hso_stop_net_device(struct hso_device *hso_dev); static void hso_serial_ref_free(struct kref *ref); +static void hso_std_serial_read_bulk_callback(struct urb *urb); +static int hso_mux_serial_read(struct hso_serial *serial); static void async_get_intf(struct work_struct *data); static void async_put_intf(struct work_struct *data); static int hso_put_activity(struct hso_device *hso_dev); @@ -458,6 +472,17 @@ static ssize_t hso_sysfs_show_porttype(struct device *dev, } static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); +static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) +{ + int idx; + + for (idx = 0; idx < serial->num_rx_urbs; idx++) + if (serial->rx_urb[idx] == urb) + return idx; + dev_err(serial->parent->dev, "hso_urb_to_index failed\n"); + return -1; +} + /* converts mux value to a port spec value */ static u32 hso_mux_to_port(int mux) { @@ -1039,6 +1064,158 @@ static void _hso_serial_set_termios(struct tty_struct *tty, return; } +static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb) +{ + int result; +#ifdef CONFIG_HSO_AUTOPM + usb_mark_last_busy(urb->dev); +#endif + /* We are done with this URB, resubmit it. Prep the USB to wait for + * another frame */ + usb_fill_bulk_urb(urb, serial->parent->usb, + usb_rcvbulkpipe(serial->parent->usb, + serial->in_endp-> + bEndpointAddress & 0x7F), + urb->transfer_buffer, serial->rx_data_length, + hso_std_serial_read_bulk_callback, serial); + /* Give this to the USB subsystem so it can tell us when more data + * arrives. */ + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) { + dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d\n", + __func__, result); + } +} + + + + +static void put_rxbuf_data_and_resubmit_bulk_urb(struct hso_serial *serial) +{ + int count; + struct urb *curr_urb; + + while (serial->rx_urb_filled[serial->curr_rx_urb_idx]) { + curr_urb = serial->rx_urb[serial->curr_rx_urb_idx]; + count = put_rxbuf_data(curr_urb, serial); + if (count == -1) + return; + if (count == 0) { + serial->curr_rx_urb_idx++; + if (serial->curr_rx_urb_idx >= serial->num_rx_urbs) + serial->curr_rx_urb_idx = 0; + hso_resubmit_rx_bulk_urb(serial, curr_urb); + } + } +} + +static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial) +{ + int count = 0; + struct urb *urb; + + urb = serial->rx_urb[0]; + if (serial->open_count > 0) { + count = put_rxbuf_data(urb, serial); + if (count == -1) + return; + } + /* Re issue a read as long as we receive data. */ + + if (count == 0 && ((urb->actual_length != 0) || + (serial->rx_state == RX_PENDING))) { + serial->rx_state = RX_SENT; + hso_mux_serial_read(serial); + } else + serial->rx_state = RX_IDLE; +} + + +/* read callback for Diag and CS port */ +static void hso_std_serial_read_bulk_callback(struct urb *urb) +{ + struct hso_serial *serial = urb->context; + int status = urb->status; + + /* sanity check */ + if (!serial) { + D1("serial == NULL"); + return; + } else if (status) { + log_usb_status(status, __func__); + return; + } + + D4("\n--- Got serial_read_bulk callback %02x ---", status); + D1("Actual length = %d\n", urb->actual_length); + DUMP1(urb->transfer_buffer, urb->actual_length); + + /* Anyone listening? */ + if (serial->open_count == 0) + return; + + if (status == 0) { + if (serial->parent->port_spec & HSO_INFO_CRC_BUG) { + u32 rest; + u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; + rest = + urb->actual_length % + serial->in_endp->wMaxPacketSize; + if (((rest == 5) || (rest == 6)) + && !memcmp(((u8 *) urb->transfer_buffer) + + urb->actual_length - 4, crc_check, 4)) { + urb->actual_length -= 4; + } + } + /* Valid data, handle RX data */ + spin_lock(&serial->serial_lock); + serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; + put_rxbuf_data_and_resubmit_bulk_urb(serial); + spin_unlock(&serial->serial_lock); + } else if (status == -ENOENT || status == -ECONNRESET) { + /* Unlinked - check for throttled port. */ + D2("Port %d, successfully unlinked urb", serial->minor); + spin_lock(&serial->serial_lock); + serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; + hso_resubmit_rx_bulk_urb(serial, urb); + spin_unlock(&serial->serial_lock); + } else { + D2("Port %d, status = %d for read urb", serial->minor, status); + return; + } +} + +/* + * This needs to be a tasklet otherwise we will + * end up recursively calling this function. + */ +void hso_unthrottle_tasklet(struct hso_serial *serial) +{ + unsigned long flags; + + spin_lock_irqsave(&serial->serial_lock, flags); + if ((serial->parent->port_spec & HSO_INTF_MUX)) + put_rxbuf_data_and_resubmit_ctrl_urb(serial); + else + put_rxbuf_data_and_resubmit_bulk_urb(serial); + spin_unlock_irqrestore(&serial->serial_lock, flags); +} + +static void hso_unthrottle(struct tty_struct *tty) +{ + struct hso_serial *serial = get_serial_by_tty(tty); + + tasklet_hi_schedule(&serial->unthrottle_tasklet); +} + +void hso_unthrottle_workfunc(struct work_struct *work) +{ + struct hso_serial *serial = + container_of(work, struct hso_serial, + retry_unthrottle_workqueue); + hso_unthrottle_tasklet(serial); +} + /* open the requested serial port */ static int hso_serial_open(struct tty_struct *tty, struct file *filp) { @@ -1064,13 +1241,18 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) tty->driver_data = serial; serial->tty = tty; - /* check for port allready opened, if not set the termios */ + /* check for port already opened, if not set the termios */ serial->open_count++; if (serial->open_count == 1) { tty->low_latency = 1; - serial->flags = 0; + serial->rx_state = RX_IDLE; /* Force default termio settings */ _hso_serial_set_termios(tty, NULL); + tasklet_init(&serial->unthrottle_tasklet, + (void (*)(unsigned long))hso_unthrottle_tasklet, + (unsigned long)serial); + INIT_WORK(&serial->retry_unthrottle_workqueue, + hso_unthrottle_workfunc); result = hso_start_serial_device(serial->parent, GFP_KERNEL); if (result) { hso_stop_serial_device(serial->parent); @@ -1117,9 +1299,13 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) } if (!usb_gone) hso_stop_serial_device(serial->parent); + tasklet_kill(&serial->unthrottle_tasklet); + cancel_work_sync(&serial->retry_unthrottle_workqueue); } + if (!usb_gone) usb_autopm_put_interface(serial->parent->interface); + mutex_unlock(&serial->parent->mutex); } @@ -1422,15 +1608,21 @@ static void intr_callback(struct urb *urb) (1 << i)); if (serial != NULL) { D1("Pending read interrupt on port %d\n", i); - if (!test_and_set_bit(HSO_SERIAL_FLAG_RX_SENT, - &serial->flags)) { + spin_lock(&serial->serial_lock); + if (serial->rx_state == RX_IDLE) { /* Setup and send a ctrl req read on * port i */ - hso_mux_serial_read(serial); + if (!serial->rx_urb_filled[0]) { + serial->rx_state = RX_SENT; + hso_mux_serial_read(serial); + } else + serial->rx_state = RX_PENDING; + } else { D1("Already pending a read on " "port %d\n", i); } + spin_unlock(&serial->serial_lock); } } } @@ -1532,16 +1724,10 @@ static void ctrl_callback(struct urb *urb) if (req->bRequestType == (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) { /* response to a read command */ - if (serial->open_count > 0) { - /* handle RX data the normal way */ - put_rxbuf_data(urb, serial); - } - - /* Re issue a read as long as we receive data. */ - if (urb->actual_length != 0) - hso_mux_serial_read(serial); - else - clear_bit(HSO_SERIAL_FLAG_RX_SENT, &serial->flags); + serial->rx_urb_filled[0] = 1; + spin_lock(&serial->serial_lock); + put_rxbuf_data_and_resubmit_ctrl_urb(serial); + spin_unlock(&serial->serial_lock); } else { hso_put_activity(serial->parent); if (serial->tty) @@ -1552,91 +1738,42 @@ static void ctrl_callback(struct urb *urb) } /* handle RX data for serial port */ -static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial) +static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) { struct tty_struct *tty = serial->tty; - + int write_length_remaining = 0; + int curr_write_len; /* Sanity check */ if (urb == NULL || serial == NULL) { D1("serial = NULL"); - return; + return -2; } /* Push data to tty */ - if (tty && urb->actual_length) { + if (tty) { + write_length_remaining = urb->actual_length - + serial->curr_rx_urb_offset; D1("data to push to tty"); - tty_insert_flip_string(tty, urb->transfer_buffer, - urb->actual_length); - tty_flip_buffer_push(tty); - } -} - -/* read callback for Diag and CS port */ -static void hso_std_serial_read_bulk_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - int result; - int status = urb->status; - - /* sanity check */ - if (!serial) { - D1("serial == NULL"); - return; - } else if (status) { - log_usb_status(status, __func__); - return; - } - - D4("\n--- Got serial_read_bulk callback %02x ---", status); - D1("Actual length = %d\n", urb->actual_length); - DUMP1(urb->transfer_buffer, urb->actual_length); - - /* Anyone listening? */ - if (serial->open_count == 0) - return; - - if (status == 0) { - if (serial->parent->port_spec & HSO_INFO_CRC_BUG) { - u32 rest; - u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; - rest = - urb->actual_length % - serial->in_endp->wMaxPacketSize; - if (((rest == 5) || (rest == 6)) - && !memcmp(((u8 *) urb->transfer_buffer) + - urb->actual_length - 4, crc_check, 4)) { - urb->actual_length -= 4; - } + while (write_length_remaining) { + if (test_bit(TTY_THROTTLED, &tty->flags)) + return -1; + curr_write_len = tty_insert_flip_string + (tty, urb->transfer_buffer + + serial->curr_rx_urb_offset, + write_length_remaining); + serial->curr_rx_urb_offset += curr_write_len; + write_length_remaining -= curr_write_len; + tty_flip_buffer_push(tty); } - /* Valid data, handle RX data */ - put_rxbuf_data(urb, serial); - } else if (status == -ENOENT || status == -ECONNRESET) { - /* Unlinked - check for throttled port. */ - D2("Port %d, successfully unlinked urb", serial->minor); - } else { - D2("Port %d, status = %d for read urb", serial->minor, status); - return; } - - usb_mark_last_busy(urb->dev); - - /* We are done with this URB, resubmit it. Prep the USB to wait for - * another frame */ - usb_fill_bulk_urb(urb, serial->parent->usb, - usb_rcvbulkpipe(serial->parent->usb, - serial->in_endp-> - bEndpointAddress & 0x7F), - urb->transfer_buffer, serial->rx_data_length, - hso_std_serial_read_bulk_callback, serial); - /* Give this to the USB subsystem so it can tell us when more data - * arrives. */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d", - __func__, result); + if (write_length_remaining == 0) { + serial->curr_rx_urb_offset = 0; + serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; } + return write_length_remaining; } + /* Base driver functions */ static void hso_log_port(struct hso_device *hso_dev) @@ -1794,9 +1931,13 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) return -ENODEV; for (i = 0; i < serial->num_rx_urbs; i++) { - if (serial->rx_urb[i]) + if (serial->rx_urb[i]) { usb_kill_urb(serial->rx_urb[i]); + serial->rx_urb_filled[i] = 0; + } } + serial->curr_rx_urb_idx = 0; + serial->curr_rx_urb_offset = 0; if (serial->tx_urb) usb_kill_urb(serial->tx_urb); @@ -2211,14 +2352,14 @@ static struct hso_device *hso_create_bulk_serial_device( USB_DIR_IN); if (!serial->in_endp) { dev_err(&interface->dev, "Failed to find BULK IN ep\n"); - goto exit; + goto exit2; } if (! (serial->out_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT))) { dev_err(&interface->dev, "Failed to find BULK IN ep\n"); - goto exit; + goto exit2; } serial->write_data = hso_std_serial_write_data; @@ -2231,9 +2372,10 @@ static struct hso_device *hso_create_bulk_serial_device( /* done, return it */ return hso_dev; + +exit2: + hso_serial_common_free(serial); exit: - if (hso_dev && serial) - hso_serial_common_free(serial); kfree(serial); hso_free_device(hso_dev); return NULL; @@ -2740,6 +2882,7 @@ static const struct tty_operations hso_serial_ops = { .chars_in_buffer = hso_serial_chars_in_buffer, .tiocmget = hso_serial_tiocmget, .tiocmset = hso_serial_tiocmset, + .unthrottle = hso_unthrottle }; static struct usb_driver hso_driver = { diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index d6829db51b4..fdbf3be24fd 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -832,7 +832,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) { - warn("kaweth failed tx_urb %d", res); + dev_warn(&net->dev, "kaweth failed tx_urb %d\n", res); skip: kaweth->stats.tx_errors++; @@ -924,7 +924,7 @@ static void kaweth_tx_timeout(struct net_device *net) { struct kaweth_device *kaweth = netdev_priv(net); - warn("%s: Tx timed out. Resetting.", net->name); + dev_warn(&net->dev, "%s: Tx timed out. Resetting.\n", net->name); kaweth->stats.tx_errors++; net->trans_start = jiffies; @@ -1016,10 +1016,10 @@ static int kaweth_probe( */ if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) { - info("Firmware present in device."); + dev_info(&intf->dev, "Firmware present in device.\n"); } else { /* Download the firmware */ - info("Downloading firmware..."); + dev_info(&intf->dev, "Downloading firmware...\n"); kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); if ((result = kaweth_download_firmware(kaweth, "kaweth/new_code.bin", @@ -1061,7 +1061,7 @@ static int kaweth_probe( } /* Device will now disappear for a moment... */ - info("Firmware loaded. I'll be back..."); + dev_info(&intf->dev, "Firmware loaded. I'll be back...\n"); err_fw: free_page((unsigned long)kaweth->firmware_buf); free_netdev(netdev); @@ -1075,10 +1075,10 @@ err_fw: goto err_free_netdev; } - info("Statistics collection: %x", kaweth->configuration.statistics_mask); - info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); - info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); - info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + dev_info(&intf->dev, "Statistics collection: %x\n", kaweth->configuration.statistics_mask); + dev_info(&intf->dev, "Multicast filter limit: %x\n", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); + dev_info(&intf->dev, "MTU: %d\n", le16_to_cpu(kaweth->configuration.segment_size)); + dev_info(&intf->dev, "Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", (int)kaweth->configuration.hw_addr[0], (int)kaweth->configuration.hw_addr[1], (int)kaweth->configuration.hw_addr[2], @@ -1174,7 +1174,8 @@ err_fw: goto err_intfdata; } - info("kaweth interface created at %s", kaweth->net->name); + dev_info(&intf->dev, "kaweth interface created at %s\n", + kaweth->net->name); dbg("Kaweth probe returning."); @@ -1205,11 +1206,11 @@ static void kaweth_disconnect(struct usb_interface *intf) struct kaweth_device *kaweth = usb_get_intfdata(intf); struct net_device *netdev; - info("Unregistering"); + dev_info(&intf->dev, "Unregistering\n"); usb_set_intfdata(intf, NULL); if (!kaweth) { - warn("unregistering non-existant device"); + dev_warn(&intf->dev, "unregistering non-existant device\n"); return; } netdev = kaweth->net; @@ -1269,7 +1270,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { // timeout - warn("usb_control/bulk_msg: timeout"); + dev_warn(&urb->dev->dev, "usb_control/bulk_msg: timeout\n"); usb_kill_urb(urb); // remove urb safely status = -ETIMEDOUT; } diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index ca9d00c1194..b5143509e8b 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -118,7 +118,7 @@ static void mcs7830_async_cmd_callback(struct urb *urb) if (urb->status < 0) printk(KERN_DEBUG "%s() failed with %d\n", - __FUNCTION__, urb->status); + __func__, urb->status); kfree(req); usb_free_urb(urb); diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 8c19307e504..38b90e7a7ed 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -119,7 +119,7 @@ static void ctrl_callback(struct urb *urb) default: if (netif_msg_drv(pegasus) && printk_ratelimit()) dev_dbg(&pegasus->intf->dev, "%s, status %d\n", - __FUNCTION__, urb->status); + __func__, urb->status); } pegasus->flags &= ~ETH_REGS_CHANGED; wake_up(&pegasus->ctrl_wait); @@ -136,7 +136,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, if (!buffer) { if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "out of memory in %s\n", - __FUNCTION__); + __func__); return -ENOMEM; } add_wait_queue(&pegasus->ctrl_wait, &wait); @@ -224,7 +224,7 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size, netif_device_detach(pegasus->net); if (netif_msg_drv(pegasus)) dev_err(&pegasus->intf->dev, "%s, status %d\n", - __FUNCTION__, ret); + __func__, ret); goto out; } @@ -246,7 +246,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) if (!tmp) { if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "out of memory in %s\n", - __FUNCTION__); + __func__); return -ENOMEM; } memcpy(tmp, &data, 1); @@ -277,7 +277,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) netif_device_detach(pegasus->net); if (netif_msg_drv(pegasus) && printk_ratelimit()) dev_err(&pegasus->intf->dev, "%s, status %d\n", - __FUNCTION__, ret); + __func__, ret); goto out; } @@ -310,7 +310,7 @@ static int update_eth_regs_async(pegasus_t * pegasus) netif_device_detach(pegasus->net); if (netif_msg_drv(pegasus)) dev_err(&pegasus->intf->dev, "%s, status %d\n", - __FUNCTION__, ret); + __func__, ret); } return ret; @@ -341,7 +341,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) } fail: if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); + dev_warn(&pegasus->intf->dev, "%s failed\n", __func__); return ret; } @@ -378,7 +378,7 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd) fail: if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); + dev_warn(&pegasus->intf->dev, "%s failed\n", __func__); return -ETIMEDOUT; } @@ -415,7 +415,7 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) fail: if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); + dev_warn(&pegasus->intf->dev, "%s failed\n", __func__); return -ETIMEDOUT; } @@ -463,7 +463,7 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data) return ret; fail: if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); + dev_warn(&pegasus->intf->dev, "%s failed\n", __func__); return -ETIMEDOUT; } #endif /* PEGASUS_WRITE_EEPROM */ diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index df56a518691..6133401ebc6 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -221,7 +221,7 @@ static void ctrl_callback(struct urb *urb) case -ENOENT: break; default: - warn("ctrl urb status %d", urb->status); + dev_warn(&urb->dev->dev, "ctrl urb status %d\n", urb->status); } dev = urb->context; clear_bit(RX_REG_SET, &dev->flags); @@ -441,10 +441,10 @@ static void read_bulk_callback(struct urb *urb) case -ENOENT: return; /* the urb is in unlink state */ case -ETIME: - warn("may be reset is needed?.."); + dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); goto goon; default: - warn("Rx status %d", urb->status); + dev_warn(&urb->dev->dev, "Rx status %d\n", urb->status); goto goon; } @@ -538,7 +538,8 @@ static void write_bulk_callback(struct urb *urb) if (!netif_device_present(dev->netdev)) return; if (urb->status) - info("%s: Tx status %d", dev->netdev->name, urb->status); + dev_info(&urb->dev->dev, "%s: Tx status %d\n", + dev->netdev->name, urb->status); dev->netdev->trans_start = jiffies; netif_wake_queue(dev->netdev); } @@ -561,7 +562,8 @@ static void intr_callback(struct urb *urb) return; /* -EPIPE: should clear the halt */ default: - info("%s: intr status %d", dev->netdev->name, urb->status); + dev_info(&urb->dev->dev, "%s: intr status %d\n", + dev->netdev->name, urb->status); goto resubmit; } @@ -665,7 +667,7 @@ static int enable_net_traffic(rtl8150_t * dev) u8 cr, tcr, rcr, msr; if (!rtl8150_reset(dev)) { - warn("%s - device reset failed", __FUNCTION__); + dev_warn(&dev->udev->dev, "device reset failed\n"); } /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */ rcr = 0x9e; @@ -699,7 +701,7 @@ static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev) static void rtl8150_tx_timeout(struct net_device *netdev) { rtl8150_t *dev = netdev_priv(netdev); - warn("%s: Tx timeout.", netdev->name); + dev_warn(&netdev->dev, "Tx timeout.\n"); usb_unlink_urb(dev->tx_urb); dev->stats.tx_errors++; } @@ -710,12 +712,12 @@ static void rtl8150_set_multicast(struct net_device *netdev) netif_stop_queue(netdev); if (netdev->flags & IFF_PROMISC) { dev->rx_creg |= cpu_to_le16(0x0001); - info("%s: promiscuous mode", netdev->name); + dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name); } else if (netdev->mc_count || (netdev->flags & IFF_ALLMULTI)) { dev->rx_creg &= cpu_to_le16(0xfffe); dev->rx_creg |= cpu_to_le16(0x0002); - info("%s: allmulti set", netdev->name); + dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name); } else { /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ dev->rx_creg &= cpu_to_le16(0x00fc); @@ -740,7 +742,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (res == -ENODEV) netif_device_detach(dev->netdev); else { - warn("failed tx_urb %d\n", res); + dev_warn(&netdev->dev, "failed tx_urb %d\n", res); dev->stats.tx_errors++; netif_start_queue(netdev); } @@ -783,7 +785,7 @@ static int rtl8150_open(struct net_device *netdev) if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) { if (res == -ENODEV) netif_device_detach(dev->netdev); - warn("%s: rx_urb submit failed: %d", __FUNCTION__, res); + dev_warn(&netdev->dev, "rx_urb submit failed: %d\n", res); return res; } usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3), @@ -792,7 +794,7 @@ static int rtl8150_open(struct net_device *netdev) if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) { if (res == -ENODEV) netif_device_detach(dev->netdev); - warn("%s: intr_urb submit failed: %d", __FUNCTION__, res); + dev_warn(&netdev->dev, "intr_urb submit failed: %d\n", res); usb_kill_urb(dev->rx_urb); return res; } @@ -947,7 +949,7 @@ static int rtl8150_probe(struct usb_interface *intf, goto out2; } - info("%s: rtl8150 is detected", netdev->name); + dev_info(&intf->dev, "%s: rtl8150 is detected\n", netdev->name); return 0; @@ -984,7 +986,8 @@ static void rtl8150_disconnect(struct usb_interface *intf) static int __init usb_rtl8150_init(void) { - info(DRIVER_DESC " " DRIVER_VERSION); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); return usb_register(&rtl8150_driver); } diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c new file mode 100644 index 00000000000..51e2f5d7d14 --- /dev/null +++ b/drivers/net/usb/smsc95xx.c @@ -0,0 +1,1225 @@ + /*************************************************************************** + * + * Copyright (C) 2007-2008 SMSC + * + * 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; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *****************************************************************************/ + +#include <linux/module.h> +#include <linux/kmod.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/usb.h> +#include <linux/crc32.h> +#include <linux/usb/usbnet.h> +#include "smsc95xx.h" + +#define SMSC_CHIPNAME "smsc95xx" +#define SMSC_DRIVER_VERSION "1.0.3" +#define HS_USB_PKT_SIZE (512) +#define FS_USB_PKT_SIZE (64) +#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) +#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE) +#define DEFAULT_BULK_IN_DELAY (0x00002000) +#define MAX_SINGLE_PACKET_SIZE (2048) +#define LAN95XX_EEPROM_MAGIC (0x9500) +#define EEPROM_MAC_OFFSET (0x01) +#define DEFAULT_RX_CSUM_ENABLE (true) +#define SMSC95XX_INTERNAL_PHY_ID (1) +#define SMSC95XX_TX_OVERHEAD (8) +#define FLOW_CTRL_TX (1) +#define FLOW_CTRL_RX (2) + +struct smsc95xx_priv { + u32 mac_cr; + spinlock_t mac_cr_lock; + bool use_rx_csum; +}; + +struct usb_context { + struct usb_ctrlrequest req; + struct completion notify; + struct usbnet *dev; +}; + +int turbo_mode = true; +module_param(turbo_mode, bool, 0644); +MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); + +static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data) +{ + u32 *buf = kmalloc(4, GFP_KERNEL); + int ret; + + BUG_ON(!dev); + + if (!buf) + return -ENOMEM; + + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), + USB_VENDOR_REQUEST_READ_REGISTER, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 00, index, buf, 4, USB_CTRL_GET_TIMEOUT); + + if (unlikely(ret < 0)) + devwarn(dev, "Failed to read register index 0x%08x", index); + + le32_to_cpus(buf); + *data = *buf; + kfree(buf); + + return ret; +} + +static int smsc95xx_write_reg(struct usbnet *dev, u32 index, u32 data) +{ + u32 *buf = kmalloc(4, GFP_KERNEL); + int ret; + + BUG_ON(!dev); + + if (!buf) + return -ENOMEM; + + *buf = data; + cpu_to_le32s(buf); + + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + USB_VENDOR_REQUEST_WRITE_REGISTER, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 00, index, buf, 4, USB_CTRL_SET_TIMEOUT); + + if (unlikely(ret < 0)) + devwarn(dev, "Failed to write register index 0x%08x", index); + + kfree(buf); + + return ret; +} + +/* Loop until the read is completed with timeout + * called with phy_mutex held */ +static int smsc95xx_phy_wait_not_busy(struct usbnet *dev) +{ + unsigned long start_time = jiffies; + u32 val; + + do { + smsc95xx_read_reg(dev, MII_ADDR, &val); + if (!(val & MII_BUSY_)) + return 0; + } while (!time_after(jiffies, start_time + HZ)); + + return -EIO; +} + +static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx) +{ + struct usbnet *dev = netdev_priv(netdev); + u32 val, addr; + + mutex_lock(&dev->phy_mutex); + + /* confirm MII not busy */ + if (smsc95xx_phy_wait_not_busy(dev)) { + devwarn(dev, "MII is busy in smsc95xx_mdio_read"); + mutex_unlock(&dev->phy_mutex); + return -EIO; + } + + /* set the address, index & direction (read from PHY) */ + phy_id &= dev->mii.phy_id_mask; + idx &= dev->mii.reg_num_mask; + addr = (phy_id << 11) | (idx << 6) | MII_READ_; + smsc95xx_write_reg(dev, MII_ADDR, addr); + + if (smsc95xx_phy_wait_not_busy(dev)) { + devwarn(dev, "Timed out reading MII reg %02X", idx); + mutex_unlock(&dev->phy_mutex); + return -EIO; + } + + smsc95xx_read_reg(dev, MII_DATA, &val); + + mutex_unlock(&dev->phy_mutex); + + return (u16)(val & 0xFFFF); +} + +static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx, + int regval) +{ + struct usbnet *dev = netdev_priv(netdev); + u32 val, addr; + + mutex_lock(&dev->phy_mutex); + + /* confirm MII not busy */ + if (smsc95xx_phy_wait_not_busy(dev)) { + devwarn(dev, "MII is busy in smsc95xx_mdio_write"); + mutex_unlock(&dev->phy_mutex); + return; + } + + val = regval; + smsc95xx_write_reg(dev, MII_DATA, val); + + /* set the address, index & direction (write to PHY) */ + phy_id &= dev->mii.phy_id_mask; + idx &= dev->mii.reg_num_mask; + addr = (phy_id << 11) | (idx << 6) | MII_WRITE_; + smsc95xx_write_reg(dev, MII_ADDR, addr); + + if (smsc95xx_phy_wait_not_busy(dev)) + devwarn(dev, "Timed out writing MII reg %02X", idx); + + mutex_unlock(&dev->phy_mutex); +} + +static int smsc95xx_wait_eeprom(struct usbnet *dev) +{ + unsigned long start_time = jiffies; + u32 val; + + do { + smsc95xx_read_reg(dev, E2P_CMD, &val); + if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_)) + break; + udelay(40); + } while (!time_after(jiffies, start_time + HZ)); + + if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) { + devwarn(dev, "EEPROM read operation timeout"); + return -EIO; + } + + return 0; +} + +static int smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev) +{ + unsigned long start_time = jiffies; + u32 val; + + do { + smsc95xx_read_reg(dev, E2P_CMD, &val); + + if (!(val & E2P_CMD_LOADED_)) { + devwarn(dev, "No EEPROM present"); + return -EIO; + } + + if (!(val & E2P_CMD_BUSY_)) + return 0; + + udelay(40); + } while (!time_after(jiffies, start_time + HZ)); + + devwarn(dev, "EEPROM is busy"); + return -EIO; +} + +static int smsc95xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length, + u8 *data) +{ + u32 val; + int i, ret; + + BUG_ON(!dev); + BUG_ON(!data); + + ret = smsc95xx_eeprom_confirm_not_busy(dev); + if (ret) + return ret; + + for (i = 0; i < length; i++) { + val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_); + smsc95xx_write_reg(dev, E2P_CMD, val); + + ret = smsc95xx_wait_eeprom(dev); + if (ret < 0) + return ret; + + smsc95xx_read_reg(dev, E2P_DATA, &val); + + data[i] = val & 0xFF; + offset++; + } + + return 0; +} + +static int smsc95xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length, + u8 *data) +{ + u32 val; + int i, ret; + + BUG_ON(!dev); + BUG_ON(!data); + + ret = smsc95xx_eeprom_confirm_not_busy(dev); + if (ret) + return ret; + + /* Issue write/erase enable command */ + val = E2P_CMD_BUSY_ | E2P_CMD_EWEN_; + smsc95xx_write_reg(dev, E2P_CMD, val); + + ret = smsc95xx_wait_eeprom(dev); + if (ret < 0) + return ret; + + for (i = 0; i < length; i++) { + + /* Fill data register */ + val = data[i]; + smsc95xx_write_reg(dev, E2P_DATA, val); + + /* Send "write" command */ + val = E2P_CMD_BUSY_ | E2P_CMD_WRITE_ | (offset & E2P_CMD_ADDR_); + smsc95xx_write_reg(dev, E2P_CMD, val); + + ret = smsc95xx_wait_eeprom(dev); + if (ret < 0) + return ret; + + offset++; + } + + return 0; +} + +static void smsc95xx_async_cmd_callback(struct urb *urb, struct pt_regs *regs) +{ + struct usb_context *usb_context = urb->context; + struct usbnet *dev = usb_context->dev; + + if (urb->status < 0) + devwarn(dev, "async callback failed with %d", urb->status); + + complete(&usb_context->notify); + + kfree(usb_context); + usb_free_urb(urb); +} + +static int smsc95xx_write_reg_async(struct usbnet *dev, u16 index, u32 *data) +{ + struct usb_context *usb_context; + int status; + struct urb *urb; + const u16 size = 4; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + devwarn(dev, "Error allocating URB"); + return -ENOMEM; + } + + usb_context = kmalloc(sizeof(struct usb_context), GFP_ATOMIC); + if (usb_context == NULL) { + devwarn(dev, "Error allocating control msg"); + usb_free_urb(urb); + return -ENOMEM; + } + + usb_context->req.bRequestType = + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + usb_context->req.bRequest = USB_VENDOR_REQUEST_WRITE_REGISTER; + usb_context->req.wValue = 00; + usb_context->req.wIndex = cpu_to_le16(index); + usb_context->req.wLength = cpu_to_le16(size); + init_completion(&usb_context->notify); + + usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), + (void *)&usb_context->req, data, size, + (usb_complete_t)smsc95xx_async_cmd_callback, + (void *)usb_context); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { + devwarn(dev, "Error submitting control msg, sts=%d", status); + kfree(usb_context); + usb_free_urb(urb); + } + + return status; +} + +/* returns hash bit number for given MAC address + * example: + * 01 00 5E 00 00 01 -> returns bit number 31 */ +static unsigned int smsc95xx_hash(char addr[ETH_ALEN]) +{ + return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; +} + +static void smsc95xx_set_multicast(struct net_device *netdev) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + u32 hash_hi = 0; + u32 hash_lo = 0; + unsigned long flags; + + spin_lock_irqsave(&pdata->mac_cr_lock, flags); + + if (dev->net->flags & IFF_PROMISC) { + if (netif_msg_drv(dev)) + devdbg(dev, "promiscuous mode enabled"); + pdata->mac_cr |= MAC_CR_PRMS_; + pdata->mac_cr &= ~(MAC_CR_MCPAS_ | MAC_CR_HPFILT_); + } else if (dev->net->flags & IFF_ALLMULTI) { + if (netif_msg_drv(dev)) + devdbg(dev, "receive all multicast enabled"); + pdata->mac_cr |= MAC_CR_MCPAS_; + pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_HPFILT_); + } else if (dev->net->mc_count > 0) { + struct dev_mc_list *mc_list = dev->net->mc_list; + int count = 0; + + pdata->mac_cr |= MAC_CR_HPFILT_; + pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_); + + while (mc_list) { + count++; + if (mc_list->dmi_addrlen == ETH_ALEN) { + u32 bitnum = smsc95xx_hash(mc_list->dmi_addr); + u32 mask = 0x01 << (bitnum & 0x1F); + if (bitnum & 0x20) + hash_hi |= mask; + else + hash_lo |= mask; + } else { + devwarn(dev, "dmi_addrlen != 6"); + } + mc_list = mc_list->next; + } + + if (count != ((u32)dev->net->mc_count)) + devwarn(dev, "mc_count != dev->mc_count"); + + if (netif_msg_drv(dev)) + devdbg(dev, "HASHH=0x%08X, HASHL=0x%08X", hash_hi, + hash_lo); + } else { + if (netif_msg_drv(dev)) + devdbg(dev, "receive own packets only"); + pdata->mac_cr &= + ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); + } + + spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); + + /* Initiate async writes, as we can't wait for completion here */ + smsc95xx_write_reg_async(dev, HASHH, &hash_hi); + smsc95xx_write_reg_async(dev, HASHL, &hash_lo); + smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); +} + +static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv) +{ + u8 cap = 0; + + if (lcladv & ADVERTISE_PAUSE_CAP) { + if (lcladv & ADVERTISE_PAUSE_ASYM) { + if (rmtadv & LPA_PAUSE_CAP) + cap = FLOW_CTRL_TX | FLOW_CTRL_RX; + else if (rmtadv & LPA_PAUSE_ASYM) + cap = FLOW_CTRL_RX; + } else { + if (rmtadv & LPA_PAUSE_CAP) + cap = FLOW_CTRL_TX | FLOW_CTRL_RX; + } + } else if (lcladv & ADVERTISE_PAUSE_ASYM) { + if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) + cap = FLOW_CTRL_TX; + } + + return cap; +} + +static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, + u16 lcladv, u16 rmtadv) +{ + u32 flow, afc_cfg = 0; + + int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg); + if (ret < 0) { + devwarn(dev, "error reading AFC_CFG"); + return; + } + + if (duplex == DUPLEX_FULL) { + u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv); + + if (cap & FLOW_CTRL_RX) + flow = 0xFFFF0002; + else + flow = 0; + + if (cap & FLOW_CTRL_TX) + afc_cfg |= 0xF; + else + afc_cfg &= ~0xF; + + if (netif_msg_link(dev)) + devdbg(dev, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + } else { + if (netif_msg_link(dev)) + devdbg(dev, "half duplex"); + flow = 0; + afc_cfg |= 0xF; + } + + smsc95xx_write_reg(dev, FLOW, flow); + smsc95xx_write_reg(dev, AFC_CFG, afc_cfg); +} + +static int smsc95xx_link_reset(struct usbnet *dev) +{ + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + struct mii_if_info *mii = &dev->mii; + struct ethtool_cmd ecmd; + unsigned long flags; + u16 lcladv, rmtadv; + u32 intdata; + + /* clear interrupt status */ + smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC); + intdata = 0xFFFFFFFF; + smsc95xx_write_reg(dev, INT_STS, intdata); + + mii_check_media(mii, 1, 1); + mii_ethtool_gset(&dev->mii, &ecmd); + lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); + rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); + + if (netif_msg_link(dev)) + devdbg(dev, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x", + ecmd.speed, ecmd.duplex, lcladv, rmtadv); + + spin_lock_irqsave(&pdata->mac_cr_lock, flags); + if (ecmd.duplex != DUPLEX_FULL) { + pdata->mac_cr &= ~MAC_CR_FDPX_; + pdata->mac_cr |= MAC_CR_RCVOWN_; + } else { + pdata->mac_cr &= ~MAC_CR_RCVOWN_; + pdata->mac_cr |= MAC_CR_FDPX_; + } + spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); + + smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); + + smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); + + return 0; +} + +static void smsc95xx_status(struct usbnet *dev, struct urb *urb) +{ + u32 intdata; + + if (urb->actual_length != 4) { + devwarn(dev, "unexpected urb length %d", urb->actual_length); + return; + } + + memcpy(&intdata, urb->transfer_buffer, 4); + le32_to_cpus(&intdata); + + if (netif_msg_link(dev)) + devdbg(dev, "intdata: 0x%08X", intdata); + + if (intdata & INT_ENP_PHY_INT_) + usbnet_defer_kevent(dev, EVENT_LINK_RESET); + else + devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata); +} + +/* Enable or disable Rx checksum offload engine */ +static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable) +{ + u32 read_buf; + int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read COE_CR: %d", ret); + return ret; + } + + if (enable) + read_buf |= Rx_COE_EN_; + else + read_buf &= ~Rx_COE_EN_; + + ret = smsc95xx_write_reg(dev, COE_CR, read_buf); + if (ret < 0) { + devwarn(dev, "Failed to write COE_CR: %d", ret); + return ret; + } + + if (netif_msg_hw(dev)) + devdbg(dev, "COE_CR = 0x%08x", read_buf); + return 0; +} + +static int smsc95xx_ethtool_get_eeprom_len(struct net_device *net) +{ + return MAX_EEPROM_SIZE; +} + +static int smsc95xx_ethtool_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, u8 *data) +{ + struct usbnet *dev = netdev_priv(netdev); + + ee->magic = LAN95XX_EEPROM_MAGIC; + + return smsc95xx_read_eeprom(dev, ee->offset, ee->len, data); +} + +static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, u8 *data) +{ + struct usbnet *dev = netdev_priv(netdev); + + if (ee->magic != LAN95XX_EEPROM_MAGIC) { + devwarn(dev, "EEPROM: magic value mismatch, magic = 0x%x", + ee->magic); + return -EINVAL; + } + + 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_rx_csum(dev, pdata->use_rx_csum); +} + +static struct ethtool_ops smsc95xx_ethtool_ops = { + .get_link = usbnet_get_link, + .nway_reset = usbnet_nway_reset, + .get_drvinfo = usbnet_get_drvinfo, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, + .get_eeprom = smsc95xx_ethtool_get_eeprom, + .set_eeprom = smsc95xx_ethtool_set_eeprom, + .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) +{ + struct usbnet *dev = netdev_priv(netdev); + + if (!netif_running(netdev)) + return -EINVAL; + + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +static void smsc95xx_init_mac_address(struct usbnet *dev) +{ + /* try reading mac address from EEPROM */ + if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, + dev->net->dev_addr) == 0) { + if (is_valid_ether_addr(dev->net->dev_addr)) { + /* eeprom values are valid so use them */ + if (netif_msg_ifup(dev)) + devdbg(dev, "MAC address read from EEPROM"); + return; + } + } + + /* no eeprom, or eeprom values are invalid. generate random MAC */ + random_ether_addr(dev->net->dev_addr); + if (netif_msg_ifup(dev)) + devdbg(dev, "MAC address set to random_ether_addr"); +} + +static int smsc95xx_set_mac_address(struct usbnet *dev) +{ + u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | + dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24; + u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8; + int ret; + + ret = smsc95xx_write_reg(dev, ADDRL, addr_lo); + if (ret < 0) { + devwarn(dev, "Failed to write ADDRL: %d", ret); + return ret; + } + + ret = smsc95xx_write_reg(dev, ADDRH, addr_hi); + if (ret < 0) { + devwarn(dev, "Failed to write ADDRH: %d", ret); + return ret; + } + + return 0; +} + +/* starts the TX path */ +static void smsc95xx_start_tx_path(struct usbnet *dev) +{ + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + unsigned long flags; + u32 reg_val; + + /* Enable Tx at MAC */ + spin_lock_irqsave(&pdata->mac_cr_lock, flags); + pdata->mac_cr |= MAC_CR_TXEN_; + spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); + + smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); + + /* Enable Tx at SCSRs */ + reg_val = TX_CFG_ON_; + smsc95xx_write_reg(dev, TX_CFG, reg_val); +} + +/* Starts the Receive path */ +static void smsc95xx_start_rx_path(struct usbnet *dev) +{ + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + unsigned long flags; + + spin_lock_irqsave(&pdata->mac_cr_lock, flags); + pdata->mac_cr |= MAC_CR_RXEN_; + spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); + + smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); +} + +static int smsc95xx_phy_initialize(struct usbnet *dev) +{ + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = smsc95xx_mdio_read; + dev->mii.mdio_write = smsc95xx_mdio_write; + dev->mii.phy_id_mask = 0x1f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = SMSC95XX_INTERNAL_PHY_ID; + + smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + + /* read to clear */ + smsc95xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); + + smsc95xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK, + PHY_INT_MASK_DEFAULT_); + mii_nway_restart(&dev->mii); + + if (netif_msg_ifup(dev)) + devdbg(dev, "phy initialised succesfully"); + return 0; +} + +static int smsc95xx_reset(struct usbnet *dev) +{ + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + u32 read_buf, write_buf, burst_cap; + int ret = 0, timeout; + DECLARE_MAC_BUF(mac); + + if (netif_msg_ifup(dev)) + devdbg(dev, "entering smsc95xx_reset"); + + write_buf = HW_CFG_LRST_; + ret = smsc95xx_write_reg(dev, HW_CFG, write_buf); + if (ret < 0) { + devwarn(dev, "Failed to write HW_CFG_LRST_ bit in HW_CFG " + "register, ret = %d", ret); + return ret; + } + + timeout = 0; + do { + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read HW_CFG: %d", ret); + return ret; + } + msleep(10); + timeout++; + } while ((read_buf & HW_CFG_LRST_) && (timeout < 100)); + + if (timeout >= 100) { + devwarn(dev, "timeout waiting for completion of Lite Reset"); + return ret; + } + + write_buf = PM_CTL_PHY_RST_; + ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf); + if (ret < 0) { + devwarn(dev, "Failed to write PM_CTRL: %d", ret); + return ret; + } + + timeout = 0; + do { + ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read PM_CTRL: %d", ret); + return ret; + } + msleep(10); + timeout++; + } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100)); + + if (timeout >= 100) { + devwarn(dev, "timeout waiting for PHY Reset"); + return ret; + } + + smsc95xx_init_mac_address(dev); + + ret = smsc95xx_set_mac_address(dev); + if (ret < 0) + return ret; + + if (netif_msg_ifup(dev)) + devdbg(dev, "MAC Address: %s", + print_mac(mac, dev->net->dev_addr)); + + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read HW_CFG: %d", ret); + return ret; + } + + if (netif_msg_ifup(dev)) + devdbg(dev, "Read Value from HW_CFG : 0x%08x", read_buf); + + read_buf |= HW_CFG_BIR_; + + ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); + if (ret < 0) { + devwarn(dev, "Failed to write HW_CFG_BIR_ bit in HW_CFG " + "register, ret = %d", ret); + return ret; + } + + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read HW_CFG: %d", ret); + return ret; + } + if (netif_msg_ifup(dev)) + devdbg(dev, "Read Value from HW_CFG after writing " + "HW_CFG_BIR_: 0x%08x", read_buf); + + if (!turbo_mode) { + burst_cap = 0; + dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE; + } else if (dev->udev->speed == USB_SPEED_HIGH) { + burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; + dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; + } else { + burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; + dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; + } + + if (netif_msg_ifup(dev)) + devdbg(dev, "rx_urb_size=%ld", (ulong)dev->rx_urb_size); + + ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap); + if (ret < 0) { + devwarn(dev, "Failed to write BURST_CAP: %d", ret); + return ret; + } + + ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read BURST_CAP: %d", ret); + return ret; + } + if (netif_msg_ifup(dev)) + devdbg(dev, "Read Value from BURST_CAP after writing: 0x%08x", + read_buf); + + read_buf = DEFAULT_BULK_IN_DELAY; + ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf); + if (ret < 0) { + devwarn(dev, "ret = %d", ret); + return ret; + } + + ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read BULK_IN_DLY: %d", ret); + return ret; + } + if (netif_msg_ifup(dev)) + devdbg(dev, "Read Value from BULK_IN_DLY after writing: " + "0x%08x", read_buf); + + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read HW_CFG: %d", ret); + return ret; + } + if (netif_msg_ifup(dev)) + devdbg(dev, "Read Value from HW_CFG: 0x%08x", read_buf); + + if (turbo_mode) + read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_); + + read_buf &= ~HW_CFG_RXDOFF_; + + /* set Rx data offset=2, Make IP header aligns on word boundary. */ + read_buf |= NET_IP_ALIGN << 9; + + ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); + if (ret < 0) { + devwarn(dev, "Failed to write HW_CFG register, ret=%d", ret); + return ret; + } + + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read HW_CFG: %d", ret); + return ret; + } + if (netif_msg_ifup(dev)) + devdbg(dev, "Read Value from HW_CFG after writing: 0x%08x", + read_buf); + + write_buf = 0xFFFFFFFF; + ret = smsc95xx_write_reg(dev, INT_STS, write_buf); + if (ret < 0) { + devwarn(dev, "Failed to write INT_STS register, ret=%d", ret); + return ret; + } + + ret = smsc95xx_read_reg(dev, ID_REV, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read ID_REV: %d", ret); + return ret; + } + if (netif_msg_ifup(dev)) + devdbg(dev, "ID_REV = 0x%08x", read_buf); + + /* Init Tx */ + write_buf = 0; + ret = smsc95xx_write_reg(dev, FLOW, write_buf); + if (ret < 0) { + devwarn(dev, "Failed to write FLOW: %d", ret); + return ret; + } + + read_buf = AFC_CFG_DEFAULT; + ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf); + if (ret < 0) { + devwarn(dev, "Failed to write AFC_CFG: %d", ret); + return ret; + } + + /* Don't need mac_cr_lock during initialisation */ + ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr); + if (ret < 0) { + devwarn(dev, "Failed to read MAC_CR: %d", ret); + return ret; + } + + /* Init Rx */ + /* Set Vlan */ + write_buf = (u32)ETH_P_8021Q; + ret = smsc95xx_write_reg(dev, VLAN1, write_buf); + if (ret < 0) { + devwarn(dev, "Failed to write VAN1: %d", ret); + return ret; + } + + /* Enable or disable Rx checksum offload engine */ + ret = smsc95xx_set_rx_csum(dev, pdata->use_rx_csum); + if (ret < 0) { + devwarn(dev, "Failed to set Rx csum offload: %d", ret); + return ret; + } + + smsc95xx_set_multicast(dev->net); + + if (smsc95xx_phy_initialize(dev) < 0) + return -EIO; + + ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf); + if (ret < 0) { + devwarn(dev, "Failed to read INT_EP_CTL: %d", ret); + return ret; + } + + /* enable PHY interrupts */ + read_buf |= INT_EP_CTL_PHY_INT_; + + ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf); + if (ret < 0) { + devwarn(dev, "Failed to write INT_EP_CTL: %d", ret); + return ret; + } + + smsc95xx_start_tx_path(dev); + smsc95xx_start_rx_path(dev); + + if (netif_msg_ifup(dev)) + devdbg(dev, "smsc95xx_reset, return 0"); + return 0; +} + +static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) +{ + struct smsc95xx_priv *pdata = NULL; + int ret; + + printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n"); + + ret = usbnet_get_endpoints(dev, intf); + if (ret < 0) { + devwarn(dev, "usbnet_get_endpoints failed: %d", ret); + return ret; + } + + dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc95xx_priv), + GFP_KERNEL); + + pdata = (struct smsc95xx_priv *)(dev->data[0]); + if (!pdata) { + devwarn(dev, "Unable to allocate struct smsc95xx_priv"); + return -ENOMEM; + } + + spin_lock_init(&pdata->mac_cr_lock); + + pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + + /* Init all registers */ + ret = smsc95xx_reset(dev); + + dev->net->do_ioctl = smsc95xx_ioctl; + dev->net->ethtool_ops = &smsc95xx_ethtool_ops; + dev->net->set_multicast_list = smsc95xx_set_multicast; + dev->net->flags |= IFF_MULTICAST; + dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD; + return 0; +} + +static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + if (pdata) { + if (netif_msg_ifdown(dev)) + devdbg(dev, "free pdata"); + kfree(pdata); + pdata = NULL; + dev->data[0] = 0; + } +} + +static void smsc95xx_rx_csum_offload(struct sk_buff *skb) +{ + skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2); + skb->ip_summed = CHECKSUM_COMPLETE; + skb_trim(skb, skb->len - 2); +} + +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; + unsigned char *packet; + u16 size; + + memcpy(&header, skb->data, sizeof(header)); + le32_to_cpus(&header); + skb_pull(skb, 4 + NET_IP_ALIGN); + packet = skb->data; + + /* get the packet length */ + size = (u16)((header & RX_STS_FL_) >> 16); + align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4; + + if (unlikely(header & RX_STS_ES_)) { + if (netif_msg_rx_err(dev)) + devdbg(dev, "Error header=0x%08x", header); + dev->stats.rx_errors++; + dev->stats.rx_dropped++; + + if (header & RX_STS_CRC_) { + dev->stats.rx_crc_errors++; + } else { + if (header & (RX_STS_TL_ | RX_STS_RF_)) + dev->stats.rx_frame_errors++; + + if ((header & RX_STS_LE_) && + (!(header & RX_STS_FT_))) + dev->stats.rx_length_errors++; + } + } else { + /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */ + if (unlikely(size > (ETH_FRAME_LEN + 12))) { + if (netif_msg_rx_err(dev)) + devdbg(dev, "size err header=0x%08x", + header); + return 0; + } + + /* last frame in this batch */ + if (skb->len == size) { + if (pdata->use_rx_csum) + smsc95xx_rx_csum_offload(skb); + + skb->truesize = size + sizeof(struct sk_buff); + + return 1; + } + + ax_skb = skb_clone(skb, GFP_ATOMIC); + if (unlikely(!ax_skb)) { + devwarn(dev, "Error allocating skb"); + return 0; + } + + ax_skb->len = size; + ax_skb->data = packet; + skb_set_tail_pointer(ax_skb, size); + + if (pdata->use_rx_csum) + smsc95xx_rx_csum_offload(ax_skb); + + ax_skb->truesize = size + sizeof(struct sk_buff); + + usbnet_skb_return(dev, ax_skb); + } + + skb_pull(skb, size); + + /* padding bytes before the next frame starts */ + if (skb->len) + skb_pull(skb, align_count); + } + + if (unlikely(skb->len < 0)) { + devwarn(dev, "invalid rx length<0 %d", skb->len); + return 0; + } + + return 1; +} + +static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, + struct sk_buff *skb, gfp_t flags) +{ + u32 tx_cmd_a, tx_cmd_b; + + if (skb_headroom(skb) < SMSC95XX_TX_OVERHEAD) { + struct sk_buff *skb2 = skb_copy_expand(skb, + SMSC95XX_TX_OVERHEAD, 0, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + skb_push(skb, 4); + tx_cmd_b = (u32)(skb->len - 4); + cpu_to_le32s(&tx_cmd_b); + memcpy(skb->data, &tx_cmd_b, 4); + + skb_push(skb, 4); + tx_cmd_a = (u32)(skb->len - 8) | TX_CMD_A_FIRST_SEG_ | + TX_CMD_A_LAST_SEG_; + cpu_to_le32s(&tx_cmd_a); + memcpy(skb->data, &tx_cmd_a, 4); + + return skb; +} + +static const struct driver_info smsc95xx_info = { + .description = "smsc95xx USB 2.0 Ethernet", + .bind = smsc95xx_bind, + .unbind = smsc95xx_unbind, + .link_reset = smsc95xx_link_reset, + .reset = smsc95xx_reset, + .rx_fixup = smsc95xx_rx_fixup, + .tx_fixup = smsc95xx_tx_fixup, + .status = smsc95xx_status, + .flags = FLAG_ETHER, +}; + +static const struct usb_device_id products[] = { + { + /* SMSC9500 USB Ethernet Device */ + USB_DEVICE(0x0424, 0x9500), + .driver_info = (unsigned long) &smsc95xx_info, + }, + { }, /* END */ +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver smsc95xx_driver = { + .name = "smsc95xx", + .id_table = products, + .probe = usbnet_probe, + .suspend = usbnet_suspend, + .resume = usbnet_resume, + .disconnect = usbnet_disconnect, +}; + +static int __init smsc95xx_init(void) +{ + return usb_register(&smsc95xx_driver); +} +module_init(smsc95xx_init); + +static void __exit smsc95xx_exit(void) +{ + usb_deregister(&smsc95xx_driver); +} +module_exit(smsc95xx_exit); + +MODULE_AUTHOR("Nancy Lin"); +MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>"); +MODULE_DESCRIPTION("SMSC95XX USB 2.0 Ethernet Devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/smsc95xx.h b/drivers/net/usb/smsc95xx.h new file mode 100644 index 00000000000..66b5c84f302 --- /dev/null +++ b/drivers/net/usb/smsc95xx.h @@ -0,0 +1,253 @@ + /*************************************************************************** + * + * Copyright (C) 2007-2008 SMSC + * + * 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; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *****************************************************************************/ + +#ifndef _SMSC95XX_H +#define _SMSC95XX_H + +/* Tx command words */ +#define TX_CMD_A_DATA_OFFSET_ (0x001F0000) +#define TX_CMD_A_FIRST_SEG_ (0x00002000) +#define TX_CMD_A_LAST_SEG_ (0x00001000) +#define TX_CMD_A_BUF_SIZE_ (0x000007FF) + +#define TX_CMD_B_CSUM_ENABLE (0x00004000) +#define TX_CMD_B_ADD_CRC_DISABLE_ (0x00002000) +#define TX_CMD_B_DISABLE_PADDING_ (0x00001000) +#define TX_CMD_B_PKT_BYTE_LENGTH_ (0x000007FF) + +/* Rx status word */ +#define RX_STS_FF_ (0x40000000) /* Filter Fail */ +#define RX_STS_FL_ (0x3FFF0000) /* Frame Length */ +#define RX_STS_ES_ (0x00008000) /* Error Summary */ +#define RX_STS_BF_ (0x00002000) /* Broadcast Frame */ +#define RX_STS_LE_ (0x00001000) /* Length Error */ +#define RX_STS_RF_ (0x00000800) /* Runt Frame */ +#define RX_STS_MF_ (0x00000400) /* Multicast Frame */ +#define RX_STS_TL_ (0x00000080) /* Frame too long */ +#define RX_STS_CS_ (0x00000040) /* Collision Seen */ +#define RX_STS_FT_ (0x00000020) /* Frame Type */ +#define RX_STS_RW_ (0x00000010) /* Receive Watchdog */ +#define RX_STS_ME_ (0x00000008) /* Mii Error */ +#define RX_STS_DB_ (0x00000004) /* Dribbling */ +#define RX_STS_CRC_ (0x00000002) /* CRC Error */ + +/* SCSRs */ +#define ID_REV (0x00) +#define ID_REV_CHIP_ID_MASK_ (0xFFFF0000) +#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) +#define ID_REV_CHIP_ID_9500_ (0x9500) + +#define INT_STS (0x08) +#define INT_STS_TX_STOP_ (0x00020000) +#define INT_STS_RX_STOP_ (0x00010000) +#define INT_STS_PHY_INT_ (0x00008000) +#define INT_STS_TXE_ (0x00004000) +#define INT_STS_TDFU_ (0x00002000) +#define INT_STS_TDFO_ (0x00001000) +#define INT_STS_RXDF_ (0x00000800) +#define INT_STS_GPIOS_ (0x000007FF) + +#define RX_CFG (0x0C) +#define RX_FIFO_FLUSH_ (0x00000001) + +#define TX_CFG (0x10) +#define TX_CFG_ON_ (0x00000004) +#define TX_CFG_STOP_ (0x00000002) +#define TX_CFG_FIFO_FLUSH_ (0x00000001) + +#define HW_CFG (0x14) +#define HW_CFG_BIR_ (0x00001000) +#define HW_CFG_LEDB_ (0x00000800) +#define HW_CFG_RXDOFF_ (0x00000600) +#define HW_CFG_DRP_ (0x00000040) +#define HW_CFG_MEF_ (0x00000020) +#define HW_CFG_LRST_ (0x00000008) +#define HW_CFG_PSEL_ (0x00000004) +#define HW_CFG_BCE_ (0x00000002) +#define HW_CFG_SRST_ (0x00000001) + +#define PM_CTRL (0x20) +#define PM_CTL_DEV_RDY_ (0x00000080) +#define PM_CTL_SUS_MODE_ (0x00000060) +#define PM_CTL_SUS_MODE_0 (0x00000000) +#define PM_CTL_SUS_MODE_1 (0x00000020) +#define PM_CTL_SUS_MODE_2 (0x00000060) +#define PM_CTL_PHY_RST_ (0x00000010) +#define PM_CTL_WOL_EN_ (0x00000008) +#define PM_CTL_ED_EN_ (0x00000004) +#define PM_CTL_WUPS_ (0x00000003) +#define PM_CTL_WUPS_NO_ (0x00000000) +#define PM_CTL_WUPS_ED_ (0x00000001) +#define PM_CTL_WUPS_WOL_ (0x00000002) +#define PM_CTL_WUPS_MULTI_ (0x00000003) + +#define LED_GPIO_CFG (0x24) + +#define GPIO_CFG (0x28) + +#define AFC_CFG (0x2C) + +/* Hi watermark = 15.5Kb (~10 mtu pkts) */ +/* low watermark = 3k (~2 mtu pkts) */ +/* backpressure duration = ~ 350us */ +/* Apply FC on any frame. */ +#define AFC_CFG_DEFAULT (0x00F830A1) + +#define E2P_CMD (0x30) +#define E2P_CMD_BUSY_ (0x80000000) +#define E2P_CMD_MASK_ (0x70000000) +#define E2P_CMD_READ_ (0x00000000) +#define E2P_CMD_EWDS_ (0x10000000) +#define E2P_CMD_EWEN_ (0x20000000) +#define E2P_CMD_WRITE_ (0x30000000) +#define E2P_CMD_WRAL_ (0x40000000) +#define E2P_CMD_ERASE_ (0x50000000) +#define E2P_CMD_ERAL_ (0x60000000) +#define E2P_CMD_RELOAD_ (0x70000000) +#define E2P_CMD_TIMEOUT_ (0x00000400) +#define E2P_CMD_LOADED_ (0x00000200) +#define E2P_CMD_ADDR_ (0x000001FF) + +#define MAX_EEPROM_SIZE (512) + +#define E2P_DATA (0x34) +#define E2P_DATA_MASK_ (0x000000FF) + +#define BURST_CAP (0x38) + +#define GPIO_WAKE (0x64) + +#define INT_EP_CTL (0x68) +#define INT_EP_CTL_INTEP_ (0x80000000) +#define INT_EP_CTL_MACRTO_ (0x00080000) +#define INT_EP_CTL_TX_STOP_ (0x00020000) +#define INT_EP_CTL_RX_STOP_ (0x00010000) +#define INT_EP_CTL_PHY_INT_ (0x00008000) +#define INT_EP_CTL_TXE_ (0x00004000) +#define INT_EP_CTL_TDFU_ (0x00002000) +#define INT_EP_CTL_TDFO_ (0x00001000) +#define INT_EP_CTL_RXDF_ (0x00000800) +#define INT_EP_CTL_GPIOS_ (0x000007FF) + +#define BULK_IN_DLY (0x6C) + +/* MAC CSRs */ +#define MAC_CR (0x100) +#define MAC_CR_RXALL_ (0x80000000) +#define MAC_CR_RCVOWN_ (0x00800000) +#define MAC_CR_LOOPBK_ (0x00200000) +#define MAC_CR_FDPX_ (0x00100000) +#define MAC_CR_MCPAS_ (0x00080000) +#define MAC_CR_PRMS_ (0x00040000) +#define MAC_CR_INVFILT_ (0x00020000) +#define MAC_CR_PASSBAD_ (0x00010000) +#define MAC_CR_HFILT_ (0x00008000) +#define MAC_CR_HPFILT_ (0x00002000) +#define MAC_CR_LCOLL_ (0x00001000) +#define MAC_CR_BCAST_ (0x00000800) +#define MAC_CR_DISRTY_ (0x00000400) +#define MAC_CR_PADSTR_ (0x00000100) +#define MAC_CR_BOLMT_MASK (0x000000C0) +#define MAC_CR_DFCHK_ (0x00000020) +#define MAC_CR_TXEN_ (0x00000008) +#define MAC_CR_RXEN_ (0x00000004) + +#define ADDRH (0x104) + +#define ADDRL (0x108) + +#define HASHH (0x10C) + +#define HASHL (0x110) + +#define MII_ADDR (0x114) +#define MII_WRITE_ (0x02) +#define MII_BUSY_ (0x01) +#define MII_READ_ (0x00) /* ~of MII Write bit */ + +#define MII_DATA (0x118) + +#define FLOW (0x11C) +#define FLOW_FCPT_ (0xFFFF0000) +#define FLOW_FCPASS_ (0x00000004) +#define FLOW_FCEN_ (0x00000002) +#define FLOW_FCBSY_ (0x00000001) + +#define VLAN1 (0x120) + +#define VLAN2 (0x124) + +#define WUFF (0x128) + +#define WUCSR (0x12C) + +#define COE_CR (0x130) +#define Tx_COE_EN_ (0x00010000) +#define Rx_COE_MODE_ (0x00000002) +#define Rx_COE_EN_ (0x00000001) + +/* Vendor-specific PHY Definitions */ + +/* Mode Control/Status Register */ +#define PHY_MODE_CTRL_STS (17) +#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000) +#define MODE_CTRL_STS_ENERGYON_ ((u16)0x0002) + +#define SPECIAL_CTRL_STS (27) +#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ ((u16)0x8000) +#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ ((u16)0x4000) +#define SPECIAL_CTRL_STS_AMDIX_STATE_ ((u16)0x2000) + +#define PHY_INT_SRC (29) +#define PHY_INT_SRC_ENERGY_ON_ ((u16)0x0080) +#define PHY_INT_SRC_ANEG_COMP_ ((u16)0x0040) +#define PHY_INT_SRC_REMOTE_FAULT_ ((u16)0x0020) +#define PHY_INT_SRC_LINK_DOWN_ ((u16)0x0010) + +#define PHY_INT_MASK (30) +#define PHY_INT_MASK_ENERGY_ON_ ((u16)0x0080) +#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040) +#define PHY_INT_MASK_REMOTE_FAULT_ ((u16)0x0020) +#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010) +#define PHY_INT_MASK_DEFAULT_ (PHY_INT_MASK_ANEG_COMP_ | \ + PHY_INT_MASK_LINK_DOWN_) + +#define PHY_SPECIAL (31) +#define PHY_SPECIAL_SPD_ ((u16)0x001C) +#define PHY_SPECIAL_SPD_10HALF_ ((u16)0x0004) +#define PHY_SPECIAL_SPD_10FULL_ ((u16)0x0014) +#define PHY_SPECIAL_SPD_100HALF_ ((u16)0x0008) +#define PHY_SPECIAL_SPD_100FULL_ ((u16)0x0018) + +/* USB Vendor Requests */ +#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0 +#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1 +#define USB_VENDOR_REQUEST_GET_STATS 0xA2 + +/* Interrupt Endpoint status word bitfields */ +#define INT_ENP_TX_STOP_ ((u32)BIT(17)) +#define INT_ENP_RX_STOP_ ((u32)BIT(16)) +#define INT_ENP_PHY_INT_ ((u32)BIT(15)) +#define INT_ENP_TXE_ ((u32)BIT(14)) +#define INT_ENP_TDFU_ ((u32)BIT(13)) +#define INT_ENP_TDFO_ ((u32)BIT(12)) +#define INT_ENP_RXDF_ ((u32)BIT(11)) + +#endif /* _SMSC95XX_H */ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 8463efb9e0b..02d25c74399 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -512,14 +512,13 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) int count = 0; spin_lock_irqsave (&q->lock, flags); - for (skb = q->next; skb != (struct sk_buff *) q; skb = skbnext) { + skb_queue_walk_safe(q, skb, skbnext) { struct skb_data *entry; struct urb *urb; int retval; entry = (struct skb_data *) skb->cb; urb = entry->urb; - skbnext = skb->next; // during some PM-driven resume scenarios, // these (async) unlinks complete immediately diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 96dff04334b..5b7870080c5 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -914,7 +914,7 @@ static void alloc_rbufs(struct net_device *dev) /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(rp->rx_buf_sz); + struct sk_buff *skb = netdev_alloc_skb(dev, rp->rx_buf_sz); rp->rx_skbuff[i] = skb; if (skb == NULL) break; @@ -1473,8 +1473,8 @@ static int rhine_rx(struct net_device *dev, int limit) /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && - (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { - skb_reserve(skb, 2); /* 16 byte align the IP header */ + (skb = netdev_alloc_skb(dev, pkt_len + NET_IP_ALIGN)) != NULL) { + skb_reserve(skb, NET_IP_ALIGN); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(rp->pdev, rp->rx_skbuff_dma[entry], rp->rx_buf_sz, @@ -1518,7 +1518,7 @@ static int rhine_rx(struct net_device *dev, int limit) struct sk_buff *skb; entry = rp->dirty_rx % RX_RING_SIZE; if (rp->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(rp->rx_buf_sz); + skb = netdev_alloc_skb(dev, rp->rx_buf_sz); rp->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 007c1297006..2dced383bcf 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -12,7 +12,7 @@ * Scatter gather * More testing * - * The changes are (c) Copyright 2004, Red Hat Inc. <alan@redhat.com> + * The changes are (c) Copyright 2004, Red Hat Inc. <alan@lxorguk.ukuu.org.uk> * Additional fixes and clean up: Francois Romieu * * This source has not been verified for use in safety critical systems. @@ -1272,7 +1272,7 @@ static void velocity_free_rd_ring(struct velocity_info *vptr) continue; pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz, PCI_DMA_FROMDEVICE); - rd_info->skb_dma = (dma_addr_t) NULL; + rd_info->skb_dma = 0; dev_kfree_skb(rd_info->skb); rd_info->skb = NULL; @@ -1333,7 +1333,7 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr, if (td_info->skb_dma[i]) { pci_unmap_single(vptr->pdev, td_info->skb_dma[i], td_info->skb->len, PCI_DMA_TODEVICE); - td_info->skb_dma[i] = (dma_addr_t) NULL; + td_info->skb_dma[i] = 0; } } dev_kfree_skb(td_info->skb); diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index 1b95b04c925..29a33090d3d 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1381,7 +1381,7 @@ enum velocity_msg_level { #define ASSERT(x) { \ if (!(x)) { \ printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\ - __FUNCTION__, __LINE__);\ + __func__, __LINE__);\ BUG(); \ }\ } diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 2ae2ec40015..21efd99b929 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -205,7 +205,7 @@ config WANXL_BUILD_FIRMWARE config PC300 tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)" - depends on HDLC && PCI + depends on HDLC && PCI && BROKEN ---help--- Driver for the Cyclades-PC300 synchronous communication boards. diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index f14051556c8..7f97f8d08c3 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -388,8 +388,8 @@ static int __init cosa_init(void) goto out_chrdev; } for (i = 0; i < nr_cards; i++) - device_create_drvdata(cosa_class, NULL, MKDEV(cosa_major, i), - NULL, "cosa%d", i); + device_create(cosa_class, NULL, MKDEV(cosa_major, i), NULL, + "cosa%d", i); err = 0; goto out; diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c index d14e6678dee..a5ddc6c8963 100644 --- a/drivers/net/wan/cycx_drv.c +++ b/drivers/net/wan/cycx_drv.c @@ -407,7 +407,7 @@ static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len) if (cfm->version != CFM_VERSION) { printk(KERN_ERR "%s:%s: firmware format %u rejected! " "Expecting %u.\n", - modname, __FUNCTION__, cfm->version, CFM_VERSION); + modname, __func__, cfm->version, CFM_VERSION); return -EINVAL; } @@ -420,7 +420,7 @@ static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len) */ if (cksum != cfm->checksum) { printk(KERN_ERR "%s:%s: firmware corrupted!\n", - modname, __FUNCTION__); + modname, __func__); printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n", len - (int)sizeof(struct cycx_firmware) - 1, cfm->info.codesize); @@ -432,7 +432,7 @@ static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len) /* If everything is ok, set reset, data and code pointers */ img_hdr = (struct cycx_fw_header *)&cfm->image; #ifdef FIRMWARE_DEBUG - printk(KERN_INFO "%s:%s: image sizes\n", __FUNCTION__, modname); + printk(KERN_INFO "%s:%s: image sizes\n", __func__, modname); printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size); printk(KERN_INFO " data=%lu\n", img_hdr->data_size); printk(KERN_INFO " code=%lu\n", img_hdr->code_size); diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index d3b28b01b9f..5a7303dc096 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -874,7 +874,7 @@ static void cycx_x25_irq_connect(struct cycx_device *card, nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1); dprintk(1, KERN_INFO "%s:lcn=%d, local=%s, remote=%s\n", - __FUNCTION__, lcn, loc, rem); + __func__, lcn, loc, rem); dev = cycx_x25_get_dev_by_dte_addr(wandev, rem); if (!dev) { @@ -902,7 +902,7 @@ static void cycx_x25_irq_connect_confirm(struct cycx_device *card, cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key)); dprintk(1, KERN_INFO "%s: %s:lcn=%d, key=%d\n", - card->devname, __FUNCTION__, lcn, key); + card->devname, __func__, lcn, key); dev = cycx_x25_get_dev_by_lcn(wandev, -key); if (!dev) { @@ -929,7 +929,7 @@ static void cycx_x25_irq_disconnect_confirm(struct cycx_device *card, cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); dprintk(1, KERN_INFO "%s: %s:lcn=%d\n", - card->devname, __FUNCTION__, lcn); + card->devname, __func__, lcn); dev = cycx_x25_get_dev_by_lcn(wandev, lcn); if (!dev) { /* Invalid channel, discard packet */ @@ -950,7 +950,7 @@ static void cycx_x25_irq_disconnect(struct cycx_device *card, u8 lcn; cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); - dprintk(1, KERN_INFO "%s:lcn=%d\n", __FUNCTION__, lcn); + dprintk(1, KERN_INFO "%s:lcn=%d\n", __func__, lcn); dev = cycx_x25_get_dev_by_lcn(wandev, lcn); if (dev) { @@ -1381,7 +1381,7 @@ static void cycx_x25_chan_timer(unsigned long d) cycx_x25_chan_disconnect(dev); else printk(KERN_ERR "%s: %s for svc (%s) not connected!\n", - chan->card->devname, __FUNCTION__, dev->name); + chan->card->devname, __func__, dev->name); } /* Set logical channel state. */ @@ -1485,7 +1485,7 @@ static void cycx_x25_chan_send_event(struct net_device *dev, u8 event) unsigned char *ptr; if ((skb = dev_alloc_skb(1)) == NULL) { - printk(KERN_ERR "%s: out of memory\n", __FUNCTION__); + printk(KERN_ERR "%s: out of memory\n", __func__); return; } diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index f5d55ad0226..5f1ccb2b08b 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -647,7 +647,7 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, skb = dpriv->rx_skbuff[dpriv->rx_current++%RX_RING_SIZE]; if (!skb) { - printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __FUNCTION__); + printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __func__); goto refill; } pkt_len = TO_SIZE(le32_to_cpu(rx_fd->state2)); diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index 8b7e5d2e2ac..cbcbf6f0414 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -163,15 +163,17 @@ static void x25_close(struct net_device *dev) static int x25_rx(struct sk_buff *skb) { + struct net_device *dev = skb->dev; + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - skb->dev->stats.rx_dropped++; + dev->stats.rx_dropped++; return NET_RX_DROP; } - if (lapb_data_received(skb->dev, skb) == LAPB_OK) + if (lapb_data_received(dev, skb) == LAPB_OK) return NET_RX_SUCCESS; - skb->dev->stats.rx_errors++; + dev->stats.rx_errors++; dev_kfree_skb_any(skb); return NET_RX_DROP; } diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index f80640f5a74..d7bb63e616b 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -122,7 +122,6 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ * Most functions mess with the structure * Disable interrupts while we do the polling */ - spin_lock_irqsave(&sc->lmc_lock, flags); switch (cmd) { /* @@ -152,6 +151,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ break; } + spin_lock_irqsave(&sc->lmc_lock, flags); sc->lmc_media->set_status (sc, &ctl); if(ctl.crc_length != sc->ictl.crc_length) { @@ -161,6 +161,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ else sc->TxDescriptControlInit &= ~LMC_TDES_ADD_CRC_DISABLE; } + spin_unlock_irqrestore(&sc->lmc_lock, flags); ret = 0; break; @@ -187,15 +188,18 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ break; /* no change */ } + spin_lock_irqsave(&sc->lmc_lock, flags); lmc_proto_close(sc); sc->if_type = new_type; lmc_proto_attach(sc); ret = lmc_proto_open(sc); + spin_unlock_irqrestore(&sc->lmc_lock, flags); break; } case LMCIOCGETXINFO: /*fold01*/ + spin_lock_irqsave(&sc->lmc_lock, flags); sc->lmc_xinfo.Magic0 = 0xBEEFCAFE; sc->lmc_xinfo.PciCardType = sc->lmc_cardtype; @@ -208,6 +212,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ sc->lmc_xinfo.MaxFrameSize = LMC_PKT_BUF_SZ; sc->lmc_xinfo.link_status = sc->lmc_media->get_link_status (sc); sc->lmc_xinfo.mii_reg16 = lmc_mii_readreg (sc, 0, 16); + spin_unlock_irqrestore(&sc->lmc_lock, flags); sc->lmc_xinfo.Magic1 = 0xDEADBEEF; @@ -220,6 +225,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ break; case LMCIOCGETLMCSTATS: + spin_lock_irqsave(&sc->lmc_lock, flags); if (sc->lmc_cardtype == LMC_CARDTYPE_T1) { lmc_mii_writereg(sc, 0, 17, T1FRAMER_FERR_LSB); sc->extra_stats.framingBitErrorCount += @@ -243,6 +249,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ sc->extra_stats.severelyErroredFrameCount += regVal & T1FRAMER_SEF_MASK; } + spin_unlock_irqrestore(&sc->lmc_lock, flags); if (copy_to_user(ifr->ifr_data, &sc->lmc_device->stats, sizeof(sc->lmc_device->stats)) || copy_to_user(ifr->ifr_data + sizeof(sc->lmc_device->stats), @@ -258,12 +265,14 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ break; } + spin_lock_irqsave(&sc->lmc_lock, flags); memset(&sc->lmc_device->stats, 0, sizeof(sc->lmc_device->stats)); memset(&sc->extra_stats, 0, sizeof(sc->extra_stats)); sc->extra_stats.check = STATCHECK; sc->extra_stats.version_size = (DRIVER_VERSION << 16) + sizeof(sc->lmc_device->stats) + sizeof(sc->extra_stats); sc->extra_stats.lmc_cardtype = sc->lmc_cardtype; + spin_unlock_irqrestore(&sc->lmc_lock, flags); ret = 0; break; @@ -282,8 +291,10 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ ret = -EFAULT; break; } + spin_lock_irqsave(&sc->lmc_lock, flags); sc->lmc_media->set_circuit_type(sc, ctl.circuit_type); sc->ictl.circuit_type = ctl.circuit_type; + spin_unlock_irqrestore(&sc->lmc_lock, flags); ret = 0; break; @@ -294,12 +305,14 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ break; } + spin_lock_irqsave(&sc->lmc_lock, flags); /* Reset driver and bring back to current state */ printk (" REG16 before reset +%04x\n", lmc_mii_readreg (sc, 0, 16)); lmc_running_reset (dev); printk (" REG16 after reset +%04x\n", lmc_mii_readreg (sc, 0, 16)); LMC_EVENT_LOG(LMC_EVENT_FORCEDRESET, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16)); + spin_unlock_irqrestore(&sc->lmc_lock, flags); ret = 0; break; @@ -338,14 +351,15 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ */ netif_stop_queue(dev); - if (copy_from_user(&xc, ifr->ifr_data, sizeof(struct lmc_xilinx_control))) { + if (copy_from_user(&xc, ifr->ifr_data, sizeof(struct lmc_xilinx_control))) { ret = -EFAULT; break; - } + } switch(xc.command){ case lmc_xilinx_reset: /*fold02*/ { u16 mii; + spin_lock_irqsave(&sc->lmc_lock, flags); mii = lmc_mii_readreg (sc, 0, 16); /* @@ -404,6 +418,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ lmc_led_off(sc, LMC_DS3_LED2); } } + spin_unlock_irqrestore(&sc->lmc_lock, flags); @@ -416,6 +431,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ { u16 mii; int timeout = 500000; + spin_lock_irqsave(&sc->lmc_lock, flags); mii = lmc_mii_readreg (sc, 0, 16); /* @@ -451,13 +467,14 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ */ while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 && (timeout-- > 0)) - ; + cpu_relax(); /* * stop driving Xilinx-related signals */ lmc_gpio_mkinput(sc, 0xff); + spin_unlock_irqrestore(&sc->lmc_lock, flags); ret = 0x0; @@ -493,6 +510,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data); + spin_lock_irqsave(&sc->lmc_lock, flags); lmc_gpio_mkinput(sc, 0xff); /* @@ -545,7 +563,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ */ while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 && (timeout-- > 0)) - ; + cpu_relax(); printk(KERN_DEBUG "%s: Waited %d for the Xilinx to clear it's memory\n", dev->name, 500000-timeout); @@ -588,6 +606,7 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET; lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + spin_unlock_irqrestore(&sc->lmc_lock, flags); kfree(data); @@ -611,8 +630,6 @@ int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ break; } - spin_unlock_irqrestore(&sc->lmc_lock, flags); /*fold01*/ - lmc_trace(dev, "lmc_ioctl out"); return ret; diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index 4518d0aa248..4917a94943b 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -548,7 +548,7 @@ static int pc300_tiocmset(struct tty_struct *tty, struct file *file, { st_cpc_tty_area *cpc_tty; - CPC_TTY_DBG("%s: set:%x clear:%x\n", __FUNCTION__, set, clear); + CPC_TTY_DBG("%s: set:%x clear:%x\n", __func__, set, clear); if (!tty || !tty->driver_data ) { CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n"); diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 6596cd0742b..f972fef87c9 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -856,7 +856,7 @@ prepare_to_send( struct sk_buff *skb, struct net_device *dev ) len = SBNI_MIN_LEN; nl->tx_buf_p = skb; - nl->tx_frameno = (len + nl->maxframe - 1) / nl->maxframe; + nl->tx_frameno = DIV_ROUND_UP(len, nl->maxframe); nl->framelen = len < nl->maxframe ? len : nl->maxframe; outb( inb( dev->base_addr + CSR0 ) | TR_REQ, dev->base_addr + CSR0 ); diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 243bd8d918f..ccd9cd35ecb 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -18,7 +18,8 @@ * DMA now uses get_free_page as kmalloc buffers may span a 64K * boundary. * - * Modified for SMP safety and SMP locking by Alan Cox <alan@redhat.com> + * Modified for SMP safety and SMP locking by Alan Cox + * <alan@lxorguk.ukuu.org.uk> * * Performance * diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h index 4f372396c51..85b3e785d48 100644 --- a/drivers/net/wan/z85230.h +++ b/drivers/net/wan/z85230.h @@ -2,7 +2,7 @@ * Description of Z8530 Z85C30 and Z85230 communications chips * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998 Alan Cox <alan@redhat.com> + * Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk> */ #ifndef _Z8530_H diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 9931b5ab59c..45bdf0b339b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -300,6 +300,19 @@ config LIBERTAS_DEBUG ---help--- Debugging support. +config LIBERTAS_THINFIRM + tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware" + depends on WLAN_80211 && MAC80211 + select FW_LOADER + ---help--- + A library for Marvell Libertas 8xxx devices using thinfirm. + +config LIBERTAS_THINFIRM_USB + tristate "Marvell Libertas 8388 USB 802.11b/g cards with thin firmware" + depends on LIBERTAS_THINFIRM && USB + ---help--- + A driver for Marvell Libertas 8388 USB devices using thinfirm. + config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) @@ -322,6 +335,9 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 select WIRELESS_EXT + select FW_LOADER + select CRYPTO + select CRYPTO_MICHAEL_MIC ---help--- A driver for 802.11b wireless cards based on the "Hermes" or Intersil HFA384x (Prism 2) MAC controller. This includes the vast @@ -411,7 +427,6 @@ config PCMCIA_HERMES config PCMCIA_SPECTRUM tristate "Symbol Spectrum24 Trilogy PCMCIA card support" depends on PCMCIA && HERMES - select FW_LOADER ---help--- This is a driver for 802.11b cards using RAM-loadable Symbol diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 59aa89ec6e8..59d2d805f60 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o -obj-$(CONFIG_HERMES) += orinoco.o hermes.o +obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o obj-$(CONFIG_APPLE_AIRPORT) += airport.o obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o @@ -48,6 +48,8 @@ obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o obj-$(CONFIG_USB_ZD1201) += zd1201.o obj-$(CONFIG_LIBERTAS) += libertas/ +obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/ + rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 3333d4596b8..b2c050b6889 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -765,11 +765,11 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) priv->soft_rx_crc = 0; switch (priv->mode) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA); priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: priv->nar &= ~ADM8211_NAR_PR; priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR; @@ -777,7 +777,7 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) if (priv->pdev->revision >= ADM8211_REV_BA) priv->soft_rx_crc = 1; break; - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST); priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR; break; @@ -1410,11 +1410,11 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MNTR) + if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: @@ -1437,7 +1437,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; } static int adm8211_init_rings(struct ieee80211_hw *dev) @@ -1556,7 +1556,7 @@ static int adm8211_start(struct ieee80211_hw *dev) ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE | ADM8211_IER_RCIE | ADM8211_IER_TCIE | ADM8211_IER_TDUIE | ADM8211_IER_GPTIE); - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; adm8211_update_mode(dev); ADM8211_CSR_WRITE(RDR, 0); @@ -1571,7 +1571,7 @@ static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->nar = 0; ADM8211_CSR_WRITE(NAR, 0); ADM8211_CSR_WRITE(IER, 0); @@ -1884,6 +1884,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; dev->max_signal = 100; /* FIXME: find better value */ @@ -1895,7 +1896,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; /* Power-on issue. EEPROM won't read correctly without */ if (pdev->revision >= ADM8211_REV_BA) { @@ -1985,7 +1986,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct adm8211_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_INVALID) { + if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { ieee80211_stop_queues(dev); adm8211_stop(dev); } @@ -2003,7 +2004,7 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->mode != IEEE80211_IF_TYPE_INVALID) { + if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { adm8211_start(dev); ieee80211_wake_queues(dev); } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index b5cd850a4a5..370133e492d 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1915,7 +1915,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct airo_info *ai = dev->priv; if (!skb) { - airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__); + airo_print_err(dev->name, "%s: skb == NULL!",__func__); return 0; } npacks = skb_queue_len (&ai->txq); @@ -1964,7 +1964,7 @@ static int mpi_send_packet (struct net_device *dev) if ((skb = skb_dequeue(&ai->txq)) == NULL) { airo_print_err(dev->name, "%s: Dequeue'd zero in send_packet()", - __FUNCTION__); + __func__); return 0; } @@ -2115,7 +2115,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { u32 *fids = priv->fids; if ( skb == NULL ) { - airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__); + airo_print_err(dev->name, "%s: skb == NULL!", __func__); return 0; } @@ -2186,7 +2186,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { } if ( skb == NULL ) { - airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__); + airo_print_err(dev->name, "%s: skb == NULL!", __func__); return 0; } @@ -4127,7 +4127,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid)) airo_print_err(ai->dev->name, "%s: MAC should be disabled (rid=%04x)", - __FUNCTION__, rid); + __func__, rid); memset(&cmd, 0, sizeof(cmd)); memset(&rsp, 0, sizeof(rsp)); @@ -4142,7 +4142,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, &ai->config_desc.rid_desc, sizeof(Rid)); if (len < 4 || len > 2047) { - airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len); + airo_print_err(ai->dev->name, "%s: len=%d", __func__, len); rc = -1; } else { memcpy((char *)ai->config_desc.virtual_host_addr, @@ -4151,9 +4151,9 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, rc = issuecommand(ai, &cmd, &rsp); if ((rc & 0xff00) != 0) { airo_print_err(ai->dev->name, "%s: Write rid Error %d", - __FUNCTION__, rc); + __func__, rc); airo_print_err(ai->dev->name, "%s: Cmd=%04x", - __FUNCTION__, cmd.cmd); + __func__, cmd.cmd); } if ((rsp.status & 0x7f00)) @@ -7107,7 +7107,7 @@ static int airo_get_aplist(struct net_device *dev, */ static int airo_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + struct iw_point *dwrq, char *extra) { struct airo_info *ai = dev->priv; diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index f12355398fe..27696c20f4c 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -147,7 +147,7 @@ static int airo_probe(struct pcmcia_device *p_dev) DEBUG(0, "airo_attach()\n"); /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = NULL; @@ -206,126 +206,123 @@ static void airo_detach(struct pcmcia_device *link) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) +static int airo_cs_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + win_req_t *req = priv_data; + + if (cfg->index == 0) + return -ENODEV; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + p_dev->conf.Attributes |= CONF_ENABLE_SPKR; + p_dev->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + return -ENODEV; + + /* + Now set up a common memory window, if needed. There is room + in the struct pcmcia_device structure for one memory window handle, + but if the base addresses need to be saved, or if multiple + windows are needed, the info should go in the private data + structure for this device. + + Note that the memory window base is a physical address, and + needs to be mapped to virtual space with ioremap() before it + is used. + */ + if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) { + cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; + memreq_t map; + req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + req->Base = mem->win[0].host_addr; + req->Size = mem->win[0].len; + req->AccessSpeed = 0; + if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0) + return -ENODEV; + map.Page = 0; + map.CardOffset = mem->win[0].card_addr; + if (pcmcia_map_mem_page(p_dev->win, &map) != 0) + return -ENODEV; + } + /* If we got this far, we're cool! */ + return 0; +} + + static int airo_config(struct pcmcia_device *link) { - tuple_t tuple; - cisparse_t parse; local_info_t *dev; + win_req_t *req; int last_fn, last_ret; - u_char buf[64]; - win_req_t req; - memreq_t map; dev = link->priv; DEBUG(0, "airo_config(0x%p)\n", link); + req = kzalloc(sizeof(win_req_t), GFP_KERNEL); + if (!req) + return -ENOMEM; + + /* + * In this loop, we scan the CIS for configuration table + * entries, each of which describes a valid card + * configuration, including voltage, IO window, memory window, + * and interrupt settings. + * + * We make no assumptions about the card to be configured: we + * use just the information available in the CIS. In an ideal + * world, this would work for any PCMCIA card, but it requires + * a complete and accurate CIS. In practice, a driver usually + * "knows" most of these things without consulting the CIS, + * and most client drivers will only use the CIS to fill in + * implementation-defined details. + */ + last_ret = pcmcia_loop_config(link, airo_cs_config_check, req); + if (last_ret) + goto failed; + /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. */ - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (1) { - cistpl_cftable_entry_t dflt = { 0 }; - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(link, &tuple) != 0 || - pcmcia_parse_tuple(link, &tuple, &parse) != 0) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; - if (cfg->index == 0) goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) - link->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; - else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) - link->conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - - /* - Now set up a common memory window, if needed. There is room - in the struct pcmcia_device structure for one memory window handle, - but if the base addresses need to be saved, or if multiple - windows are needed, the info should go in the private data - structure for this device. - - Note that the memory window base is a physical address, and - needs to be mapped to virtual space with ioremap() before it - is used. - */ - if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { - cistpl_mem_t *mem = - (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; - req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; - req.Base = mem->win[0].host_addr; - req.Size = mem->win[0].len; - req.AccessSpeed = 0; - if (pcmcia_request_window(&link, &req, &link->win) != 0) - goto next_entry; - map.Page = 0; map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(link->win, &map) != 0) - goto next_entry; - } - /* If we got this far, we're cool! */ - break; - - next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); - } - - /* - Allocate an interrupt line. Note that this does not assign a - handler to the interrupt, unless the 'Handler' member of the - irq structure is initialized. - */ if (link->conf.Attributes & CONF_ENABLE_IRQ) CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); @@ -362,14 +359,17 @@ static int airo_config(struct pcmcia_device *link) printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1); if (link->win) - printk(", mem 0x%06lx-0x%06lx", req.Base, - req.Base+req.Size-1); + printk(", mem 0x%06lx-0x%06lx", req->Base, + req->Base+req->Size-1); printk("\n"); + kfree(req); return 0; cs_failed: cs_error(link, last_fn, last_ret); + failed: airo_release(link); + kfree(req); return -ENODEV; } /* airo_config */ diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 6f7eb9f5922..ce03a2e865f 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -180,7 +180,8 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) } /* Allocate space for private device-specific data */ - dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); + dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, + airport_hard_reset, NULL); if (! dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); return -ENODEV; diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath5k/Makefile index 564ecd0c5d4..719cfaef708 100644 --- a/drivers/net/wireless/ath5k/Makefile +++ b/drivers/net/wireless/ath5k/Makefile @@ -1,6 +1,14 @@ -ath5k-y += base.o -ath5k-y += hw.o +ath5k-y += caps.o ath5k-y += initvals.o +ath5k-y += eeprom.o +ath5k-y += gpio.o +ath5k-y += desc.o +ath5k-y += dma.o +ath5k-y += qcu.o +ath5k-y += pcu.o ath5k-y += phy.o +ath5k-y += reset.o +ath5k-y += attach.o +ath5k-y += base.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 9102eea3c8b..53ea439aff4 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -18,18 +18,23 @@ #ifndef _ATH5K_H #define _ATH5K_H -/* Set this to 1 to disable regulatory domain restrictions for channel tests. - * WARNING: This is for debuging only and has side effects (eg. scan takes too - * long and results timeouts). It's also illegal to tune to some of the - * supported frequencies in some countries, so use this at your own risk, - * you've been warned. */ +/* TODO: Clean up channel debuging -doesn't work anyway- and start + * working on reg. control code using all available eeprom information + * -rev. engineering needed- */ #define CHAN_DEBUG 0 #include <linux/io.h> #include <linux/types.h> #include <net/mac80211.h> -#include "hw.h" +/* RX/TX descriptor hw structs + * TODO: Driver part should only see sw structs */ +#include "desc.h" + +/* EEPROM structs/offsets + * TODO: Make a more generic struct (eg. add more stuff to ath5k_capabilities) + * and clean up common bits, then introduce set/get functions in eeprom.c */ +#include "eeprom.h" /* PCI IDs */ #define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */ @@ -87,7 +92,92 @@ ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__) /* + * AR5K REGISTER ACCESS + */ + +/* Some macros to read/write fields */ + +/* First shift, then mask */ +#define AR5K_REG_SM(_val, _flags) \ + (((_val) << _flags##_S) & (_flags)) + +/* First mask, then shift */ +#define AR5K_REG_MS(_val, _flags) \ + (((_val) & (_flags)) >> _flags##_S) + +/* Some registers can hold multiple values of interest. For this + * reason when we want to write to these registers we must first + * retrieve the values which we do not want to clear (lets call this + * old_data) and then set the register with this and our new_value: + * ( old_data | new_value) */ +#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val) \ + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \ + (((_val) << _flags##_S) & (_flags)), _reg) + +#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask) \ + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & \ + (_mask)) | (_flags), _reg) + +#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags) \ + ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg) + +#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \ + ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg) + +/* Access to PHY registers */ +#define AR5K_PHY_READ(ah, _reg) \ + ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2)) + +#define AR5K_PHY_WRITE(ah, _reg, _val) \ + ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2)) + +/* Access QCU registers per queue */ +#define AR5K_REG_READ_Q(ah, _reg, _queue) \ + (ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \ + +#define AR5K_REG_WRITE_Q(ah, _reg, _queue) \ + ath5k_hw_reg_write(ah, (1 << _queue), _reg) + +#define AR5K_Q_ENABLE_BITS(_reg, _queue) do { \ + _reg |= 1 << _queue; \ +} while (0) + +#define AR5K_Q_DISABLE_BITS(_reg, _queue) do { \ + _reg &= ~(1 << _queue); \ +} while (0) + +/* Used while writing initvals */ +#define AR5K_REG_WAIT(_i) do { \ + if (_i % 64) \ + udelay(1); \ +} while (0) + +/* Register dumps are done per operation mode */ +#define AR5K_INI_RFGAIN_5GHZ 0 +#define AR5K_INI_RFGAIN_2GHZ 1 + +/* TODO: Clean this up */ +#define AR5K_INI_VAL_11A 0 +#define AR5K_INI_VAL_11A_TURBO 1 +#define AR5K_INI_VAL_11B 2 +#define AR5K_INI_VAL_11G 3 +#define AR5K_INI_VAL_11G_TURBO 4 +#define AR5K_INI_VAL_XR 0 +#define AR5K_INI_VAL_MAX 5 + +#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS +#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS + +/* Used for BSSID etc manipulation */ +#define AR5K_LOW_ID(_a)( \ +(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \ +) + +#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8) + +/* * Some tuneable values (these should be changeable by the user) + * TODO: Make use of them and add more options OR use debug/configfs */ #define AR5K_TUNE_DMA_BEACON_RESP 2 #define AR5K_TUNE_SW_BEACON_RESP 10 @@ -98,13 +188,13 @@ #define AR5K_TUNE_REGISTER_TIMEOUT 20000 /* Register for RSSI threshold has a mask of 0xff, so 255 seems to * be the max value. */ -#define AR5K_TUNE_RSSI_THRES 129 +#define AR5K_TUNE_RSSI_THRES 129 /* This must be set when setting the RSSI threshold otherwise it can * prevent a reset. If AR5K_RSSI_THR is read after writing to it * the BMISS_THRES will be seen as 0, seems harware doesn't keep * track of it. Max value depends on harware. For AR5210 this is just 7. * For AR5211+ this seems to be up to 255. */ -#define AR5K_TUNE_BMISS_THRES 7 +#define AR5K_TUNE_BMISS_THRES 7 #define AR5K_TUNE_REGISTER_DWELL_TIME 20000 #define AR5K_TUNE_BEACON_INTERVAL 100 #define AR5K_TUNE_AIFS 2 @@ -123,6 +213,55 @@ #define AR5K_TUNE_ANT_DIVERSITY true #define AR5K_TUNE_HWTXTRIES 4 +#define AR5K_INIT_CARR_SENSE_EN 1 + +/*Swap RX/TX Descriptor for big endian archs*/ +#if defined(__BIG_ENDIAN) +#define AR5K_INIT_CFG ( \ + AR5K_CFG_SWTD | AR5K_CFG_SWRD \ +) +#else +#define AR5K_INIT_CFG 0x00000000 +#endif + +/* Initial values */ +#define AR5K_INIT_TX_LATENCY 502 +#define AR5K_INIT_USEC 39 +#define AR5K_INIT_USEC_TURBO 79 +#define AR5K_INIT_USEC_32 31 +#define AR5K_INIT_SLOT_TIME 396 +#define AR5K_INIT_SLOT_TIME_TURBO 480 +#define AR5K_INIT_ACK_CTS_TIMEOUT 1024 +#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800 +#define AR5K_INIT_PROG_IFS 920 +#define AR5K_INIT_PROG_IFS_TURBO 960 +#define AR5K_INIT_EIFS 3440 +#define AR5K_INIT_EIFS_TURBO 6880 +#define AR5K_INIT_SIFS 560 +#define AR5K_INIT_SIFS_TURBO 480 +#define AR5K_INIT_SH_RETRY 10 +#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY +#define AR5K_INIT_SSH_RETRY 32 +#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY +#define AR5K_INIT_TX_RETRY 10 + +#define AR5K_INIT_TRANSMIT_LATENCY ( \ + (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ + (AR5K_INIT_USEC) \ +) +#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \ + (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ + (AR5K_INIT_USEC_TURBO) \ +) +#define AR5K_INIT_PROTO_TIME_CNTRL ( \ + (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \ + (AR5K_INIT_PROG_IFS) \ +) +#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \ + (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \ + (AR5K_INIT_PROG_IFS_TURBO) \ +) + /* token to use for aifs, cwmin, cwmax in MadWiFi */ #define AR5K_TXQ_USEDEFAULT ((u32) -1) @@ -142,7 +281,9 @@ enum ath5k_radio { AR5K_RF5112 = 2, AR5K_RF2413 = 3, AR5K_RF5413 = 4, - AR5K_RF2425 = 5, + AR5K_RF2316 = 5, + AR5K_RF2317 = 6, + AR5K_RF2425 = 7, }; /* @@ -150,7 +291,7 @@ enum ath5k_radio { */ enum ath5k_srev_type { - AR5K_VERSION_VER, + AR5K_VERSION_MAC, AR5K_VERSION_RAD, }; @@ -162,23 +303,24 @@ struct ath5k_srev_name { #define AR5K_SREV_UNKNOWN 0xffff -#define AR5K_SREV_VER_AR5210 0x00 -#define AR5K_SREV_VER_AR5311 0x10 -#define AR5K_SREV_VER_AR5311A 0x20 -#define AR5K_SREV_VER_AR5311B 0x30 -#define AR5K_SREV_VER_AR5211 0x40 -#define AR5K_SREV_VER_AR5212 0x50 -#define AR5K_SREV_VER_AR5213 0x55 -#define AR5K_SREV_VER_AR5213A 0x59 -#define AR5K_SREV_VER_AR2413 0x78 -#define AR5K_SREV_VER_AR2414 0x79 -#define AR5K_SREV_VER_AR2424 0xa0 /* PCI-E */ -#define AR5K_SREV_VER_AR5424 0xa3 /* PCI-E */ -#define AR5K_SREV_VER_AR5413 0xa4 -#define AR5K_SREV_VER_AR5414 0xa5 -#define AR5K_SREV_VER_AR5416 0xc0 /* PCI-E */ -#define AR5K_SREV_VER_AR5418 0xca /* PCI-E */ -#define AR5K_SREV_VER_AR2425 0xe2 /* PCI-E */ +#define AR5K_SREV_AR5210 0x00 /* Crete */ +#define AR5K_SREV_AR5311 0x10 /* Maui 1 */ +#define AR5K_SREV_AR5311A 0x20 /* Maui 2 */ +#define AR5K_SREV_AR5311B 0x30 /* Spirit */ +#define AR5K_SREV_AR5211 0x40 /* Oahu */ +#define AR5K_SREV_AR5212 0x50 /* Venice */ +#define AR5K_SREV_AR5213 0x55 /* ??? */ +#define AR5K_SREV_AR5213A 0x59 /* Hainan */ +#define AR5K_SREV_AR2413 0x78 /* Griffin lite */ +#define AR5K_SREV_AR2414 0x70 /* Griffin */ +#define AR5K_SREV_AR5424 0x90 /* Condor */ +#define AR5K_SREV_AR5413 0xa4 /* Eagle lite */ +#define AR5K_SREV_AR5414 0xa0 /* Eagle */ +#define AR5K_SREV_AR2415 0xb0 /* Cobra */ +#define AR5K_SREV_AR5416 0xc0 /* PCI-E */ +#define AR5K_SREV_AR5418 0xca /* PCI-E */ +#define AR5K_SREV_AR2425 0xe0 /* Swan */ +#define AR5K_SREV_AR2417 0xf0 /* Nala */ #define AR5K_SREV_RAD_5110 0x00 #define AR5K_SREV_RAD_5111 0x10 @@ -190,13 +332,22 @@ struct ath5k_srev_name { #define AR5K_SREV_RAD_2112 0x40 #define AR5K_SREV_RAD_2112A 0x45 #define AR5K_SREV_RAD_2112B 0x46 -#define AR5K_SREV_RAD_SC0 0x50 /* Found on 2413/2414 */ -#define AR5K_SREV_RAD_SC1 0x60 /* Found on 5413/5414 */ -#define AR5K_SREV_RAD_SC2 0xa0 /* Found on 2424-5/5424 */ -#define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ +#define AR5K_SREV_RAD_2413 0x50 +#define AR5K_SREV_RAD_5413 0x60 +#define AR5K_SREV_RAD_2316 0x70 +#define AR5K_SREV_RAD_2317 0x80 +#define AR5K_SREV_RAD_5424 0xa0 /* Mostly same as 5413 */ +#define AR5K_SREV_RAD_2425 0xa2 +#define AR5K_SREV_RAD_5133 0xc0 + +#define AR5K_SREV_PHY_5211 0x30 +#define AR5K_SREV_PHY_5212 0x41 +#define AR5K_SREV_PHY_2112B 0x43 +#define AR5K_SREV_PHY_2413 0x45 +#define AR5K_SREV_PHY_5413 0x61 +#define AR5K_SREV_PHY_2425 0x70 /* IEEE defs */ - #define IEEE80211_MAX_LEN 2500 /* TODO add support to mac80211 for vendor-specific rates and modes */ @@ -268,27 +419,21 @@ enum ath5k_driver_mode { AR5K_MODE_MAX = 5 }; -/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */ -#define AR5K_SET_SHORT_PREAMBLE 0x04 - -#define HAS_SHPREAMBLE(_ix) \ - (rt->rates[_ix].modulation == IEEE80211_RATE_SHORT_PREAMBLE) -#define SHPREAMBLE_FLAG(_ix) \ - (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0) - /****************\ TX DEFINITIONS \****************/ /* - * TX Status + * TX Status descriptor */ struct ath5k_tx_status { u16 ts_seqnum; u16 ts_tstamp; u8 ts_status; - u8 ts_rate; + u8 ts_rate[4]; + u8 ts_retry[4]; + u8 ts_final_idx; s8 ts_rssi; u8 ts_shortretry; u8 ts_longretry; @@ -354,7 +499,6 @@ enum ath5k_tx_queue_id { AR5K_TX_QUEUE_ID_XR_DATA = 9, }; - /* * Flags to set hw queue's parameters... */ @@ -387,7 +531,8 @@ struct ath5k_txq_info { /* * Transmit packet types. - * These are not fully used inside OpenHAL yet + * used on tx control descriptor + * TODO: Use them inside base.c corectly */ enum ath5k_pkt_type { AR5K_PKT_TYPE_NORMAL = 0, @@ -430,7 +575,7 @@ enum ath5k_dmasize { \****************/ /* - * RX Status + * RX Status descriptor */ struct ath5k_rx_status { u16 rs_datalen; @@ -494,34 +639,59 @@ struct ath5k_beacon_state { #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) +/*******************************\ + GAIN OPTIMIZATION DEFINITIONS +\*******************************/ + +enum ath5k_rfgain { + AR5K_RFGAIN_INACTIVE = 0, + AR5K_RFGAIN_READ_REQUESTED, + AR5K_RFGAIN_NEED_CHANGE, +}; + +#define AR5K_GAIN_CRN_FIX_BITS_5111 4 +#define AR5K_GAIN_CRN_FIX_BITS_5112 7 +#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112 +#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15 +#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20 +#define AR5K_GAIN_CCK_PROBE_CORR 5 +#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15 +#define AR5K_GAIN_STEP_COUNT 10 +#define AR5K_GAIN_PARAM_TX_CLIP 0 +#define AR5K_GAIN_PARAM_PD_90 1 +#define AR5K_GAIN_PARAM_PD_84 2 +#define AR5K_GAIN_PARAM_GAIN_SEL 3 +#define AR5K_GAIN_PARAM_MIX_ORN 0 +#define AR5K_GAIN_PARAM_PD_138 1 +#define AR5K_GAIN_PARAM_PD_137 2 +#define AR5K_GAIN_PARAM_PD_136 3 +#define AR5K_GAIN_PARAM_PD_132 4 +#define AR5K_GAIN_PARAM_PD_131 5 +#define AR5K_GAIN_PARAM_PD_130 6 +#define AR5K_GAIN_CHECK_ADJUST(_g) \ + ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) + +struct ath5k_gain_opt_step { + s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; + s32 gos_gain; +}; + +struct ath5k_gain { + u32 g_step_idx; + u32 g_current; + u32 g_target; + u32 g_low; + u32 g_high; + u32 g_f_corr; + u32 g_active; + const struct ath5k_gain_opt_step *g_step; +}; + + /********************\ COMMON DEFINITIONS \********************/ -/* - * Atheros hardware descriptor - * This is read and written to by the hardware - */ -struct ath5k_desc { - u32 ds_link; /* physical address of the next descriptor */ - u32 ds_data; /* physical address of data buffer (skb) */ - - union { - struct ath5k_hw_5210_tx_desc ds_tx5210; - struct ath5k_hw_5212_tx_desc ds_tx5212; - struct ath5k_hw_all_rx_desc ds_rx; - } ud; -} __packed; - -#define AR5K_RXDESC_INTREQ 0x0020 - -#define AR5K_TXDESC_CLRDMASK 0x0001 -#define AR5K_TXDESC_NOACK 0x0002 /*[5211+]*/ -#define AR5K_TXDESC_RTSENA 0x0004 -#define AR5K_TXDESC_CTSENA 0x0008 -#define AR5K_TXDESC_INTREQ 0x0010 -#define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/ - #define AR5K_SLOT_TIME_9 396 #define AR5K_SLOT_TIME_20 880 #define AR5K_SLOT_TIME_MAX 0xffff @@ -553,167 +723,79 @@ struct ath5k_desc { #define CHANNEL_MODES CHANNEL_ALL /* - * Used internaly in OpenHAL (ar5211.c/ar5212.c - * for reset_tx_queue). Also see struct struct ieee80211_channel. + * Used internaly for reset_tx_queue). + * Also see struct struct ieee80211_channel. */ #define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0) #define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0) /* - * The following structure will be used to map 2GHz channels to + * The following structure is used to map 2GHz channels to * 5GHz Atheros channels. + * TODO: Clean up */ struct ath5k_athchan_2ghz { u32 a2_flags; u16 a2_athchan; }; -/* - * Rate definitions - * TODO: Clean them up or move them on mac80211 -most of these infos are - * used by the rate control algorytm on MadWiFi. - */ -/* Max number of rates on the rate table and what it seems - * Atheros hardware supports */ -#define AR5K_MAX_RATES 32 +/******************\ + RATE DEFINITIONS +\******************/ /** - * struct ath5k_rate - rate structure - * @valid: is this a valid rate for rate control (remove) - * @modulation: respective mac80211 modulation - * @rate_kbps: rate in kbit/s - * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on - * &struct ath5k_rx_status.rs_rate and on TX on - * &struct ath5k_tx_status.ts_rate. Seems the ar5xxx harware supports - * up to 32 rates, indexed by 1-32. This means we really only need - * 6 bits for the rate_code. - * @dot11_rate: respective IEEE-802.11 rate value - * @control_rate: index of rate assumed to be used to send control frames. - * This can be used to set override the value on the rate duration - * registers. This is only useful if we can override in the harware at - * what rate we want to send control frames at. Note that IEEE-802.11 - * Ch. 9.6 (after IEEE 802.11g changes) defines the rate at which we - * should send ACK/CTS, if we change this value we can be breaking - * the spec. + * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32. * - * This structure is used to get the RX rate or set the TX rate on the + * The rate code is used to get the RX rate or set the TX rate on the * hardware descriptors. It is also used for internal modulation control * and settings. * - * On RX after the &struct ath5k_desc is parsed by the appropriate - * ah_proc_rx_desc() the respective hardware rate value is set in - * &struct ath5k_rx_status.rs_rate. On TX the desired rate is set in - * &struct ath5k_tx_status.ts_rate which is later used to setup the - * &struct ath5k_desc correctly. This is the hardware rate map we are - * aware of: + * This is the hardware rate map we are aware of: * - * rate_code 1 2 3 4 5 6 7 8 + * rate_code 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 * rate_kbps 3000 1000 ? ? ? 2000 500 48000 * - * rate_code 9 10 11 12 13 14 15 16 + * rate_code 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 * rate_kbps 24000 12000 6000 54000 36000 18000 9000 ? * * rate_code 17 18 19 20 21 22 23 24 * rate_kbps ? ? ? ? ? ? ? 11000 * * rate_code 25 26 27 28 29 30 31 32 - * rate_kbps 5500 2000 1000 ? ? ? ? ? + * rate_kbps 5500 2000 1000 11000S 5500S 2000S ? ? * + * "S" indicates CCK rates with short preamble. + * + * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the + * lowest 4 bits, so they are the same as below with a 0xF mask. + * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M). + * We handle this in ath5k_setup_bands(). */ -struct ath5k_rate { - u8 valid; - u32 modulation; - u16 rate_kbps; - u8 rate_code; - u8 dot11_rate; - u8 control_rate; -}; - -/* XXX: GRR all this stuff to get leds blinking ??? (check out setcurmode) */ -struct ath5k_rate_table { - u16 rate_count; - u8 rate_code_to_index[AR5K_MAX_RATES]; /* Back-mapping */ - struct ath5k_rate rates[AR5K_MAX_RATES]; -}; - -/* - * Rate tables... - * TODO: CLEAN THIS !!! - */ -#define AR5K_RATES_11A { 8, { \ - 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \ - 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \ - 255, 255, 255, 255, 255, 255, 255, 255 }, { \ - { 1, 0, 6000, 11, 140, 0 }, \ - { 1, 0, 9000, 15, 18, 0 }, \ - { 1, 0, 12000, 10, 152, 2 }, \ - { 1, 0, 18000, 14, 36, 2 }, \ - { 1, 0, 24000, 9, 176, 4 }, \ - { 1, 0, 36000, 13, 72, 4 }, \ - { 1, 0, 48000, 8, 96, 4 }, \ - { 1, 0, 54000, 12, 108, 4 } } \ -} - -#define AR5K_RATES_11B { 4, { \ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ - 3, 2, 1, 0, 255, 255, 255, 255 }, { \ - { 1, 0, 1000, 27, 130, 0 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 132, 1 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 139, 1 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 150, 1 } } \ -} - -#define AR5K_RATES_11G { 12, { \ - 255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4, \ - 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \ - 3, 2, 1, 0, 255, 255, 255, 255 }, { \ - { 1, 0, 1000, 27, 2, 0 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 4, 1 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 11, 1 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 22, 1 }, \ - { 0, 0, 6000, 11, 12, 4 }, \ - { 0, 0, 9000, 15, 18, 4 }, \ - { 1, 0, 12000, 10, 24, 6 }, \ - { 1, 0, 18000, 14, 36, 6 }, \ - { 1, 0, 24000, 9, 48, 8 }, \ - { 1, 0, 36000, 13, 72, 8 }, \ - { 1, 0, 48000, 8, 96, 8 }, \ - { 1, 0, 54000, 12, 108, 8 } } \ -} - -#define AR5K_RATES_TURBO { 8, { \ - 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \ - 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \ - 255, 255, 255, 255, 255, 255, 255, 255 }, { \ - { 1, MODULATION_TURBO, 6000, 11, 140, 0 }, \ - { 1, MODULATION_TURBO, 9000, 15, 18, 0 }, \ - { 1, MODULATION_TURBO, 12000, 10, 152, 2 }, \ - { 1, MODULATION_TURBO, 18000, 14, 36, 2 }, \ - { 1, MODULATION_TURBO, 24000, 9, 176, 4 }, \ - { 1, MODULATION_TURBO, 36000, 13, 72, 4 }, \ - { 1, MODULATION_TURBO, 48000, 8, 96, 4 }, \ - { 1, MODULATION_TURBO, 54000, 12, 108, 4 } } \ -} +#define AR5K_MAX_RATES 32 -#define AR5K_RATES_XR { 12, { \ - 255, 3, 1, 255, 255, 255, 2, 0, 10, 8, 6, 4, \ - 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \ - 255, 255, 255, 255, 255, 255, 255, 255 }, { \ - { 1, MODULATION_XR, 500, 7, 129, 0 }, \ - { 1, MODULATION_XR, 1000, 2, 139, 1 }, \ - { 1, MODULATION_XR, 2000, 6, 150, 2 }, \ - { 1, MODULATION_XR, 3000, 1, 150, 3 }, \ - { 1, 0, 6000, 11, 140, 4 }, \ - { 1, 0, 9000, 15, 18, 4 }, \ - { 1, 0, 12000, 10, 152, 6 }, \ - { 1, 0, 18000, 14, 36, 6 }, \ - { 1, 0, 24000, 9, 176, 8 }, \ - { 1, 0, 36000, 13, 72, 8 }, \ - { 1, 0, 48000, 8, 96, 8 }, \ - { 1, 0, 54000, 12, 108, 8 } } \ -} +/* B */ +#define ATH5K_RATE_CODE_1M 0x1B +#define ATH5K_RATE_CODE_2M 0x1A +#define ATH5K_RATE_CODE_5_5M 0x19 +#define ATH5K_RATE_CODE_11M 0x18 +/* A and G */ +#define ATH5K_RATE_CODE_6M 0x0B +#define ATH5K_RATE_CODE_9M 0x0F +#define ATH5K_RATE_CODE_12M 0x0A +#define ATH5K_RATE_CODE_18M 0x0E +#define ATH5K_RATE_CODE_24M 0x09 +#define ATH5K_RATE_CODE_36M 0x0D +#define ATH5K_RATE_CODE_48M 0x08 +#define ATH5K_RATE_CODE_54M 0x0C +/* XR */ +#define ATH5K_RATE_CODE_XR_500K 0x07 +#define ATH5K_RATE_CODE_XR_1M 0x02 +#define ATH5K_RATE_CODE_XR_2M 0x06 +#define ATH5K_RATE_CODE_XR_3M 0x01 + +/* adding this flag to rate_code enables short preamble */ +#define AR5K_SET_SHORT_PREAMBLE 0x04 /* * Crypto definitions @@ -735,7 +817,6 @@ struct ath5k_rate_table { return (false); \ } while (0) - enum ath5k_ant_setting { AR5K_ANT_VARIABLE = 0, /* variable by programming */ AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ @@ -846,7 +927,8 @@ enum ath5k_power_mode { /* * These match net80211 definitions (not used in - * d80211). + * mac80211). + * TODO: Clean this up */ #define AR5K_LED_INIT 0 /*IEEE80211_S_INIT*/ #define AR5K_LED_SCAN 1 /*IEEE80211_S_SCAN*/ @@ -862,7 +944,8 @@ enum ath5k_power_mode { /* * Chipset capabilities -see ath5k_hw_get_capability- * get_capability function is not yet fully implemented - * in OpenHAL so most of these don't work yet... + * in ath5k so most of these don't work yet... + * TODO: Implement these & merge with _TUNE_ stuff above */ enum ath5k_capability_type { AR5K_CAP_REG_DMN = 0, /* Used to get current reg. domain id */ @@ -931,6 +1014,7 @@ struct ath5k_capabilities { #define AR5K_MAX_GPIO 10 #define AR5K_MAX_RF_BANKS 8 +/* TODO: Clean up and merge with ath5k_softc */ struct ath5k_hw { u32 ah_magic; @@ -939,7 +1023,7 @@ struct ath5k_hw { enum ath5k_int ah_imr; - enum ieee80211_if_types ah_op_mode; + enum nl80211_iftype ah_op_mode; enum ath5k_power_mode ah_power_mode; struct ieee80211_channel ah_current_channel; bool ah_turbo; @@ -1023,11 +1107,13 @@ struct ath5k_hw { /* * Function pointers */ + int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc, + u32 size, unsigned int flags); int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); - int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, + int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, @@ -1040,33 +1126,38 @@ struct ath5k_hw { * Prototypes */ -/* General Functions */ -extern int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set); /* Attach/Detach Functions */ extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version); -extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, unsigned int mode); extern void ath5k_hw_detach(struct ath5k_hw *ah); + /* Reset Functions */ -extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel); +extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); +extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel); /* Power management functions */ extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); + /* DMA Related Functions */ -extern void ath5k_hw_start_rx(struct ath5k_hw *ah); +extern void ath5k_hw_start_rx_dma(struct ath5k_hw *ah); extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah); -extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah); -extern void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr); -extern int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue); +extern u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah); +extern void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr); +extern int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue); extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue); -extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue); -extern int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr); +extern u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue); +extern int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, + u32 phys_addr); extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase); /* Interrupt handling */ extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); -extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask); +extern enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum +ath5k_int new_mask); extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats); + /* EEPROM access functions */ -extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain); +extern int ath5k_eeprom_init(struct ath5k_hw *ah); +extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); + /* Protocol Control Unit Functions */ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); /* BSSID Functions */ @@ -1076,14 +1167,14 @@ extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); /* Receive start/stop functions */ extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); -extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah); +extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah); /* RX Filter functions */ extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1); -extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index); +extern int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index); extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index); extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah); extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter); -/* Beacon related functions */ +/* Beacon control functions */ extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah); extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah); @@ -1105,61 +1196,129 @@ extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry); extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac); extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac); + /* Queue Control Unit, DFS Control Unit Functions */ -extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info); -extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *queue_info); extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info); +extern int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, + const struct ath5k_txq_info *queue_info); +extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, + enum ath5k_tx_queue queue_type, + struct ath5k_txq_info *queue_info); +extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue); extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue); -extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); -extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time); extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah); +extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time); + /* Hardware Descriptor Functions */ -extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags); +extern int ath5k_hw_init_desc_functions(struct ath5k_hw *ah); + /* GPIO Functions */ extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state); -extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio); extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio); +extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio); extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); + /* Misc functions */ +int ath5k_hw_set_capabilities(struct ath5k_hw *ah); extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); - +extern int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id); +extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah); /* Initial register settings functions */ extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel); + /* Initialize RF */ extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode); extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq); extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah); extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah); - - /* PHY/RF channel functions */ extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); /* PHY calibration */ extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); -extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); +extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); /* Misc PHY functions */ extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant); extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); -extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); +extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); /* TX power setup */ extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower); extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power); +/* + * Functions used internaly + */ +/* + * Translate usec to hw clock units + */ +static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) +{ + return turbo ? (usec * 80) : (usec * 40); +} + +/* + * Translate hw clock units to usec + */ +static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) +{ + return turbo ? (clock / 80) : (clock / 40); +} + +/* + * Read from a register + */ static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg) { return ioread32(ah->ah_iobase + reg); } +/* + * Write to a register + */ static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) { iowrite32(val, ah->ah_iobase + reg); } +#if defined(_ATH5K_RESET) || defined(_ATH5K_PHY) +/* + * Check if a register write has been completed + */ +static int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, + u32 val, bool is_set) +{ + int i; + u32 data; + + for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { + data = ath5k_hw_reg_read(ah, reg); + if (is_set && (data & flag)) + break; + else if ((data & flag) == val) + break; + udelay(15); + } + + return (i <= 0) ? -EAGAIN : 0; +} +#endif + +static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) +{ + u32 retval = 0, bit, i; + + for (i = 0; i < bits; i++) { + bit = (val >> i) & 1; + retval = (retval << 1) | bit; + } + + return retval; +} + #endif diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c new file mode 100644 index 00000000000..51d569883cd --- /dev/null +++ b/drivers/net/wireless/ath5k/attach.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * + * Permission to use, copy, modify, and 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. + * + */ + +/*************************************\ +* Attach/Detach Functions and helpers * +\*************************************/ + +#include <linux/pci.h> +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/** + * ath5k_hw_post - Power On Self Test helper function + * + * @ah: The &struct ath5k_hw + */ +static int ath5k_hw_post(struct ath5k_hw *ah) +{ + + int i, c; + u16 cur_reg; + u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)}; + u32 var_pattern; + u32 static_pattern[4] = { + 0x55555555, 0xaaaaaaaa, + 0x66666666, 0x99999999 + }; + u32 init_val; + u32 cur_val; + + for (c = 0; c < 2; c++) { + + cur_reg = regs[c]; + + /* Save previous value */ + init_val = ath5k_hw_reg_read(ah, cur_reg); + + for (i = 0; i < 256; i++) { + var_pattern = i << 16 | i; + ath5k_hw_reg_write(ah, var_pattern, cur_reg); + cur_val = ath5k_hw_reg_read(ah, cur_reg); + + if (cur_val != var_pattern) { + ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); + return -EAGAIN; + } + + /* Found on ndiswrapper dumps */ + var_pattern = 0x0039080f; + ath5k_hw_reg_write(ah, var_pattern, cur_reg); + } + + for (i = 0; i < 4; i++) { + var_pattern = static_pattern[i]; + ath5k_hw_reg_write(ah, var_pattern, cur_reg); + cur_val = ath5k_hw_reg_read(ah, cur_reg); + + if (cur_val != var_pattern) { + ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); + return -EAGAIN; + } + + /* Found on ndiswrapper dumps */ + var_pattern = 0x003b080f; + ath5k_hw_reg_write(ah, var_pattern, cur_reg); + } + + /* Restore previous value */ + ath5k_hw_reg_write(ah, init_val, cur_reg); + + } + + return 0; + +} + +/** + * ath5k_hw_attach - Check if hw is supported and init the needed structs + * + * @sc: The &struct ath5k_softc we got from the driver's attach function + * @mac_version: The mac version id (check out ath5k.h) based on pci id + * + * Check if the device is supported, perform a POST and initialize the needed + * structs. Returns -ENOMEM if we don't have memory for the needed structs, + * -ENODEV if the device is not supported or prints an error msg if something + * else went wrong. + */ +struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) +{ + struct ath5k_hw *ah; + struct pci_dev *pdev = sc->pdev; + u8 mac[ETH_ALEN]; + int ret; + u32 srev; + + /*If we passed the test malloc a ath5k_hw struct*/ + ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); + if (ah == NULL) { + ret = -ENOMEM; + ATH5K_ERR(sc, "out of memory\n"); + goto err; + } + + ah->ah_sc = sc; + ah->ah_iobase = sc->iobase; + + /* + * HW information + */ + ah->ah_op_mode = NL80211_IFTYPE_STATION; + ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; + ah->ah_turbo = false; + ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; + ah->ah_imr = 0; + ah->ah_atim_window = 0; + ah->ah_aifs = AR5K_TUNE_AIFS; + ah->ah_cw_min = AR5K_TUNE_CWMIN; + ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; + ah->ah_software_retry = false; + ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY; + + /* + * Set the mac version based on the pci id + */ + ah->ah_version = mac_version; + + /*Fill the ath5k_hw struct with the needed functions*/ + ret = ath5k_hw_init_desc_functions(ah); + if (ret) + goto err_free; + + /* Bring device out of sleep and reset it's units */ + ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true); + if (ret) + goto err_free; + + /* Get MAC, PHY and RADIO revisions */ + srev = ath5k_hw_reg_read(ah, AR5K_SREV); + ah->ah_mac_srev = srev; + ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); + ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); + ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & + 0xffffffff; + ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_5GHZ); + ah->ah_phy = AR5K_PHY(0); + + /* Try to identify radio chip based on it's srev */ + switch (ah->ah_radio_5ghz_revision & 0xf0) { + case AR5K_SREV_RAD_5111: + ah->ah_radio = AR5K_RF5111; + ah->ah_single_chip = false; + ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_2GHZ); + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; + break; + case AR5K_SREV_RAD_5112: + case AR5K_SREV_RAD_2112: + ah->ah_radio = AR5K_RF5112; + ah->ah_single_chip = false; + ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_2GHZ); + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; + break; + case AR5K_SREV_RAD_2413: + ah->ah_radio = AR5K_RF2413; + ah->ah_single_chip = true; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; + break; + case AR5K_SREV_RAD_5413: + ah->ah_radio = AR5K_RF5413; + ah->ah_single_chip = true; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; + break; + case AR5K_SREV_RAD_2316: + ah->ah_radio = AR5K_RF2316; + ah->ah_single_chip = true; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316; + break; + case AR5K_SREV_RAD_2317: + ah->ah_radio = AR5K_RF2317; + ah->ah_single_chip = true; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2317; + break; + case AR5K_SREV_RAD_5424: + if (ah->ah_mac_version == AR5K_SREV_AR2425 || + ah->ah_mac_version == AR5K_SREV_AR2417){ + ah->ah_radio = AR5K_RF2425; + ah->ah_single_chip = true; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; + } else { + ah->ah_radio = AR5K_RF5413; + ah->ah_single_chip = true; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; + } + break; + default: + /* Identify radio based on mac/phy srev */ + if (ah->ah_version == AR5K_AR5210) { + ah->ah_radio = AR5K_RF5110; + ah->ah_single_chip = false; + } else if (ah->ah_version == AR5K_AR5211) { + ah->ah_radio = AR5K_RF5111; + ah->ah_single_chip = false; + ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_2GHZ); + } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) || + ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) || + ah->ah_phy_revision == AR5K_SREV_PHY_2425) { + ah->ah_radio = AR5K_RF2425; + ah->ah_single_chip = true; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; + } else if (srev == AR5K_SREV_AR5213A && + ah->ah_phy_revision == AR5K_SREV_PHY_2112B) { + ah->ah_radio = AR5K_RF5112; + ah->ah_single_chip = false; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2112B; + } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) { + ah->ah_radio = AR5K_RF2316; + ah->ah_single_chip = true; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316; + } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) || + ah->ah_phy_revision == AR5K_SREV_PHY_5413) { + ah->ah_radio = AR5K_RF5413; + ah->ah_single_chip = true; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; + } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) || + ah->ah_phy_revision == AR5K_SREV_PHY_2413) { + ah->ah_radio = AR5K_RF2413; + ah->ah_single_chip = true; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; + } else { + ATH5K_ERR(sc, "Couldn't identify radio revision.\n"); + ret = -ENODEV; + goto err_free; + } + } + + + /* Return on unsuported chips (unsupported eeprom etc) */ + if ((srev >= AR5K_SREV_AR5416) && + (srev < AR5K_SREV_AR2425)) { + ATH5K_ERR(sc, "Device not yet supported.\n"); + ret = -ENODEV; + goto err_free; + } + + /* + * Write PCI-E power save settings + */ + if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { + ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); + /* Shut off RX when elecidle is asserted */ + ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES); + /* TODO: EEPROM work */ + ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES); + /* Shut off PLL and CLKREQ active in L1 */ + ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES); + /* Preserce other settings */ + ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES); + /* Reset SERDES to load new settings */ + ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); + mdelay(1); + } + + /* + * POST + */ + ret = ath5k_hw_post(ah); + if (ret) + goto err_free; + + /* Enable pci core retry fix on Hainan (5213A) and later chips */ + if (srev >= AR5K_SREV_AR5213A) + ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG); + + /* + * Get card capabilities, calibration values etc + * TODO: EEPROM work + */ + ret = ath5k_eeprom_init(ah); + if (ret) { + ATH5K_ERR(sc, "unable to init EEPROM\n"); + goto err_free; + } + + /* Get misc capabilities */ + ret = ath5k_hw_set_capabilities(ah); + if (ret) { + ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", + sc->pdev->device); + goto err_free; + } + + /* Set MAC address */ + ret = ath5k_eeprom_read_mac(ah, mac); + if (ret) { + ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", + sc->pdev->device); + goto err_free; + } + + ath5k_hw_set_lladdr(ah, mac); + /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ + memset(ah->ah_bssid, 0xff, ETH_ALEN); + ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + ath5k_hw_set_opmode(ah); + + ath5k_hw_set_rfgain_opt(ah); + + return ah; +err_free: + kfree(ah); +err: + return ERR_PTR(ret); +} + +/** + * ath5k_hw_detach - Free the ath5k_hw struct + * + * @ah: The &struct ath5k_hw + */ +void ath5k_hw_detach(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + + __set_bit(ATH_STAT_INVALID, ah->ah_sc->status); + + if (ah->ah_rf_banks != NULL) + kfree(ah->ah_rf_banks); + + /* assume interrupts are down */ + kfree(ah); +} diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 0676c6d8438..9b95c4049b3 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -72,7 +72,7 @@ MODULE_AUTHOR("Nick Kossifidis"); MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards."); MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION("0.5.0 (EXPERIMENTAL)"); +MODULE_VERSION("0.6.0 (EXPERIMENTAL)"); /* Known PCI ids */ @@ -93,45 +93,94 @@ static struct pci_device_id ath5k_pci_id_table[] __devinitdata = { { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */ { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */ - { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/ + { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* PCI-E cards */ + { PCI_VDEVICE(ATHEROS, 0x001d), .driver_data = AR5K_AR5212 }, /* 2417 Nala */ { 0 } }; MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table); /* Known SREVs */ static struct ath5k_srev_name srev_names[] = { - { "5210", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210 }, - { "5311", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311 }, - { "5311A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A }, - { "5311B", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B }, - { "5211", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211 }, - { "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 }, - { "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 }, - { "5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A }, - { "2413", AR5K_VERSION_VER, AR5K_SREV_VER_AR2413 }, - { "2414", AR5K_VERSION_VER, AR5K_SREV_VER_AR2414 }, - { "2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424 }, - { "5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424 }, - { "5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413 }, - { "5414", AR5K_VERSION_VER, AR5K_SREV_VER_AR5414 }, - { "5416", AR5K_VERSION_VER, AR5K_SREV_VER_AR5416 }, - { "5418", AR5K_VERSION_VER, AR5K_SREV_VER_AR5418 }, - { "2425", AR5K_VERSION_VER, AR5K_SREV_VER_AR2425 }, - { "xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN }, + { "5210", AR5K_VERSION_MAC, AR5K_SREV_AR5210 }, + { "5311", AR5K_VERSION_MAC, AR5K_SREV_AR5311 }, + { "5311A", AR5K_VERSION_MAC, AR5K_SREV_AR5311A }, + { "5311B", AR5K_VERSION_MAC, AR5K_SREV_AR5311B }, + { "5211", AR5K_VERSION_MAC, AR5K_SREV_AR5211 }, + { "5212", AR5K_VERSION_MAC, AR5K_SREV_AR5212 }, + { "5213", AR5K_VERSION_MAC, AR5K_SREV_AR5213 }, + { "5213A", AR5K_VERSION_MAC, AR5K_SREV_AR5213A }, + { "2413", AR5K_VERSION_MAC, AR5K_SREV_AR2413 }, + { "2414", AR5K_VERSION_MAC, AR5K_SREV_AR2414 }, + { "5424", AR5K_VERSION_MAC, AR5K_SREV_AR5424 }, + { "5413", AR5K_VERSION_MAC, AR5K_SREV_AR5413 }, + { "5414", AR5K_VERSION_MAC, AR5K_SREV_AR5414 }, + { "2415", AR5K_VERSION_MAC, AR5K_SREV_AR2415 }, + { "5416", AR5K_VERSION_MAC, AR5K_SREV_AR5416 }, + { "5418", AR5K_VERSION_MAC, AR5K_SREV_AR5418 }, + { "2425", AR5K_VERSION_MAC, AR5K_SREV_AR2425 }, + { "2417", AR5K_VERSION_MAC, AR5K_SREV_AR2417 }, + { "xxxxx", AR5K_VERSION_MAC, AR5K_SREV_UNKNOWN }, { "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 }, { "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 }, + { "5111A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111A }, { "2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111 }, { "5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112 }, { "5112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, + { "5112B", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112B }, { "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, { "2112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, - { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC0 }, - { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1 }, - { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2 }, + { "2112B", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112B }, + { "2413", AR5K_VERSION_RAD, AR5K_SREV_RAD_2413 }, + { "5413", AR5K_VERSION_RAD, AR5K_SREV_RAD_5413 }, + { "2316", AR5K_VERSION_RAD, AR5K_SREV_RAD_2316 }, + { "2317", AR5K_VERSION_RAD, AR5K_SREV_RAD_2317 }, + { "5424", AR5K_VERSION_RAD, AR5K_SREV_RAD_5424 }, { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 }, { "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN }, }; +static struct ieee80211_rate ath5k_rates[] = { + { .bitrate = 10, + .hw_value = ATH5K_RATE_CODE_1M, }, + { .bitrate = 20, + .hw_value = ATH5K_RATE_CODE_2M, + .hw_value_short = ATH5K_RATE_CODE_2M | AR5K_SET_SHORT_PREAMBLE, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = ATH5K_RATE_CODE_5_5M, + .hw_value_short = ATH5K_RATE_CODE_5_5M | AR5K_SET_SHORT_PREAMBLE, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = ATH5K_RATE_CODE_11M, + .hw_value_short = ATH5K_RATE_CODE_11M | AR5K_SET_SHORT_PREAMBLE, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = ATH5K_RATE_CODE_6M, + .flags = 0 }, + { .bitrate = 90, + .hw_value = ATH5K_RATE_CODE_9M, + .flags = 0 }, + { .bitrate = 120, + .hw_value = ATH5K_RATE_CODE_12M, + .flags = 0 }, + { .bitrate = 180, + .hw_value = ATH5K_RATE_CODE_18M, + .flags = 0 }, + { .bitrate = 240, + .hw_value = ATH5K_RATE_CODE_24M, + .flags = 0 }, + { .bitrate = 360, + .hw_value = ATH5K_RATE_CODE_36M, + .flags = 0 }, + { .bitrate = 480, + .hw_value = ATH5K_RATE_CODE_48M, + .flags = 0 }, + { .bitrate = 540, + .hw_value = ATH5K_RATE_CODE_54M, + .flags = 0 }, + /* XR missing */ +}; + /* * Prototypes - PCI stack related functions */ @@ -162,7 +211,8 @@ static struct pci_driver ath5k_pci_driver = { * Prototypes - MAC 802.11 stack related functions */ static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -static int ath5k_reset(struct ieee80211_hw *hw); +static int ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel); +static int ath5k_reset_wake(struct ath5k_softc *sc); static int ath5k_start(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw); static int ath5k_add_interface(struct ieee80211_hw *hw, @@ -218,20 +268,16 @@ static void ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw); /* Channel/mode setup */ static inline short ath5k_ieee2mhz(short chan); -static unsigned int ath5k_copy_rates(struct ieee80211_rate *rates, - const struct ath5k_rate_table *rt, - unsigned int max); static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, unsigned int mode, unsigned int max); -static int ath5k_getchannels(struct ieee80211_hw *hw); +static int ath5k_setup_bands(struct ieee80211_hw *hw); static int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan); static void ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode); static void ath5k_mode_setup(struct ath5k_softc *sc); -static void ath5k_set_total_hw_rates(struct ath5k_softc *sc); /* Descriptor setup */ static int ath5k_desc_alloc(struct ath5k_softc *sc, @@ -351,7 +397,11 @@ ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) for (i = 0; i < ARRAY_SIZE(srev_names); i++) { if (srev_names[i].sr_type != type) continue; - if ((val & 0xff) < srev_names[i + 1].sr_val) { + + if ((val & 0xf0) == srev_names[i].sr_val) + name = srev_names[i].sr_name; + + if ((val & 0xff) == srev_names[i].sr_val) { name = srev_names[i].sr_name; break; } @@ -446,6 +496,12 @@ ath5k_pci_probe(struct pci_dev *pdev, hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT); + hw->extra_tx_headroom = 2; hw->channel_change_time = 5000; sc = hw->priv; @@ -462,7 +518,7 @@ ath5k_pci_probe(struct pci_dev *pdev, sc->iobase = mem; /* So we can unmap it on detach */ sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ - sc->opmode = IEEE80211_IF_TYPE_STA; + sc->opmode = NL80211_IFTYPE_STATION; mutex_init(&sc->lock); spin_lock_init(&sc->rxbuflock); spin_lock_init(&sc->txbuflock); @@ -485,13 +541,19 @@ ath5k_pci_probe(struct pci_dev *pdev, goto err_irq; } + /* set up multi-rate retry capabilities */ + if (sc->ah->ah_version == AR5K_AR5212) { + hw->max_altrates = 3; + hw->max_altrate_tries = 11; + } + /* Finish private driver data initialization */ ret = ath5k_attach(pdev, hw); if (ret) goto err_ah; ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n", - ath5k_chip_name(AR5K_VERSION_VER,sc->ah->ah_mac_srev), + ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev), sc->ah->ah_mac_srev, sc->ah->ah_phy_revision); @@ -646,7 +708,6 @@ err_no_irq: #endif /* CONFIG_PM */ - /***********************\ * Driver Initialization * \***********************/ @@ -669,7 +730,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) * return false w/o doing anything. MAC's that do * support it will return true w/o doing anything. */ - ret = ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); + ret = ah->ah_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); if (ret < 0) goto err; if (ret > 0) @@ -688,15 +749,12 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) * on settings like the phy mode and regulatory * domain restrictions. */ - ret = ath5k_getchannels(hw); + ret = ath5k_setup_bands(hw); if (ret) { ATH5K_ERR(sc, "can't get channels\n"); goto err; } - /* Set *_rates so we can map hw rate index */ - ath5k_set_total_hw_rates(sc); - /* NB: setup here so ath5k_rate_update is happy */ if (test_bit(AR5K_MODE_11A, ah->ah_modes)) ath5k_setcurmode(sc, AR5K_MODE_11A); @@ -813,27 +871,6 @@ ath5k_ieee2mhz(short chan) } static unsigned int -ath5k_copy_rates(struct ieee80211_rate *rates, - const struct ath5k_rate_table *rt, - unsigned int max) -{ - unsigned int i, count; - - if (rt == NULL) - return 0; - - for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) { - rates[count].bitrate = rt->rates[i].rate_kbps / 100; - rates[count].hw_value = rt->rates[i].rate_code; - rates[count].flags = rt->rates[i].modulation; - count++; - max--; - } - - return count; -} - -static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, unsigned int mode, @@ -895,74 +932,97 @@ ath5k_copy_channels(struct ath5k_hw *ah, return count; } +static void +ath5k_setup_rate_idx(struct ath5k_softc *sc, struct ieee80211_supported_band *b) +{ + u8 i; + + for (i = 0; i < AR5K_MAX_RATES; i++) + sc->rate_idx[b->band][i] = -1; + + for (i = 0; i < b->n_bitrates; i++) { + sc->rate_idx[b->band][b->bitrates[i].hw_value] = i; + if (b->bitrates[i].hw_value_short) + sc->rate_idx[b->band][b->bitrates[i].hw_value_short] = i; + } +} + static int -ath5k_getchannels(struct ieee80211_hw *hw) +ath5k_setup_bands(struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - struct ieee80211_supported_band *sbands = sc->sbands; - const struct ath5k_rate_table *hw_rates; - unsigned int max_r, max_c, count_r, count_c; - int mode2g = AR5K_MODE_11G; + struct ieee80211_supported_band *sband; + int max_c, count_c = 0; + int i; BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS); - - max_r = ARRAY_SIZE(sc->rates); max_c = ARRAY_SIZE(sc->channels); - count_r = count_c = 0; /* 2GHz band */ - if (!test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) { - mode2g = AR5K_MODE_11B; - if (!test_bit(AR5K_MODE_11B, - sc->ah->ah_capabilities.cap_mode)) - mode2g = -1; - } + sband = &sc->sbands[IEEE80211_BAND_2GHZ]; + sband->band = IEEE80211_BAND_2GHZ; + sband->bitrates = &sc->rates[IEEE80211_BAND_2GHZ][0]; - if (mode2g > 0) { - struct ieee80211_supported_band *sband = - &sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) { + /* G mode */ + memcpy(sband->bitrates, &ath5k_rates[0], + sizeof(struct ieee80211_rate) * 12); + sband->n_bitrates = 12; - sband->bitrates = sc->rates; sband->channels = sc->channels; - - sband->band = IEEE80211_BAND_2GHZ; sband->n_channels = ath5k_copy_channels(ah, sband->channels, - mode2g, max_c); - - hw_rates = ath5k_hw_get_rate_table(ah, mode2g); - sband->n_bitrates = ath5k_copy_rates(sband->bitrates, - hw_rates, max_r); + AR5K_MODE_11G, max_c); + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; count_c = sband->n_channels; - count_r = sband->n_bitrates; + max_c -= count_c; + } else if (test_bit(AR5K_MODE_11B, sc->ah->ah_capabilities.cap_mode)) { + /* B mode */ + memcpy(sband->bitrates, &ath5k_rates[0], + sizeof(struct ieee80211_rate) * 4); + sband->n_bitrates = 4; + + /* 5211 only supports B rates and uses 4bit rate codes + * (e.g normally we have 0x1B for 1M, but on 5211 we have 0x0B) + * fix them up here: + */ + if (ah->ah_version == AR5K_AR5211) { + for (i = 0; i < 4; i++) { + sband->bitrates[i].hw_value = + sband->bitrates[i].hw_value & 0xF; + sband->bitrates[i].hw_value_short = + sband->bitrates[i].hw_value_short & 0xF; + } + } - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + sband->channels = sc->channels; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + AR5K_MODE_11B, max_c); - max_r -= count_r; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + count_c = sband->n_channels; max_c -= count_c; - } + ath5k_setup_rate_idx(sc, sband); - /* 5GHz band */ - + /* 5GHz band, A mode */ if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) { - struct ieee80211_supported_band *sband = - &sbands[IEEE80211_BAND_5GHZ]; + sband = &sc->sbands[IEEE80211_BAND_5GHZ]; + sband->band = IEEE80211_BAND_5GHZ; + sband->bitrates = &sc->rates[IEEE80211_BAND_5GHZ][0]; - sband->bitrates = &sc->rates[count_r]; - sband->channels = &sc->channels[count_c]; + memcpy(sband->bitrates, &ath5k_rates[4], + sizeof(struct ieee80211_rate) * 8); + sband->n_bitrates = 8; - sband->band = IEEE80211_BAND_5GHZ; + sband->channels = &sc->channels[count_c]; sband->n_channels = ath5k_copy_channels(ah, sband->channels, AR5K_MODE_11A, max_c); - hw_rates = ath5k_hw_get_rate_table(ah, AR5K_MODE_11A); - sband->n_bitrates = ath5k_copy_rates(sband->bitrates, - hw_rates, max_r); - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; } + ath5k_setup_rate_idx(sc, sband); ath5k_debug_dump_bands(sc); @@ -978,9 +1038,6 @@ ath5k_getchannels(struct ieee80211_hw *hw) static int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) { - struct ath5k_hw *ah = sc->ah; - int ret; - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", sc->curchan->center_freq, chan->center_freq); @@ -996,41 +1053,7 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) * hardware at the new frequency, and then re-enable * the relevant bits of the h/w. */ - ath5k_hw_set_intr(ah, 0); /* disable interrupts */ - ath5k_txq_cleanup(sc); /* clear pending tx frames */ - ath5k_rx_stop(sc); /* turn off frame recv */ - ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true); - if (ret) { - ATH5K_ERR(sc, "%s: unable to reset channel " - "(%u Mhz)\n", __func__, chan->center_freq); - return ret; - } - - ath5k_hw_set_txpower_limit(sc->ah, 0); - - /* - * Re-enable rx framework. - */ - ret = ath5k_rx_start(sc); - if (ret) { - ATH5K_ERR(sc, "%s: unable to restart recv logic\n", - __func__); - return ret; - } - - /* - * Change channels and update the h/w rate map - * if we're switching; e.g. 11a to 11b/g. - * - * XXX needed? - */ -/* ath5k_chan_change(sc, chan); */ - - ath5k_beacon_config(sc); - /* - * Re-enable interrupts. - */ - ath5k_hw_set_intr(ah, sc->imask); + return ath5k_reset(sc, true, true); } return 0; @@ -1068,75 +1091,13 @@ ath5k_mode_setup(struct ath5k_softc *sc) ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); } -/* - * Match the hw provided rate index (through descriptors) - * to an index for sc->curband->bitrates, so it can be used - * by the stack. - * - * This one is a little bit tricky but i think i'm right - * about this... - * - * We have 4 rate tables in the following order: - * XR (4 rates) - * 802.11a (8 rates) - * 802.11b (4 rates) - * 802.11g (12 rates) - * that make the hw rate table. - * - * Lets take a 5211 for example that supports a and b modes only. - * First comes the 802.11a table and then 802.11b (total 12 rates). - * When hw returns eg. 11 it points to the last 802.11b rate (11Mbit), - * if it returns 2 it points to the second 802.11a rate etc. - * - * Same goes for 5212 who has xr/a/b/g support (total 28 rates). - * First comes the XR table, then 802.11a, 802.11b and 802.11g. - * When hw returns eg. 27 it points to the last 802.11g rate (54Mbits) etc - */ -static void -ath5k_set_total_hw_rates(struct ath5k_softc *sc) { - - struct ath5k_hw *ah = sc->ah; - - if (test_bit(AR5K_MODE_11A, ah->ah_modes)) - sc->a_rates = 8; - - if (test_bit(AR5K_MODE_11B, ah->ah_modes)) - sc->b_rates = 4; - - if (test_bit(AR5K_MODE_11G, ah->ah_modes)) - sc->g_rates = 12; - - /* XXX: Need to see what what happens when - xr disable bits in eeprom are set */ - if (ah->ah_version >= AR5K_AR5212) - sc->xr_rates = 4; - -} - static inline int -ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) { - - int mac80211_rix; - - if(sc->curband->band == IEEE80211_BAND_2GHZ) { - /* We setup a g ratetable for both b/g modes */ - mac80211_rix = - hw_rix - sc->b_rates - sc->a_rates - sc->xr_rates; - } else { - mac80211_rix = hw_rix - sc->xr_rates; - } - - /* Something went wrong, fallback to basic rate for this band */ - if ((mac80211_rix >= sc->curband->n_bitrates) || - (mac80211_rix <= 0 )) - mac80211_rix = 1; - - return mac80211_rix; +ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) +{ + WARN_ON(hw_rix < 0 || hw_rix > AR5K_MAX_RATES); + return sc->rate_idx[sc->curband->band][hw_rix]; } - - - /***************\ * Buffers setup * \***************/ @@ -1199,7 +1160,7 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ds = bf->desc; ds->ds_link = bf->daddr; /* link to self */ ds->ds_data = bf->skbaddr; - ath5k_hw_setup_rx_desc(ah, ds, + ah->ah_setup_rx_desc(ah, ds, skb_tailroom(skb), /* buffer size */ 0); @@ -1218,7 +1179,9 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) struct sk_buff *skb = bf->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; - int ret; + struct ieee80211_rate *rate; + unsigned int mrr_rate[3], mrr_tries[3]; + int i, ret; flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; @@ -1233,7 +1196,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) if (info->control.hw_key) { keyidx = info->control.hw_key->hw_key_idx; - pktlen += info->control.icv_len; + pktlen += info->control.hw_key->icv_len; } ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, @@ -1243,6 +1206,22 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) if (ret) goto err_unmap; + memset(mrr_rate, 0, sizeof(mrr_rate)); + memset(mrr_tries, 0, sizeof(mrr_tries)); + for (i = 0; i < 3; i++) { + rate = ieee80211_get_alt_retry_rate(sc->hw, info, i); + if (!rate) + break; + + mrr_rate[i] = rate->hw_value; + mrr_tries[i] = info->control.retries[i].limit; + } + + ah->ah_setup_mrr_tx_desc(ah, ds, + mrr_rate[0], mrr_tries[0], + mrr_rate[1], mrr_tries[1], + mrr_rate[2], mrr_tries[2]); + ds->ds_link = 0; ds->ds_data = bf->skbaddr; @@ -1250,12 +1229,12 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) list_add_tail(&bf->list, &txq->q); sc->tx_stats[txq->qnum].len++; if (txq->link == NULL) /* is this first packet? */ - ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr); + ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr); else /* no, so only link it */ *txq->link = bf->daddr; txq->link = &ds->ds_link; - ath5k_hw_tx_start(ah, txq->qnum); + ath5k_hw_start_tx_dma(ah, txq->qnum); mmiowb(); spin_unlock_bh(&txq->lock); @@ -1433,7 +1412,8 @@ ath5k_beaconq_config(struct ath5k_softc *sc) ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); if (ret) return ret; - if (sc->opmode == IEEE80211_IF_TYPE_AP) { + if (sc->opmode == NL80211_IFTYPE_AP || + sc->opmode == NL80211_IFTYPE_MESH_POINT) { /* * Always burst out beacon and CAB traffic * (aifs = cwmin = cwmax = 0) @@ -1441,7 +1421,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc) qi.tqi_aifs = 0; qi.tqi_cw_min = 0; qi.tqi_cw_max = 0; - } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { /* * Adhoc mode; backoff between 0 and (2 * cw_min). */ @@ -1454,7 +1434,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc) "beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n", qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max); - ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi); + ret = ath5k_hw_set_tx_queueprops(ah, sc->bhalq, &qi); if (ret) { ATH5K_ERR(sc, "%s: unable to update parameters for beacon " "hardware queue!\n", __func__); @@ -1503,14 +1483,14 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) /* don't touch the hardware if marked invalid */ ath5k_hw_stop_tx_dma(ah, sc->bhalq); ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n", - ath5k_hw_get_tx_buf(ah, sc->bhalq)); + ath5k_hw_get_txdp(ah, sc->bhalq)); for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) if (sc->txqs[i].setup) { ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum); ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, " "link %p\n", sc->txqs[i].qnum, - ath5k_hw_get_tx_buf(ah, + ath5k_hw_get_txdp(ah, sc->txqs[i].qnum), sc->txqs[i].link); } @@ -1570,8 +1550,8 @@ ath5k_rx_start(struct ath5k_softc *sc) bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); spin_unlock_bh(&sc->rxbuflock); - ath5k_hw_put_rx_buf(ah, bf->daddr); - ath5k_hw_start_rx(ah); /* enable recv descriptors */ + ath5k_hw_set_rxdp(ah, bf->daddr); + ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ ath5k_mode_setup(sc); /* set filters, etc. */ ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ @@ -1588,7 +1568,7 @@ ath5k_rx_stop(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; - ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ + ath5k_hw_stop_rx_pcu(ah); /* disable PCU */ ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ @@ -1602,7 +1582,7 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, struct sk_buff *skb, struct ath5k_rx_status *rs) { struct ieee80211_hdr *hdr = (void *)skb->data; - unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb); + unsigned int keyix, hlen; if (!(rs->rs_status & AR5K_RXERR_DECRYPT) && rs->rs_keyix != AR5K_RXKEYIX_INVALID) @@ -1611,6 +1591,7 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, /* Apparently when a default key is used to decrypt the packet the hw does not set the index used to decrypt. In such cases get the index from the packet. */ + hlen = ieee80211_hdrlen(hdr->frame_control); if (ieee80211_has_protected(hdr->frame_control) && !(rs->rs_status & AR5K_RXERR_DECRYPT) && skb->len >= hlen + 4) { @@ -1768,7 +1749,7 @@ ath5k_tasklet_rx(unsigned long data) /* let crypto-error packets fall through in MNTR */ if ((rs.rs_status & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || - sc->opmode != IEEE80211_IF_TYPE_MNTR) + sc->opmode != NL80211_IFTYPE_MONITOR) goto next; } accept: @@ -1824,10 +1805,14 @@ accept: rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); + if (rxs.rate_idx >= 0 && rs.rs_rate == + sc->curband->bitrates[rxs.rate_idx].hw_value_short) + rxs.flag |= RX_FLAG_SHORTPRE; + ath5k_debug_dump_skb(sc, skb, "RX ", 0); /* check beacons in IBSS mode */ - if (sc->opmode == IEEE80211_IF_TYPE_IBSS) + if (sc->opmode == NL80211_IFTYPE_ADHOC) ath5k_check_ibss_tsf(sc, skb, &rxs); __ieee80211_rx(sc->hw, skb, &rxs); @@ -1853,7 +1838,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) struct ath5k_desc *ds; struct sk_buff *skb; struct ieee80211_tx_info *info; - int ret; + int i, ret; spin_lock(&txq->lock); list_for_each_entry_safe(bf, bf0, &txq->q, list) { @@ -1875,7 +1860,25 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; + memset(&info->status, 0, sizeof(info->status)); + info->tx_rate_idx = ath5k_hw_to_driver_rix(sc, + ts.ts_rate[ts.ts_final_idx]); + info->status.retry_count = ts.ts_longretry; + + for (i = 0; i < 4; i++) { + struct ieee80211_tx_altrate *r = + &info->status.retries[i]; + + if (ts.ts_rate[i]) { + r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); + r->limit = ts.ts_retry[i]; + } else { + r->rate_idx = -1; + r->limit = 0; + } + } + + info->status.excessive_retries = 0; if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; if (ts.ts_status & AR5K_TXERR_XRETRY) @@ -1942,7 +1945,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ds = bf->desc; flags = AR5K_TXDESC_NOACK; - if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) { + if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) { ds->ds_link = bf->daddr; /* self-linked */ flags |= AR5K_TXDESC_VEOL; /* @@ -1991,8 +1994,8 @@ ath5k_beacon_send(struct ath5k_softc *sc) ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); - if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA || - sc->opmode == IEEE80211_IF_TYPE_MNTR)) { + if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION || + sc->opmode == NL80211_IFTYPE_MONITOR)) { ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); return; } @@ -2032,8 +2035,8 @@ ath5k_beacon_send(struct ath5k_softc *sc) /* NB: hw still stops DMA, so proceed */ } - ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr); - ath5k_hw_tx_start(ah, sc->bhalq); + ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); + ath5k_hw_start_tx_dma(ah, sc->bhalq); ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", sc->bhalq, (unsigned long long)bf->daddr, bf->desc); @@ -2162,13 +2165,13 @@ ath5k_beacon_config(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; - ath5k_hw_set_intr(ah, 0); + ath5k_hw_set_imr(ah, 0); sc->bmisscount = 0; sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); - if (sc->opmode == IEEE80211_IF_TYPE_STA) { + if (sc->opmode == NL80211_IFTYPE_STATION) { sc->imask |= AR5K_INT_BMISS; - } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { /* * In IBSS mode we use a self-linked tx descriptor and let the * hardware send the beacons automatically. We have to load it @@ -2188,7 +2191,7 @@ ath5k_beacon_config(struct ath5k_softc *sc) } /* TODO else AP */ - ath5k_hw_set_intr(ah, sc->imask); + ath5k_hw_set_imr(ah, sc->imask); } @@ -2220,36 +2223,13 @@ ath5k_init(struct ath5k_softc *sc) */ sc->curchan = sc->hw->conf.channel; sc->curband = &sc->sbands[sc->curchan->band]; - ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false); - if (ret) { - ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret); - goto done; - } - /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath5k_hw_set_txpower_limit(sc->ah, 0); - - /* - * Setup the hardware after reset: the key cache - * is filled as needed and the receive engine is - * set going. Frame transmit is handled entirely - * in the frame output path; there's nothing to do - * here except setup the interrupt mask. - */ - ret = ath5k_rx_start(sc); - if (ret) - goto done; - - /* - * Enable interrupts. - */ sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; + ret = ath5k_reset(sc, false, false); + if (ret) + goto done; - ath5k_hw_set_intr(sc->ah, sc->imask); /* Set ack to be sent at low bit-rates */ ath5k_hw_set_ack_bitrate_high(sc->ah, false); @@ -2290,7 +2270,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) if (!test_bit(ATH_STAT_INVALID, sc->status)) { ath5k_led_off(sc); - ath5k_hw_set_intr(ah, 0); + ath5k_hw_set_imr(ah, 0); synchronize_irq(sc->pdev->irq); } ath5k_txq_cleanup(sc); @@ -2396,7 +2376,7 @@ ath5k_intr(int irq, void *dev_id) * transmission time) in order to detect wether * automatic TSF updates happened. */ - if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + if (sc->opmode == NL80211_IFTYPE_ADHOC) { /* XXX: only if VEOL suppported */ u64 tsf = ath5k_hw_get_tsf64(ah); sc->nexttbtt += sc->bintval; @@ -2451,7 +2431,7 @@ ath5k_tasklet_reset(unsigned long data) { struct ath5k_softc *sc = (void *)data; - ath5k_reset(sc->hw); + ath5k_reset_wake(sc); } /* @@ -2474,7 +2454,7 @@ ath5k_calibrate(unsigned long data) * to load new gain values. */ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); - ath5k_reset(sc->hw); + ath5k_reset_wake(sc); } if (ath5k_hw_phy_calibrate(ah, sc->curchan)) ATH5K_ERR(sc, "calibration of channel %u failed\n", @@ -2626,7 +2606,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ath5k_debug_dump_skb(sc, skb, "TX ", 1); - if (sc->opmode == IEEE80211_IF_TYPE_MNTR) + if (sc->opmode == NL80211_IFTYPE_MONITOR) ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n"); /* @@ -2675,48 +2655,67 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) } static int -ath5k_reset(struct ieee80211_hw *hw) +ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel) { - struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; int ret; ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); - ath5k_hw_set_intr(ah, 0); - ath5k_txq_cleanup(sc); - ath5k_rx_stop(sc); - + if (stop) { + ath5k_hw_set_imr(ah, 0); + ath5k_txq_cleanup(sc); + ath5k_rx_stop(sc); + } ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true); - if (unlikely(ret)) { + if (ret) { ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); goto err; } + + /* + * This is needed only to setup initial state + * but it's best done after a reset. + */ ath5k_hw_set_txpower_limit(sc->ah, 0); ret = ath5k_rx_start(sc); - if (unlikely(ret)) { + if (ret) { ATH5K_ERR(sc, "can't start recv logic\n"); goto err; } + /* - * We may be doing a reset in response to an ioctl - * that changes the channel so update any state that - * might change as a result. + * Change channels and update the h/w rate map if we're switching; + * e.g. 11a to 11b/g. + * + * We may be doing a reset in response to an ioctl that changes the + * channel so update any state that might change as a result. * * XXX needed? */ /* ath5k_chan_change(sc, c); */ - ath5k_beacon_config(sc); - /* intrs are started by ath5k_beacon_config */ - ieee80211_wake_queues(hw); + ath5k_beacon_config(sc); + /* intrs are enabled by ath5k_beacon_config */ return 0; err: return ret; } +static int +ath5k_reset_wake(struct ath5k_softc *sc) +{ + int ret; + + ret = ath5k_reset(sc, true, true); + if (!ret) + ieee80211_wake_queues(sc->hw); + + return ret; +} + static int ath5k_start(struct ieee80211_hw *hw) { return ath5k_init(hw->priv); @@ -2742,9 +2741,9 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, sc->vif = conf->vif; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MONITOR: sc->opmode = conf->type; break; default: @@ -2815,7 +2814,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (conf->changed & IEEE80211_IFCC_BEACON && - vif->type == IEEE80211_IF_TYPE_IBSS) { + vif->type == NL80211_IFTYPE_ADHOC) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) { ret = -ENOMEM; @@ -2827,7 +2826,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_unlock(&sc->lock); - return ath5k_reset(hw); + return ath5k_reset_wake(sc); unlock: mutex_unlock(&sc->lock); return ret; @@ -2934,16 +2933,17 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ - if (sc->opmode == IEEE80211_IF_TYPE_MNTR) + if (sc->opmode == NL80211_IFTYPE_MONITOR) rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; - if (sc->opmode != IEEE80211_IF_TYPE_STA) + if (sc->opmode != NL80211_IFTYPE_STATION) rfilt |= AR5K_RX_FILTER_PROBEREQ; - if (sc->opmode != IEEE80211_IF_TYPE_AP && + if (sc->opmode != NL80211_IFTYPE_AP && + sc->opmode != NL80211_IFTYPE_MESH_POINT && test_bit(ATH_STAT_PROMISC, sc->status)) rfilt |= AR5K_RX_FILTER_PROM; - if (sc->opmode == IEEE80211_IF_TYPE_STA || - sc->opmode == IEEE80211_IF_TYPE_IBSS) { + if (sc->opmode == NL80211_IFTYPE_STATION || + sc->opmode == NL80211_IFTYPE_ADHOC) { rfilt |= AR5K_RX_FILTER_BEACON; } @@ -3048,7 +3048,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) * in IBSS mode we need to update the beacon timers too. * this will also reset the TSF if we call it with 0 */ - if (sc->opmode == IEEE80211_IF_TYPE_IBSS) + if (sc->opmode == NL80211_IFTYPE_ADHOC) ath5k_beacon_update_timers(sc, 0); else ath5k_hw_reset_tsf(sc->ah); @@ -3063,7 +3063,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) ath5k_debug_dump_skb(sc, skb, "BC ", 1); - if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { + if (sc->opmode != NL80211_IFTYPE_ADHOC) { ret = -EIO; goto end; } diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 7ec2f377d5c..9d0b728928e 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -111,17 +111,13 @@ struct ath5k_softc { struct ieee80211_hw *hw; /* IEEE 802.11 common */ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; struct ieee80211_channel channels[ATH_CHAN_MAX]; - struct ieee80211_rate rates[AR5K_MAX_RATES * IEEE80211_NUM_BANDS]; - enum ieee80211_if_types opmode; + struct ieee80211_rate rates[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; + u8 rate_idx[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; + enum nl80211_iftype opmode; struct ath5k_hw *ah; /* Atheros HW */ struct ieee80211_supported_band *curband; - u8 a_rates; - u8 b_rates; - u8 g_rates; - u8 xr_rates; - #ifdef CONFIG_ATH5K_DEBUG struct ath5k_dbg_info debug; /* debug info */ #endif /* CONFIG_ATH5K_DEBUG */ diff --git a/drivers/net/wireless/ath5k/caps.c b/drivers/net/wireless/ath5k/caps.c new file mode 100644 index 00000000000..150f5ed204a --- /dev/null +++ b/drivers/net/wireless/ath5k/caps.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> + * + * Permission to use, copy, modify, and 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. + * + */ + +/**************\ +* Capabilities * +\**************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * Fill the capabilities struct + * TODO: Merge this with EEPROM code when we are done with it + */ +int ath5k_hw_set_capabilities(struct ath5k_hw *ah) +{ + u16 ee_header; + + ATH5K_TRACE(ah->ah_sc); + /* Capabilities stored in the EEPROM */ + ee_header = ah->ah_capabilities.cap_eeprom.ee_header; + + if (ah->ah_version == AR5K_AR5210) { + /* + * Set radio capabilities + * (The AR5110 only supports the middle 5GHz band) + */ + ah->ah_capabilities.cap_range.range_5ghz_min = 5120; + ah->ah_capabilities.cap_range.range_5ghz_max = 5430; + ah->ah_capabilities.cap_range.range_2ghz_min = 0; + ah->ah_capabilities.cap_range.range_2ghz_max = 0; + + /* Set supported modes */ + __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode); + } else { + /* + * XXX The tranceiver supports frequencies from 4920 to 6100GHz + * XXX and from 2312 to 2732GHz. There are problems with the + * XXX current ieee80211 implementation because the IEEE + * XXX channel mapping does not support negative channel + * XXX numbers (2312MHz is channel -19). Of course, this + * XXX doesn't matter because these channels are out of range + * XXX but some regulation domains like MKK (Japan) will + * XXX support frequencies somewhere around 4.8GHz. + */ + + /* + * Set radio capabilities + */ + + if (AR5K_EEPROM_HDR_11A(ee_header)) { + /* 4920 */ + ah->ah_capabilities.cap_range.range_5ghz_min = 5005; + ah->ah_capabilities.cap_range.range_5ghz_max = 6100; + + /* Set supported modes */ + __set_bit(AR5K_MODE_11A, + ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A_TURBO, + ah->ah_capabilities.cap_mode); + if (ah->ah_version == AR5K_AR5212) + __set_bit(AR5K_MODE_11G_TURBO, + ah->ah_capabilities.cap_mode); + } + + /* Enable 802.11b if a 2GHz capable radio (2111/5112) is + * connected */ + if (AR5K_EEPROM_HDR_11B(ee_header) || + AR5K_EEPROM_HDR_11G(ee_header)) { + /* 2312 */ + ah->ah_capabilities.cap_range.range_2ghz_min = 2412; + ah->ah_capabilities.cap_range.range_2ghz_max = 2732; + + if (AR5K_EEPROM_HDR_11B(ee_header)) + __set_bit(AR5K_MODE_11B, + ah->ah_capabilities.cap_mode); + + if (AR5K_EEPROM_HDR_11G(ee_header)) + __set_bit(AR5K_MODE_11G, + ah->ah_capabilities.cap_mode); + } + } + + /* GPIO */ + ah->ah_gpio_npins = AR5K_NUM_GPIO; + + /* Set number of supported TX queues */ + if (ah->ah_version == AR5K_AR5210) + ah->ah_capabilities.cap_queues.q_tx_num = + AR5K_NUM_TX_QUEUES_NOQCU; + else + ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; + + return 0; +} + +/* Main function used by the driver part to check caps */ +int ath5k_hw_get_capability(struct ath5k_hw *ah, + enum ath5k_capability_type cap_type, + u32 capability, u32 *result) +{ + ATH5K_TRACE(ah->ah_sc); + + switch (cap_type) { + case AR5K_CAP_NUM_TXQUEUES: + if (result) { + if (ah->ah_version == AR5K_AR5210) + *result = AR5K_NUM_TX_QUEUES_NOQCU; + else + *result = AR5K_NUM_TX_QUEUES; + goto yes; + } + case AR5K_CAP_VEOL: + goto yes; + case AR5K_CAP_COMPRESSION: + if (ah->ah_version == AR5K_AR5212) + goto yes; + else + goto no; + case AR5K_CAP_BURST: + goto yes; + case AR5K_CAP_TPC: + goto yes; + case AR5K_CAP_BSSIDMASK: + if (ah->ah_version == AR5K_AR5212) + goto yes; + else + goto no; + case AR5K_CAP_XR: + if (ah->ah_version == AR5K_AR5212) + goto yes; + else + goto no; + default: + goto no; + } + +no: + return -EINVAL; +yes: + return 0; +} + +/* + * TODO: Following functions should be part of a new function + * set_capability + */ + +int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, + u16 assoc_id) +{ + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); + return 0; + } + + return -EIO; +} + +int ath5k_hw_disable_pspoll(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); + return 0; + } + + return -EIO; +} diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c index 6fa6c8e04ff..8f92d670f61 100644 --- a/drivers/net/wireless/ath5k/debug.c +++ b/drivers/net/wireless/ath5k/debug.c @@ -58,8 +58,8 @@ * THE POSSIBILITY OF SUCH DAMAGES. */ -#include "debug.h" #include "base.h" +#include "debug.h" static unsigned int ath5k_debug; module_param_named(debug, ath5k_debug, uint, 0); @@ -525,7 +525,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) return; printk(KERN_DEBUG "rx queue %x, link %p\n", - ath5k_hw_get_rx_buf(ah), sc->rxlink); + ath5k_hw_get_rxdp(ah), sc->rxlink); spin_lock_bh(&sc->rxbuflock); list_for_each_entry(bf, &sc->rxbuf, list) { diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c new file mode 100644 index 00000000000..dd1374052ba --- /dev/null +++ b/drivers/net/wireless/ath5k/desc.c @@ -0,0 +1,692 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org> + * + * Permission to use, copy, modify, and 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. + * + */ + +/******************************\ + Hardware Descriptor Functions +\******************************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * TX Descriptors + */ + +/* + * Initialize the 2-word tx control descriptor on 5210/5211 + */ +static int +ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, + unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, + unsigned int key_index, unsigned int antenna_mode, unsigned int flags, + unsigned int rtscts_rate, unsigned int rtscts_duration) +{ + u32 frame_type; + struct ath5k_hw_2w_tx_ctl *tx_ctl; + unsigned int frame_len; + + tx_ctl = &desc->ud.ds_tx5210.tx_ctl; + + /* + * Validate input + * - Zero retries don't make sense. + * - A zero rate will put the HW into a mode where it continously sends + * noise on the channel, so it is important to avoid this. + */ + if (unlikely(tx_tries0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero retries\n"); + WARN_ON(1); + return -EINVAL; + } + if (unlikely(tx_rate0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero rate\n"); + WARN_ON(1); + return -EINVAL; + } + + /* Clear descriptor */ + memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); + + /* Setup control descriptor */ + + /* Verify and set frame length */ + + /* remove padding we might have added before */ + frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + + if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) + return -EINVAL; + + tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; + + /* Verify and set buffer length */ + + /* NB: beacon's BufLen must be a multiple of 4 bytes */ + if (type == AR5K_PKT_TYPE_BEACON) + pkt_len = roundup(pkt_len, 4); + + if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) + return -EINVAL; + + tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; + + /* + * Verify and set header length + * XXX: I only found that on 5210 code, does it work on 5211 ? + */ + if (ah->ah_version == AR5K_AR5210) { + if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) + return -EINVAL; + tx_ctl->tx_control_0 |= + AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); + } + + /*Diferences between 5210-5211*/ + if (ah->ah_version == AR5K_AR5210) { + switch (type) { + case AR5K_PKT_TYPE_BEACON: + case AR5K_PKT_TYPE_PROBE_RESP: + frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; + case AR5K_PKT_TYPE_PIFS: + frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; + default: + frame_type = type /*<< 2 ?*/; + } + + tx_ctl->tx_control_0 |= + AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | + AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); + + } else { + tx_ctl->tx_control_0 |= + AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | + AR5K_REG_SM(antenna_mode, + AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); + tx_ctl->tx_control_1 |= + AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); + } +#define _TX_FLAGS(_c, _flag) \ + if (flags & AR5K_TXDESC_##_flag) { \ + tx_ctl->tx_control_##_c |= \ + AR5K_2W_TX_DESC_CTL##_c##_##_flag; \ + } + + _TX_FLAGS(0, CLRDMASK); + _TX_FLAGS(0, VEOL); + _TX_FLAGS(0, INTREQ); + _TX_FLAGS(0, RTSENA); + _TX_FLAGS(1, NOACK); + +#undef _TX_FLAGS + + /* + * WEP crap + */ + if (key_index != AR5K_TXKEYIX_INVALID) { + tx_ctl->tx_control_0 |= + AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + tx_ctl->tx_control_1 |= + AR5K_REG_SM(key_index, + AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); + } + + /* + * RTS/CTS Duration [5210 ?] + */ + if ((ah->ah_version == AR5K_AR5210) && + (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) + tx_ctl->tx_control_1 |= rtscts_duration & + AR5K_2W_TX_DESC_CTL1_RTS_DURATION; + + return 0; +} + +/* + * Initialize the 4-word tx control descriptor on 5212 + */ +static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, + struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, + enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, + unsigned int tx_tries0, unsigned int key_index, + unsigned int antenna_mode, unsigned int flags, + unsigned int rtscts_rate, + unsigned int rtscts_duration) +{ + struct ath5k_hw_4w_tx_ctl *tx_ctl; + unsigned int frame_len; + + ATH5K_TRACE(ah->ah_sc); + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; + + /* + * Validate input + * - Zero retries don't make sense. + * - A zero rate will put the HW into a mode where it continously sends + * noise on the channel, so it is important to avoid this. + */ + if (unlikely(tx_tries0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero retries\n"); + WARN_ON(1); + return -EINVAL; + } + if (unlikely(tx_rate0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero rate\n"); + WARN_ON(1); + return -EINVAL; + } + + /* Clear descriptor */ + memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); + + /* Setup control descriptor */ + + /* Verify and set frame length */ + + /* remove padding we might have added before */ + frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + + if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) + return -EINVAL; + + tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; + + /* Verify and set buffer length */ + + /* NB: beacon's BufLen must be a multiple of 4 bytes */ + if (type == AR5K_PKT_TYPE_BEACON) + pkt_len = roundup(pkt_len, 4); + + if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) + return -EINVAL; + + tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; + + tx_ctl->tx_control_0 |= + AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | + AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); + tx_ctl->tx_control_1 |= AR5K_REG_SM(type, + AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); + tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); + tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + +#define _TX_FLAGS(_c, _flag) \ + if (flags & AR5K_TXDESC_##_flag) { \ + tx_ctl->tx_control_##_c |= \ + AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ + } + + _TX_FLAGS(0, CLRDMASK); + _TX_FLAGS(0, VEOL); + _TX_FLAGS(0, INTREQ); + _TX_FLAGS(0, RTSENA); + _TX_FLAGS(0, CTSENA); + _TX_FLAGS(1, NOACK); + +#undef _TX_FLAGS + + /* + * WEP crap + */ + if (key_index != AR5K_TXKEYIX_INVALID) { + tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, + AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); + } + + /* + * RTS/CTS + */ + if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { + if ((flags & AR5K_TXDESC_RTSENA) && + (flags & AR5K_TXDESC_CTSENA)) + return -EINVAL; + tx_ctl->tx_control_2 |= rtscts_duration & + AR5K_4W_TX_DESC_CTL2_RTS_DURATION; + tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, + AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); + } + + return 0; +} + +/* + * Initialize a 4-word multi rate retry tx control descriptor on 5212 + */ +static int +ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, + u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) +{ + struct ath5k_hw_4w_tx_ctl *tx_ctl; + + /* + * Rates can be 0 as long as the retry count is 0 too. + * A zero rate and nonzero retry count will put the HW into a mode where + * it continously sends noise on the channel, so it is important to + * avoid this. + */ + if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || + (tx_rate2 == 0 && tx_tries2 != 0) || + (tx_rate3 == 0 && tx_tries3 != 0))) { + ATH5K_ERR(ah->ah_sc, "zero rate\n"); + WARN_ON(1); + return -EINVAL; + } + + if (ah->ah_version == AR5K_AR5212) { + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; + +#define _XTX_TRIES(_n) \ + if (tx_tries##_n) { \ + tx_ctl->tx_control_2 |= \ + AR5K_REG_SM(tx_tries##_n, \ + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ + tx_ctl->tx_control_3 |= \ + AR5K_REG_SM(tx_rate##_n, \ + AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ + } + + _XTX_TRIES(1); + _XTX_TRIES(2); + _XTX_TRIES(3); + +#undef _XTX_TRIES + + return 1; + } + + return 0; +} + +/* no mrr support for cards older than 5212 */ +static int +ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, + u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) +{ + return 0; +} + +/* + * Proccess the tx status descriptor on 5210/5211 + */ +static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_tx_status *ts) +{ + struct ath5k_hw_2w_tx_ctl *tx_ctl; + struct ath5k_hw_tx_status *tx_status; + + ATH5K_TRACE(ah->ah_sc); + + tx_ctl = &desc->ud.ds_tx5210.tx_ctl; + tx_status = &desc->ud.ds_tx5210.tx_stat; + + /* No frame has been send or error */ + if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) + return -EINPROGRESS; + + /* + * Get descriptor status + */ + ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); + ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); + ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); + /*TODO: ts->ts_virtcol + test*/ + ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_SEQ_NUM); + ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); + ts->ts_antenna = 1; + ts->ts_status = 0; + ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0, + AR5K_2W_TX_DESC_CTL0_XMIT_RATE); + ts->ts_retry[0] = ts->ts_longretry; + ts->ts_final_idx = 0; + + if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { + if (tx_status->tx_status_0 & + AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + ts->ts_status |= AR5K_TXERR_XRETRY; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + ts->ts_status |= AR5K_TXERR_FIFO; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) + ts->ts_status |= AR5K_TXERR_FILT; + } + + return 0; +} + +/* + * Proccess a tx status descriptor on 5212 + */ +static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_tx_status *ts) +{ + struct ath5k_hw_4w_tx_ctl *tx_ctl; + struct ath5k_hw_tx_status *tx_status; + + ATH5K_TRACE(ah->ah_sc); + + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; + tx_status = &desc->ud.ds_tx5212.tx_stat; + + /* No frame has been send or error */ + if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))) + return -EINPROGRESS; + + /* + * Get descriptor status + */ + ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); + ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); + ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); + ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_SEQ_NUM); + ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); + ts->ts_antenna = (tx_status->tx_status_1 & + AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; + ts->ts_status = 0; + + ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX); + + /* The longretry counter has the number of un-acked retries + * for the final rate. To get the total number of retries + * we have to add the retry counters for the other rates + * as well + */ + ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; + switch (ts->ts_final_idx) { + case 3: + ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); + + ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); + ts->ts_longretry += ts->ts_retry[2]; + /* fall through */ + case 2: + ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); + + ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); + ts->ts_longretry += ts->ts_retry[1]; + /* fall through */ + case 1: + ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); + + ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); + ts->ts_longretry += ts->ts_retry[0]; + /* fall through */ + case 0: + ts->ts_rate[0] = tx_ctl->tx_control_3 & + AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + break; + } + + /* TX error */ + if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { + if (tx_status->tx_status_0 & + AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + ts->ts_status |= AR5K_TXERR_XRETRY; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + ts->ts_status |= AR5K_TXERR_FIFO; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) + ts->ts_status |= AR5K_TXERR_FILT; + } + + return 0; +} + +/* + * RX Descriptors + */ + +/* + * Initialize an rx control descriptor + */ +static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + u32 size, unsigned int flags) +{ + struct ath5k_hw_rx_ctl *rx_ctl; + + ATH5K_TRACE(ah->ah_sc); + rx_ctl = &desc->ud.ds_rx.rx_ctl; + + /* + * Clear the descriptor + * If we don't clean the status descriptor, + * while scanning we get too many results, + * most of them virtual, after some secs + * of scanning system hangs. M.F. + */ + memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc)); + + /* Setup descriptor */ + rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; + if (unlikely(rx_ctl->rx_control_1 != size)) + return -EINVAL; + + if (flags & AR5K_RXDESC_INTREQ) + rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; + + return 0; +} + +/* + * Proccess the rx status descriptor on 5210/5211 + */ +static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_rx_status *rs) +{ + struct ath5k_hw_rx_status *rx_status; + + rx_status = &desc->ud.ds_rx.u.rx_stat; + + /* No frame received / not ready */ + if (unlikely(!(rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_DONE))) + return -EINPROGRESS; + + /* + * Frame receive status + */ + rs->rs_datalen = rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_DATA_LEN; + rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL); + rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE); + rs->rs_antenna = rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA; + rs->rs_more = rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_MORE; + /* TODO: this timestamp is 13 bit, later on we assume 15 bit */ + rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); + rs->rs_status = 0; + rs->rs_phyerr = 0; + + /* + * Key table status + */ + if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID) + rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5210_RX_DESC_STATUS1_KEY_INDEX); + else + rs->rs_keyix = AR5K_RXKEYIX_INVALID; + + /* + * Receive/descriptor errors + */ + if (!(rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { + if (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_CRC; + + if (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN) + rs->rs_status |= AR5K_RXERR_FIFO; + + if (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { + rs->rs_status |= AR5K_RXERR_PHY; + rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); + } + + if (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_DECRYPT; + } + + return 0; +} + +/* + * Proccess the rx status descriptor on 5212 + */ +static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_rx_status *rs) +{ + struct ath5k_hw_rx_status *rx_status; + struct ath5k_hw_rx_error *rx_err; + + ATH5K_TRACE(ah->ah_sc); + rx_status = &desc->ud.ds_rx.u.rx_stat; + + /* Overlay on error */ + rx_err = &desc->ud.ds_rx.u.rx_err; + + /* No frame received / not ready */ + if (unlikely(!(rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_DONE))) + return -EINPROGRESS; + + /* + * Frame receive status + */ + rs->rs_datalen = rx_status->rx_status_0 & + AR5K_5212_RX_DESC_STATUS0_DATA_LEN; + rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); + rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); + rs->rs_antenna = rx_status->rx_status_0 & + AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA; + rs->rs_more = rx_status->rx_status_0 & + AR5K_5212_RX_DESC_STATUS0_MORE; + rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); + rs->rs_status = 0; + rs->rs_phyerr = 0; + + /* + * Key table status + */ + if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) + rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); + else + rs->rs_keyix = AR5K_RXKEYIX_INVALID; + + /* + * Receive/descriptor errors + */ + if (!(rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_CRC; + + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { + rs->rs_status |= AR5K_RXERR_PHY; + rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, + AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); + } + + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_DECRYPT; + + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) + rs->rs_status |= AR5K_RXERR_MIC; + } + + return 0; +} + +/* + * Init function pointers inside ath5k_hw struct + */ +int ath5k_hw_init_desc_functions(struct ath5k_hw *ah) +{ + + if (ah->ah_version != AR5K_AR5210 && + ah->ah_version != AR5K_AR5211 && + ah->ah_version != AR5K_AR5212) + return -ENOTSUPP; + + /* XXX: What is this magic value and where is it used ? */ + if (ah->ah_version == AR5K_AR5212) + ah->ah_magic = AR5K_EEPROM_MAGIC_5212; + else if (ah->ah_version == AR5K_AR5211) + ah->ah_magic = AR5K_EEPROM_MAGIC_5211; + + if (ah->ah_version == AR5K_AR5212) { + ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; + ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; + ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc; + ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status; + } else { + ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; + ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; + ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr; + ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; + } + + if (ah->ah_version == AR5K_AR5212) + ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; + else if (ah->ah_version <= AR5K_AR5211) + ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status; + + return 0; +} + diff --git a/drivers/net/wireless/ath5k/hw.h b/drivers/net/wireless/ath5k/desc.h index 64fca8dcb38..56158c804e3 100644 --- a/drivers/net/wireless/ath5k/hw.h +++ b/drivers/net/wireless/ath5k/desc.h @@ -1,8 +1,6 @@ /* - * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> - * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com> - * Copyright (c) 2007 Matthew W. S. Bell <mentor@madwifi.org> - * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu> + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,159 +13,9 @@ * 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/delay.h> - -/* - * Gain settings - */ - -enum ath5k_rfgain { - AR5K_RFGAIN_INACTIVE = 0, - AR5K_RFGAIN_READ_REQUESTED, - AR5K_RFGAIN_NEED_CHANGE, -}; - -#define AR5K_GAIN_CRN_FIX_BITS_5111 4 -#define AR5K_GAIN_CRN_FIX_BITS_5112 7 -#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112 -#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15 -#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20 -#define AR5K_GAIN_CCK_PROBE_CORR 5 -#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15 -#define AR5K_GAIN_STEP_COUNT 10 -#define AR5K_GAIN_PARAM_TX_CLIP 0 -#define AR5K_GAIN_PARAM_PD_90 1 -#define AR5K_GAIN_PARAM_PD_84 2 -#define AR5K_GAIN_PARAM_GAIN_SEL 3 -#define AR5K_GAIN_PARAM_MIX_ORN 0 -#define AR5K_GAIN_PARAM_PD_138 1 -#define AR5K_GAIN_PARAM_PD_137 2 -#define AR5K_GAIN_PARAM_PD_136 3 -#define AR5K_GAIN_PARAM_PD_132 4 -#define AR5K_GAIN_PARAM_PD_131 5 -#define AR5K_GAIN_PARAM_PD_130 6 -#define AR5K_GAIN_CHECK_ADJUST(_g) \ - ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) - -struct ath5k_gain_opt_step { - s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; - s32 gos_gain; -}; - -struct ath5k_gain { - u32 g_step_idx; - u32 g_current; - u32 g_target; - u32 g_low; - u32 g_high; - u32 g_f_corr; - u32 g_active; - const struct ath5k_gain_opt_step *g_step; -}; - - -/* - * HW SPECIFIC STRUCTS - */ - -/* Some EEPROM defines */ -#define AR5K_EEPROM_EEP_SCALE 100 -#define AR5K_EEPROM_EEP_DELTA 10 -#define AR5K_EEPROM_N_MODES 3 -#define AR5K_EEPROM_N_5GHZ_CHAN 10 -#define AR5K_EEPROM_N_2GHZ_CHAN 3 -#define AR5K_EEPROM_MAX_CHAN 10 -#define AR5K_EEPROM_N_PCDAC 11 -#define AR5K_EEPROM_N_TEST_FREQ 8 -#define AR5K_EEPROM_N_EDGES 8 -#define AR5K_EEPROM_N_INTERCEPTS 11 -#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff) -#define AR5K_EEPROM_PCDAC_M 0x3f -#define AR5K_EEPROM_PCDAC_START 1 -#define AR5K_EEPROM_PCDAC_STOP 63 -#define AR5K_EEPROM_PCDAC_STEP 1 -#define AR5K_EEPROM_NON_EDGE_M 0x40 -#define AR5K_EEPROM_CHANNEL_POWER 8 -#define AR5K_EEPROM_N_OBDB 4 -#define AR5K_EEPROM_OBDB_DIS 0xffff -#define AR5K_EEPROM_CHANNEL_DIS 0xff -#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10) -#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32) -#define AR5K_EEPROM_MAX_CTLS 32 -#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 -#define AR5K_EEPROM_N_XPD0_POINTS 4 -#define AR5K_EEPROM_N_XPD3_POINTS 3 -#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35 -#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 -#define AR5K_EEPROM_POWER_M 0x3f -#define AR5K_EEPROM_POWER_MIN 0 -#define AR5K_EEPROM_POWER_MAX 3150 -#define AR5K_EEPROM_POWER_STEP 50 -#define AR5K_EEPROM_POWER_TABLE_SIZE 64 -#define AR5K_EEPROM_N_POWER_LOC_11B 4 -#define AR5K_EEPROM_N_POWER_LOC_11G 6 -#define AR5K_EEPROM_I_GAIN 10 -#define AR5K_EEPROM_CCK_OFDM_DELTA 15 -#define AR5K_EEPROM_N_IQ_CAL 2 - -/* Struct to hold EEPROM calibration data */ -struct ath5k_eeprom_info { - u16 ee_magic; - u16 ee_protect; - u16 ee_regdomain; - u16 ee_version; - u16 ee_header; - u16 ee_ant_gain; - u16 ee_misc0; - u16 ee_misc1; - u16 ee_cck_ofdm_gain_delta; - u16 ee_cck_ofdm_power_delta; - u16 ee_scaled_cck_delta; - - /* Used for tx thermal adjustment (eeprom_init, rfregs) */ - u16 ee_tx_clip; - u16 ee_pwd_84; - u16 ee_pwd_90; - u16 ee_gain_select; - - /* RF Calibration settings (reset, rfregs) */ - u16 ee_i_cal[AR5K_EEPROM_N_MODES]; - u16 ee_q_cal[AR5K_EEPROM_N_MODES]; - u16 ee_fixed_bias[AR5K_EEPROM_N_MODES]; - u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES]; - u16 ee_xr_power[AR5K_EEPROM_N_MODES]; - u16 ee_switch_settling[AR5K_EEPROM_N_MODES]; - u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES]; - u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC]; - u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; - u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; - u16 ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES]; - u16 ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES]; - u16 ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES]; - u16 ee_thr_62[AR5K_EEPROM_N_MODES]; - u16 ee_xlna_gain[AR5K_EEPROM_N_MODES]; - u16 ee_xpd[AR5K_EEPROM_N_MODES]; - u16 ee_x_gain[AR5K_EEPROM_N_MODES]; - u16 ee_i_gain[AR5K_EEPROM_N_MODES]; - u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES]; - - /* Unused */ - u16 ee_false_detect[AR5K_EEPROM_N_MODES]; - u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN]; - u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/ - - /* Conformance test limits (Unused) */ - u16 ee_ctls; - u16 ee_ctl[AR5K_EEPROM_MAX_CTLS]; - - /* Noise Floor Calibration settings */ - s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES]; - s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES]; - s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES]; -}; - /* * Internal RX/TX descriptor structures * (rX: reserved fields possibily used by future versions of the ar5k chipset) @@ -178,14 +26,15 @@ struct ath5k_eeprom_info { */ struct ath5k_hw_rx_ctl { u32 rx_control_0; /* RX control word 0 */ + u32 rx_control_1; /* RX control word 1 */ +} __packed; +/* RX control word 0 field/sflags */ #define AR5K_DESC_RX_CTL0 0x00000000 - u32 rx_control_1; /* RX control word 1 */ - +/* RX control word 1 fields/flags */ #define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff #define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 -} __packed; /* * common hardware RX status descriptor @@ -197,6 +46,7 @@ struct ath5k_hw_rx_status { } __packed; /* 5210/5211 */ +/* RX status word 0 fields/flags */ #define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff #define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000 #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 @@ -205,6 +55,8 @@ struct ath5k_hw_rx_status { #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 + +/* RX status word 1 fields/flags */ #define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001 #define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 #define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004 @@ -220,6 +72,7 @@ struct ath5k_hw_rx_status { #define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 /* 5212 */ +/* RX status word 0 fields/flags */ #define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff #define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000 #define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 @@ -229,6 +82,8 @@ struct ath5k_hw_rx_status { #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 + +/* RX status word 1 fields/flags */ #define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001 #define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 #define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004 @@ -246,16 +101,18 @@ struct ath5k_hw_rx_status { * common hardware RX error descriptor */ struct ath5k_hw_rx_error { - u32 rx_error_0; /* RX error word 0 */ + u32 rx_error_0; /* RX status word 0 */ + u32 rx_error_1; /* RX status word 1 */ +} __packed; +/* RX error word 0 fields/flags */ #define AR5K_RX_DESC_ERROR0 0x00000000 - u32 rx_error_1; /* RX error word 1 */ - +/* RX error word 1 fields/flags */ #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 -} __packed; +/* PHY Error codes */ #define AR5K_DESC_RX_PHY_ERROR_NONE 0x00 #define AR5K_DESC_RX_PHY_ERROR_TIMING 0x20 #define AR5K_DESC_RX_PHY_ERROR_PARITY 0x40 @@ -270,7 +127,10 @@ struct ath5k_hw_rx_error { */ struct ath5k_hw_2w_tx_ctl { u32 tx_control_0; /* TX control word 0 */ + u32 tx_control_1; /* TX control word 1 */ +} __packed; +/* TX control word 0 fields/flags */ #define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff #define AR5K_2W_TX_DESC_CTL0_HEADER_LEN 0x0003f000 /*[5210 ?]*/ #define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S 12 @@ -284,29 +144,34 @@ struct ath5k_hw_2w_tx_ctl { #define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S 26 #define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000 #define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000 -#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT (ah->ah_version == AR5K_AR5210 ? \ - AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \ - AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211) + +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT \ + (ah->ah_version == AR5K_AR5210 ? \ + AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \ + AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211) + #define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 #define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 #define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 - u32 tx_control_1; /* TX control word 1 */ - +/* TX control word 1 fields/flags */ #define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff #define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000 #define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 0x0007e000 #define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211 0x000fe000 -#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX (ah->ah_version == AR5K_AR5210 ? \ - AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \ - AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211) + +#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX \ + (ah->ah_version == AR5K_AR5210 ? \ + AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \ + AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211) + #define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 #define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE 0x00700000 /*[5211]*/ #define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S 20 #define AR5K_2W_TX_DESC_CTL1_NOACK 0x00800000 /*[5211]*/ #define AR5K_2W_TX_DESC_CTL1_RTS_DURATION 0xfff80000 /*[5210 ?]*/ -} __packed; +/* Frame types */ #define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0x00 #define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 0x04 #define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 0x08 @@ -378,7 +243,10 @@ struct ath5k_hw_4w_tx_ctl { */ struct ath5k_hw_tx_status { u32 tx_status_0; /* TX status word 0 */ + u32 tx_status_1; /* TX status word 1 */ +} __packed; +/* TX status word 0 fields/flags */ #define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 #define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002 #define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004 @@ -400,8 +268,7 @@ struct ath5k_hw_tx_status { #define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 #define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16 - u32 tx_status_1; /* TX status word 1 */ - +/* TX status word 1 fields/flags */ #define AR5K_DESC_TX_STATUS1_DONE 0x00000001 #define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe #define AR5K_DESC_TX_STATUS1_SEQ_NUM_S 1 @@ -411,8 +278,6 @@ struct ath5k_hw_tx_status { #define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S 21 #define AR5K_DESC_TX_STATUS1_COMP_SUCCESS 0x00800000 #define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA 0x01000000 -} __packed; - /* * 5210/5211 hardware TX descriptor @@ -441,176 +306,27 @@ struct ath5k_hw_all_rx_desc { } u; } __packed; - /* - * AR5K REGISTER ACCESS + * Atheros hardware descriptor + * This is read and written to by the hardware */ +struct ath5k_desc { + u32 ds_link; /* physical address of the next descriptor */ + u32 ds_data; /* physical address of data buffer (skb) */ -/*Swap RX/TX Descriptor for big endian archs*/ -#if defined(__BIG_ENDIAN) -#define AR5K_INIT_CFG ( \ - AR5K_CFG_SWTD | AR5K_CFG_SWRD \ -) -#else -#define AR5K_INIT_CFG 0x00000000 -#endif - -/*#define AR5K_REG_READ(_reg) ath5k_hw_reg_read(ah, _reg) - -#define AR5K_REG_WRITE(_reg, _val) ath5k_hw_reg_write(ah, _val, _reg)*/ - -#define AR5K_REG_SM(_val, _flags) \ - (((_val) << _flags##_S) & (_flags)) - -#define AR5K_REG_MS(_val, _flags) \ - (((_val) & (_flags)) >> _flags##_S) - -/* Some registers can hold multiple values of interest. For this - * reason when we want to write to these registers we must first - * retrieve the values which we do not want to clear (lets call this - * old_data) and then set the register with this and our new_value: - * ( old_data | new_value) */ -#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val) \ - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \ - (((_val) << _flags##_S) & (_flags)), _reg) - -#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask) \ - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & \ - (_mask)) | (_flags), _reg) - -#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags) \ - ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg) - -#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \ - ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg) - -#define AR5K_PHY_WRITE(ah, _reg, _val) \ - ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2)) - -#define AR5K_PHY_READ(ah, _reg) \ - ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2)) - -#define AR5K_REG_WAIT(_i) do { \ - if (_i % 64) \ - udelay(1); \ -} while (0) - -#define AR5K_EEPROM_READ(_o, _v) do { \ - if ((ret = ath5k_hw_eeprom_read(ah, (_o), &(_v))) != 0) \ - return (ret); \ -} while (0) - -#define AR5K_EEPROM_READ_HDR(_o, _v) \ - AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ - -/* Read status of selected queue */ -#define AR5K_REG_READ_Q(ah, _reg, _queue) \ - (ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \ - -#define AR5K_REG_WRITE_Q(ah, _reg, _queue) \ - ath5k_hw_reg_write(ah, (1 << _queue), _reg) - -#define AR5K_Q_ENABLE_BITS(_reg, _queue) do { \ - _reg |= 1 << _queue; \ -} while (0) - -#define AR5K_Q_DISABLE_BITS(_reg, _queue) do { \ - _reg &= ~(1 << _queue); \ -} while (0) - -#define AR5K_LOW_ID(_a)( \ -(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \ -) - -#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8) - -/* - * Initial register values - */ - -/* - * Common initial register values - */ -#define AR5K_INIT_MODE CHANNEL_B - -#define AR5K_INIT_TX_LATENCY 502 -#define AR5K_INIT_USEC 39 -#define AR5K_INIT_USEC_TURBO 79 -#define AR5K_INIT_USEC_32 31 -#define AR5K_INIT_CARR_SENSE_EN 1 -#define AR5K_INIT_PROG_IFS 920 -#define AR5K_INIT_PROG_IFS_TURBO 960 -#define AR5K_INIT_EIFS 3440 -#define AR5K_INIT_EIFS_TURBO 6880 -#define AR5K_INIT_SLOT_TIME 396 -#define AR5K_INIT_SLOT_TIME_TURBO 480 -#define AR5K_INIT_ACK_CTS_TIMEOUT 1024 -#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800 -#define AR5K_INIT_SIFS 560 -#define AR5K_INIT_SIFS_TURBO 480 -#define AR5K_INIT_SH_RETRY 10 -#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY -#define AR5K_INIT_SSH_RETRY 32 -#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY -#define AR5K_INIT_TX_RETRY 10 -#define AR5K_INIT_TOPS 8 -#define AR5K_INIT_RXNOFRM 8 -#define AR5K_INIT_RPGTO 0 -#define AR5K_INIT_TXNOFRM 0 -#define AR5K_INIT_BEACON_PERIOD 65535 -#define AR5K_INIT_TIM_OFFSET 0 -#define AR5K_INIT_BEACON_EN 0 -#define AR5K_INIT_RESET_TSF 0 - -#define AR5K_INIT_TRANSMIT_LATENCY ( \ - (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ - (AR5K_INIT_USEC) \ -) -#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \ - (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ - (AR5K_INIT_USEC_TURBO) \ -) -#define AR5K_INIT_PROTO_TIME_CNTRL ( \ - (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \ - (AR5K_INIT_PROG_IFS) \ -) -#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \ - (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \ - (AR5K_INIT_PROG_IFS_TURBO) \ -) -#define AR5K_INIT_BEACON_CONTROL ( \ - (AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) | \ - (AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD) \ -) - -/* - * Non-common initial register values which have to be loaded into the - * card at boot time and after each reset. - */ - -/* Register dumps are done per operation mode */ -#define AR5K_INI_RFGAIN_5GHZ 0 -#define AR5K_INI_RFGAIN_2GHZ 1 - -#define AR5K_INI_VAL_11A 0 -#define AR5K_INI_VAL_11A_TURBO 1 -#define AR5K_INI_VAL_11B 2 -#define AR5K_INI_VAL_11G 3 -#define AR5K_INI_VAL_11G_TURBO 4 -#define AR5K_INI_VAL_XR 0 -#define AR5K_INI_VAL_MAX 5 - -#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS -#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS + union { + struct ath5k_hw_5210_tx_desc ds_tx5210; + struct ath5k_hw_5212_tx_desc ds_tx5212; + struct ath5k_hw_all_rx_desc ds_rx; + } ud; +} __packed; -static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) -{ - u32 retval = 0, bit, i; +#define AR5K_RXDESC_INTREQ 0x0020 - for (i = 0; i < bits; i++) { - bit = (val >> i) & 1; - retval = (retval << 1) | bit; - } +#define AR5K_TXDESC_CLRDMASK 0x0001 +#define AR5K_TXDESC_NOACK 0x0002 /*[5211+]*/ +#define AR5K_TXDESC_RTSENA 0x0004 +#define AR5K_TXDESC_CTSENA 0x0008 +#define AR5K_TXDESC_INTREQ 0x0010 +#define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/ - return retval; -} diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c new file mode 100644 index 00000000000..7adceb2c7fa --- /dev/null +++ b/drivers/net/wireless/ath5k/dma.c @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * + * Permission to use, copy, modify, and 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. + * + */ + +/*************************************\ +* DMA and interrupt masking functions * +\*************************************/ + +/* + * dma.c - DMA and interrupt masking functions + * + * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and + * handle queue setup for 5210 chipset (rest are handled on qcu.c). + * Also we setup interrupt mask register (IMR) and read the various iterrupt + * status registers (ISR). + * + * TODO: Handle SISR on 5211+ and introduce a function to return the queue + * number that resulted the interrupt. + */ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/*********\ +* Receive * +\*********/ + +/** + * ath5k_hw_start_rx_dma - Start DMA receive + * + * @ah: The &struct ath5k_hw + */ +void ath5k_hw_start_rx_dma(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); + ath5k_hw_reg_read(ah, AR5K_CR); +} + +/** + * ath5k_hw_stop_rx_dma - Stop DMA receive + * + * @ah: The &struct ath5k_hw + */ +int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) +{ + unsigned int i; + + ATH5K_TRACE(ah->ah_sc); + ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR); + + /* + * It may take some time to disable the DMA receive unit + */ + for (i = 1000; i > 0 && + (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; + i--) + udelay(10); + + return i ? 0 : -EBUSY; +} + +/** + * ath5k_hw_get_rxdp - Get RX Descriptor's address + * + * @ah: The &struct ath5k_hw + * + * XXX: Is RXDP read and clear ? + */ +u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah) +{ + return ath5k_hw_reg_read(ah, AR5K_RXDP); +} + +/** + * ath5k_hw_set_rxdp - Set RX Descriptor's address + * + * @ah: The &struct ath5k_hw + * @phys_addr: RX descriptor address + * + * XXX: Should we check if rx is enabled before setting rxdp ? + */ +void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) +{ + ATH5K_TRACE(ah->ah_sc); + + ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); +} + + +/**********\ +* Transmit * +\**********/ + +/** + * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue + * + * @ah: The &struct ath5k_hw + * @queue: The hw queue number + * + * Start DMA transmit for a specific queue and since 5210 doesn't have + * QCU/DCU, set up queue parameters for 5210 here based on queue type (one + * queue for normal data and one queue for beacons). For queue setup + * on newer chips check out qcu.c. Returns -EINVAL if queue number is out + * of range or if queue is already disabled. + * + * NOTE: Must be called after setting up tx control descriptor for that + * queue (see below). + */ +int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) +{ + u32 tx_queue; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* Return if queue is declared inactive */ + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return -EIO; + + if (ah->ah_version == AR5K_AR5210) { + tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); + + /* + * Set the queue by type on 5210 + */ + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0; + break; + case AR5K_TX_QUEUE_BEACON: + tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; + ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, + AR5K_BSR); + break; + case AR5K_TX_QUEUE_CAB: + tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; + ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V | + AR5K_BCR_BDMAE, AR5K_BSR); + break; + default: + return -EINVAL; + } + /* Start queue */ + ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); + ath5k_hw_reg_read(ah, AR5K_CR); + } else { + /* Return if queue is disabled */ + if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue)) + return -EIO; + + /* Start queue */ + AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue); + } + + return 0; +} + +/** + * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue + * + * @ah: The &struct ath5k_hw + * @queue: The hw queue number + * + * Stop DMA transmit on a specific hw queue and drain queue so we don't + * have any pending frames. Returns -EBUSY if we still have pending frames, + * -EINVAL if queue number is out of range. + * + */ +int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) +{ + unsigned int i = 40; + u32 tx_queue, pending; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* Return if queue is declared inactive */ + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return -EIO; + + if (ah->ah_version == AR5K_AR5210) { + tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); + + /* + * Set by queue type + */ + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + /* XXX Fix me... */ + tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1; + ath5k_hw_reg_write(ah, 0, AR5K_BSR); + break; + default: + return -EINVAL; + } + + /* Stop queue */ + ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); + ath5k_hw_reg_read(ah, AR5K_CR); + } else { + /* + * Schedule TX disable and wait until queue is empty + */ + AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue); + + /*Check for pending frames*/ + do { + pending = ath5k_hw_reg_read(ah, + AR5K_QUEUE_STATUS(queue)) & + AR5K_QCU_STS_FRMPENDCNT; + udelay(100); + } while (--i && pending); + + /* For 2413+ order PCU to drop packets using + * QUIET mechanism */ + if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) && + pending){ + /* Set periodicity and duration */ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)| + AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR), + AR5K_QUIET_CTL2); + + /* Enable quiet period for current TSF */ + ath5k_hw_reg_write(ah, + AR5K_QUIET_CTL1_QT_EN | + AR5K_REG_SM(ath5k_hw_reg_read(ah, + AR5K_TSF_L32_5211) >> 10, + AR5K_QUIET_CTL1_NEXT_QT_TSF), + AR5K_QUIET_CTL1); + + /* Force channel idle high */ + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211, + AR5K_DIAG_SW_CHANEL_IDLE_HIGH); + + /* Wait a while and disable mechanism */ + udelay(200); + AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1, + AR5K_QUIET_CTL1_QT_EN); + + /* Re-check for pending frames */ + i = 40; + do { + pending = ath5k_hw_reg_read(ah, + AR5K_QUEUE_STATUS(queue)) & + AR5K_QCU_STS_FRMPENDCNT; + udelay(100); + } while (--i && pending); + + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211, + AR5K_DIAG_SW_CHANEL_IDLE_HIGH); + } + + /* Clear register */ + ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); + if (pending) + return -EBUSY; + } + + /* TODO: Check for success on 5210 else return error */ + return 0; +} + +/** + * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue + * + * @ah: The &struct ath5k_hw + * @queue: The hw queue number + * + * Get TX descriptor's address for a specific queue. For 5210 we ignore + * the queue number and use tx queue type since we only have 2 queues. + * We use TXDP0 for normal data queue and TXDP1 for beacon queue. + * For newer chips with QCU/DCU we just read the corresponding TXDP register. + * + * XXX: Is TXDP read and clear ? + */ +u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue) +{ + u16 tx_reg; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* + * Get the transmit queue descriptor pointer from the selected queue + */ + /*5210 doesn't have QCU*/ + if (ah->ah_version == AR5K_AR5210) { + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_reg = AR5K_NOQCU_TXDP0; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + tx_reg = AR5K_NOQCU_TXDP1; + break; + default: + return 0xffffffff; + } + } else { + tx_reg = AR5K_QUEUE_TXDP(queue); + } + + return ath5k_hw_reg_read(ah, tx_reg); +} + +/** + * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue + * + * @ah: The &struct ath5k_hw + * @queue: The hw queue number + * + * Set TX descriptor's address for a specific queue. For 5210 we ignore + * the queue number and we use tx queue type since we only have 2 queues + * so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue. + * For newer chips with QCU/DCU we just set the corresponding TXDP register. + * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still + * active. + */ +int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) +{ + u16 tx_reg; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* + * Set the transmit queue descriptor pointer register by type + * on 5210 + */ + if (ah->ah_version == AR5K_AR5210) { + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_reg = AR5K_NOQCU_TXDP0; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + tx_reg = AR5K_NOQCU_TXDP1; + break; + default: + return -EINVAL; + } + } else { + /* + * Set the transmit queue descriptor pointer for + * the selected queue on QCU for 5211+ + * (this won't work if the queue is still active) + */ + if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) + return -EIO; + + tx_reg = AR5K_QUEUE_TXDP(queue); + } + + /* Set descriptor pointer */ + ath5k_hw_reg_write(ah, phys_addr, tx_reg); + + return 0; +} + +/** + * ath5k_hw_update_tx_triglevel - Update tx trigger level + * + * @ah: The &struct ath5k_hw + * @increase: Flag to force increase of trigger level + * + * This function increases/decreases the tx trigger level for the tx fifo + * buffer (aka FIFO threshold) that is used to indicate when PCU flushes + * the buffer and transmits it's data. Lowering this results sending small + * frames more quickly but can lead to tx underruns, raising it a lot can + * result other problems (i think bmiss is related). Right now we start with + * the lowest possible (64Bytes) and if we get tx underrun we increase it using + * the increase flag. Returns -EIO if we have have reached maximum/minimum. + * + * XXX: Link this with tx DMA size ? + * XXX: Use it to save interrupts ? + * TODO: Needs testing, i think it's related to bmiss... + */ +int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) +{ + u32 trigger_level, imr; + int ret = -EIO; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Disable interrupts by setting the mask + */ + imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL); + + trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG), + AR5K_TXCFG_TXFULL); + + if (!increase) { + if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) + goto done; + } else + trigger_level += + ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2); + + /* + * Update trigger level on success + */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL); + else + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_TXFULL, trigger_level); + + ret = 0; + +done: + /* + * Restore interrupt mask + */ + ath5k_hw_set_imr(ah, imr); + + return ret; +} + +/*******************\ +* Interrupt masking * +\*******************/ + +/** + * ath5k_hw_is_intr_pending - Check if we have pending interrupts + * + * @ah: The &struct ath5k_hw + * + * Check if we have pending interrupts to process. Returns 1 if we + * have pending interrupts and 0 if we haven't. + */ +bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0; +} + +/** + * ath5k_hw_get_isr - Get interrupt status + * + * @ah: The @struct ath5k_hw + * @interrupt_mask: Driver's interrupt mask used to filter out + * interrupts in sw. + * + * This function is used inside our interrupt handler to determine the reason + * for the interrupt by reading Primary Interrupt Status Register. Returns an + * abstract interrupt status mask which is mostly ISR with some uncommon bits + * being mapped on some standard non hw-specific positions + * (check out &ath5k_int). + * + * NOTE: We use read-and-clear register, so after this function is called ISR + * is zeroed. + * + * XXX: Why filter interrupts in sw with interrupt_mask ? No benefit at all + * plus it can be misleading (one might thing that we save interrupts this way) + */ +int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) +{ + u32 data; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Read interrupt status from the Interrupt Status register + * on 5210 + */ + if (ah->ah_version == AR5K_AR5210) { + data = ath5k_hw_reg_read(ah, AR5K_ISR); + if (unlikely(data == AR5K_INT_NOCARD)) { + *interrupt_mask = data; + return -ENODEV; + } + } else { + /* + * Read interrupt status from the Read-And-Clear + * shadow register. + * Note: PISR/SISR Not available on 5210 + */ + data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); + } + + /* + * Get abstract interrupt mask (driver-compatible) + */ + *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; + + if (unlikely(data == AR5K_INT_NOCARD)) + return -ENODEV; + + if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR)) + *interrupt_mask |= AR5K_INT_RX; + + if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR + | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL)) + *interrupt_mask |= AR5K_INT_TX; + + if (ah->ah_version != AR5K_AR5210) { + /*HIU = Host Interface Unit (PCI etc)*/ + if (unlikely(data & (AR5K_ISR_HIUERR))) + *interrupt_mask |= AR5K_INT_FATAL; + + /*Beacon Not Ready*/ + if (unlikely(data & (AR5K_ISR_BNR))) + *interrupt_mask |= AR5K_INT_BNR; + } + + /* + * XXX: BMISS interrupts may occur after association. + * I found this on 5210 code but it needs testing. If this is + * true we should disable them before assoc and re-enable them + * after a successfull assoc + some jiffies. + */ +#if 0 + interrupt_mask &= ~AR5K_INT_BMISS; +#endif + + /* + * In case we didn't handle anything, + * print the register value. + */ + if (unlikely(*interrupt_mask == 0 && net_ratelimit())) + ATH5K_PRINTF("0x%08x\n", data); + + return 0; +} + +/** + * ath5k_hw_set_imr - Set interrupt mask + * + * @ah: The &struct ath5k_hw + * @new_mask: The new interrupt mask to be set + * + * Set the interrupt mask in hw to save interrupts. We do that by mapping + * ath5k_int bits to hw-specific bits to remove abstraction and writing + * Interrupt Mask Register. + */ +enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) +{ + enum ath5k_int old_mask, int_mask; + + /* + * Disable card interrupts to prevent any race conditions + * (they will be re-enabled afterwards). + */ + ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + + old_mask = ah->ah_imr; + + /* + * Add additional, chipset-dependent interrupt mask flags + * and write them to the IMR (interrupt mask register). + */ + int_mask = new_mask & AR5K_INT_COMMON; + + if (new_mask & AR5K_INT_RX) + int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN | + AR5K_IMR_RXDESC; + + if (new_mask & AR5K_INT_TX) + int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC | + AR5K_IMR_TXURN; + + if (ah->ah_version != AR5K_AR5210) { + if (new_mask & AR5K_INT_FATAL) { + int_mask |= AR5K_IMR_HIUERR; + AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT | + AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); + } + } + + ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + + /* Store new interrupt mask */ + ah->ah_imr = new_mask; + + /* ..re-enable interrupts */ + ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + + return old_mask; +} + diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c new file mode 100644 index 00000000000..a883839b6a9 --- /dev/null +++ b/drivers/net/wireless/ath5k/eeprom.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * + * Permission to use, copy, modify, and 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. + * + */ + +/*************************************\ +* EEPROM access functions and helpers * +\*************************************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * Read from eeprom + */ +static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) +{ + u32 status, timeout; + + ATH5K_TRACE(ah->ah_sc); + /* + * Initialize EEPROM access + */ + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); + (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset)); + } else { + ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); + AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, + AR5K_EEPROM_CMD_READ); + } + + for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { + status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); + if (status & AR5K_EEPROM_STAT_RDDONE) { + if (status & AR5K_EEPROM_STAT_RDERR) + return -EIO; + *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & + 0xffff); + return 0; + } + udelay(15); + } + + return -ETIMEDOUT; +} + +/* + * Translate binary channel representation in EEPROM to frequency + */ +static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, + unsigned int mode) +{ + u16 val; + + if (bin == AR5K_EEPROM_CHANNEL_DIS) + return bin; + + if (mode == AR5K_EEPROM_MODE_11A) { + if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + val = (5 * bin) + 4800; + else + val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 : + (bin * 10) + 5100; + } else { + if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + val = bin + 2300; + else + val = bin + 2400; + } + + return val; +} + +/* + * Read antenna infos from eeprom + */ +static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, + unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 o = *offset; + u16 val; + int ret, i = 0; + + AR5K_EEPROM_READ(o++, val); + ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; + ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; + ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; + ee->ee_ant_control[mode][i++] = val & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f; + ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 2) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3; + ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f; + ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; + ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; + ee->ee_ant_control[mode][i++] = val & 0x3f; + + /* Get antenna modes */ + ah->ah_antenna[mode][0] = + (ee->ee_ant_control[mode][0] << 4) | 0x1; + ah->ah_antenna[mode][AR5K_ANT_FIXED_A] = + ee->ee_ant_control[mode][1] | + (ee->ee_ant_control[mode][2] << 6) | + (ee->ee_ant_control[mode][3] << 12) | + (ee->ee_ant_control[mode][4] << 18) | + (ee->ee_ant_control[mode][5] << 24); + ah->ah_antenna[mode][AR5K_ANT_FIXED_B] = + ee->ee_ant_control[mode][6] | + (ee->ee_ant_control[mode][7] << 6) | + (ee->ee_ant_control[mode][8] << 12) | + (ee->ee_ant_control[mode][9] << 18) | + (ee->ee_ant_control[mode][10] << 24); + + /* return new offset */ + *offset = o; + + return 0; +} + +/* + * Read supported modes from eeprom + */ +static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, + unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 o = *offset; + u16 val; + int ret; + + AR5K_EEPROM_READ(o++, val); + ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; + ee->ee_thr_62[mode] = val & 0xff; + + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) + ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28; + + AR5K_EEPROM_READ(o++, val); + ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff; + ee->ee_tx_frm2xpa_enable[mode] = val & 0xff; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff; + + if ((val & 0xff) & 0x80) + ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1); + else + ee->ee_noise_floor_thr[mode] = val & 0xff; + + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) + ee->ee_noise_floor_thr[mode] = + mode == AR5K_EEPROM_MODE_11A ? -54 : -1; + + AR5K_EEPROM_READ(o++, val); + ee->ee_xlna_gain[mode] = (val >> 5) & 0xff; + ee->ee_x_gain[mode] = (val >> 1) & 0xf; + ee->ee_xpd[mode] = val & 0x1; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) + ee->ee_fixed_bias[mode] = (val >> 13) & 0x1; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) { + AR5K_EEPROM_READ(o++, val); + ee->ee_false_detect[mode] = (val >> 6) & 0x7f; + + if (mode == AR5K_EEPROM_MODE_11A) + ee->ee_xr_power[mode] = val & 0x3f; + else { + ee->ee_ob[mode][0] = val & 0x7; + ee->ee_db[mode][0] = (val >> 3) & 0x7; + } + } + + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) { + ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN; + ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA; + } else { + ee->ee_i_gain[mode] = (val >> 13) & 0x7; + + AR5K_EEPROM_READ(o++, val); + ee->ee_i_gain[mode] |= (val << 3) & 0x38; + + if (mode == AR5K_EEPROM_MODE_11G) + ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; + } + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && + mode == AR5K_EEPROM_MODE_11A) { + ee->ee_i_cal[mode] = (val >> 8) & 0x3f; + ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + } + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 && + mode == AR5K_EEPROM_MODE_11G) + ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + + /* return new offset */ + *offset = o; + + return 0; +} + +/* + * Initialize eeprom & capabilities structs + */ +int ath5k_eeprom_init(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + unsigned int mode, i; + int ret; + u32 offset; + u16 val; + + /* Initial TX thermal adjustment values */ + ee->ee_tx_clip = 4; + ee->ee_pwd_84 = ee->ee_pwd_90 = 1; + ee->ee_gain_select = 1; + + /* + * Read values from EEPROM and store them in the capability structure + */ + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); + + /* Return if we have an old EEPROM */ + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) + return 0; + +#ifdef notyet + /* + * Validate the checksum of the EEPROM date. There are some + * devices with invalid EEPROMs. + */ + for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { + AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); + cksum ^= val; + } + if (cksum != AR5K_EEPROM_INFO_CKSUM) { + ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); + return -EIO; + } +#endif + + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), + ee_ant_gain); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); + } + + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; + + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; + } + + /* + * Get conformance test limit values + */ + offset = AR5K_EEPROM_CTL(ah->ah_ee_version); + ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version); + + for (i = 0; i < ee->ee_ctls; i++) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_ctl[i] = (val >> 8) & 0xff; + ee->ee_ctl[i + 1] = val & 0xff; + } + + /* + * Get values for 802.11a (5GHz) + */ + mode = AR5K_EEPROM_MODE_11A; + + ee->ee_turbo_max_power[mode] = + AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + + offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + ee->ee_ob[mode][3] = (val >> 5) & 0x7; + ee->ee_db[mode][3] = (val >> 2) & 0x7; + ee->ee_ob[mode][2] = (val << 1) & 0x7; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_ob[mode][2] |= (val >> 15) & 0x1; + ee->ee_db[mode][2] = (val >> 12) & 0x7; + ee->ee_ob[mode][1] = (val >> 9) & 0x7; + ee->ee_db[mode][1] = (val >> 6) & 0x7; + ee->ee_ob[mode][0] = (val >> 3) & 0x7; + ee->ee_db[mode][0] = val & 0x7; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_margin_tx_rx[mode] = val & 0x3f; + } + + /* + * Get values for 802.11b (2.4GHz) + */ + mode = AR5K_EEPROM_MODE_11B; + offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][0] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + ee->ee_cal_pier[mode][1] = + ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][2] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + } + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + /* + * Get values for 802.11g (2.4GHz) + */ + mode = AR5K_EEPROM_MODE_11G; + offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][0] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + ee->ee_cal_pier[mode][1] = + ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + + AR5K_EEPROM_READ(offset++, val); + ee->ee_turbo_max_power[mode] = val & 0x7f; + ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][2] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_i_cal[mode] = (val >> 8) & 0x3f; + ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_cck_ofdm_gain_delta = val & 0xff; + } + } + + /* + * Read 5GHz EEPROM channels + */ + + return 0; +} + +/* + * Read the MAC address from eeprom + */ +int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + u8 mac_d[ETH_ALEN]; + u32 total, offset; + u16 data; + int octet, ret; + + memset(mac, 0, ETH_ALEN); + memset(mac_d, 0, ETH_ALEN); + + ret = ath5k_hw_eeprom_read(ah, 0x20, &data); + if (ret) + return ret; + + for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { + ret = ath5k_hw_eeprom_read(ah, offset, &data); + if (ret) + return ret; + + total += data; + mac_d[octet + 1] = data & 0xff; + mac_d[octet] = data >> 8; + octet += 2; + } + + memcpy(mac, mac_d, ETH_ALEN); + + if (!total || total == 3 * 0xffff) + return -EINVAL; + + return 0; +} + diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h new file mode 100644 index 00000000000..a468ecfbb18 --- /dev/null +++ b/drivers/net/wireless/ath5k/eeprom.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * + * Permission to use, copy, modify, and 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. + * + */ + +/* + * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) + */ +#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ +#define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ +#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ +#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ +#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ + +#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ +#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ +#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 +#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ +#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 +#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ +#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 +#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ +#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 +#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ +#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 +#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ +#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 +#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ +#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 +#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ +#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ +#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) +#define AR5K_EEPROM_INFO_CKSUM 0xffff +#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n)) + +#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */ +#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */ +#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */ +#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */ +#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */ +#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */ +#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ +#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */ +#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */ +#define AR5K_EEPROM_VERSION_4_3 0x4003 +#define AR5K_EEPROM_VERSION_4_4 0x4004 +#define AR5K_EEPROM_VERSION_4_5 0x4005 +#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */ +#define AR5K_EEPROM_VERSION_4_7 0x4007 + +#define AR5K_EEPROM_MODE_11A 0 +#define AR5K_EEPROM_MODE_11B 1 +#define AR5K_EEPROM_MODE_11G 2 + +#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */ +#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) +#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) +#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) +#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */ +#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ +#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) +#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */ +#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ + +#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c +#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 +#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002 +#define AR5K_EEPROM_RFKILL_POLARITY_S 1 + +/* Newer EEPROMs are using a different offset */ +#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \ + (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0) + +#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3) +#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff)) + +/* calibration settings */ +#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4) +#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2) +#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d) +#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */ + +/* [3.1 - 3.3] */ +#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec +#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed + +/* Misc values available since EEPROM 4.0 */ +#define AR5K_EEPROM_MISC0 0x00c4 +#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) +#define AR5K_EEPROM_MISC1 0x00c5 +#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) + + +/* Some EEPROM defines */ +#define AR5K_EEPROM_EEP_SCALE 100 +#define AR5K_EEPROM_EEP_DELTA 10 +#define AR5K_EEPROM_N_MODES 3 +#define AR5K_EEPROM_N_5GHZ_CHAN 10 +#define AR5K_EEPROM_N_2GHZ_CHAN 3 +#define AR5K_EEPROM_MAX_CHAN 10 +#define AR5K_EEPROM_N_PCDAC 11 +#define AR5K_EEPROM_N_TEST_FREQ 8 +#define AR5K_EEPROM_N_EDGES 8 +#define AR5K_EEPROM_N_INTERCEPTS 11 +#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff) +#define AR5K_EEPROM_PCDAC_M 0x3f +#define AR5K_EEPROM_PCDAC_START 1 +#define AR5K_EEPROM_PCDAC_STOP 63 +#define AR5K_EEPROM_PCDAC_STEP 1 +#define AR5K_EEPROM_NON_EDGE_M 0x40 +#define AR5K_EEPROM_CHANNEL_POWER 8 +#define AR5K_EEPROM_N_OBDB 4 +#define AR5K_EEPROM_OBDB_DIS 0xffff +#define AR5K_EEPROM_CHANNEL_DIS 0xff +#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10) +#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32) +#define AR5K_EEPROM_MAX_CTLS 32 +#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 +#define AR5K_EEPROM_N_XPD0_POINTS 4 +#define AR5K_EEPROM_N_XPD3_POINTS 3 +#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35 +#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 +#define AR5K_EEPROM_POWER_M 0x3f +#define AR5K_EEPROM_POWER_MIN 0 +#define AR5K_EEPROM_POWER_MAX 3150 +#define AR5K_EEPROM_POWER_STEP 50 +#define AR5K_EEPROM_POWER_TABLE_SIZE 64 +#define AR5K_EEPROM_N_POWER_LOC_11B 4 +#define AR5K_EEPROM_N_POWER_LOC_11G 6 +#define AR5K_EEPROM_I_GAIN 10 +#define AR5K_EEPROM_CCK_OFDM_DELTA 15 +#define AR5K_EEPROM_N_IQ_CAL 2 + +#define AR5K_EEPROM_READ(_o, _v) do { \ + ret = ath5k_hw_eeprom_read(ah, (_o), &(_v)); \ + if (ret) \ + return ret; \ +} while (0) + +#define AR5K_EEPROM_READ_HDR(_o, _v) \ + AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ + +/* Struct to hold EEPROM calibration data */ +struct ath5k_eeprom_info { + u16 ee_magic; + u16 ee_protect; + u16 ee_regdomain; + u16 ee_version; + u16 ee_header; + u16 ee_ant_gain; + u16 ee_misc0; + u16 ee_misc1; + u16 ee_cck_ofdm_gain_delta; + u16 ee_cck_ofdm_power_delta; + u16 ee_scaled_cck_delta; + + /* Used for tx thermal adjustment (eeprom_init, rfregs) */ + u16 ee_tx_clip; + u16 ee_pwd_84; + u16 ee_pwd_90; + u16 ee_gain_select; + + /* RF Calibration settings (reset, rfregs) */ + u16 ee_i_cal[AR5K_EEPROM_N_MODES]; + u16 ee_q_cal[AR5K_EEPROM_N_MODES]; + u16 ee_fixed_bias[AR5K_EEPROM_N_MODES]; + u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES]; + u16 ee_xr_power[AR5K_EEPROM_N_MODES]; + u16 ee_switch_settling[AR5K_EEPROM_N_MODES]; + u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES]; + u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC]; + u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; + u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; + u16 ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES]; + u16 ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES]; + u16 ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES]; + u16 ee_thr_62[AR5K_EEPROM_N_MODES]; + u16 ee_xlna_gain[AR5K_EEPROM_N_MODES]; + u16 ee_xpd[AR5K_EEPROM_N_MODES]; + u16 ee_x_gain[AR5K_EEPROM_N_MODES]; + u16 ee_i_gain[AR5K_EEPROM_N_MODES]; + u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES]; + + /* Unused */ + u16 ee_false_detect[AR5K_EEPROM_N_MODES]; + u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN]; + u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/ + + /* Conformance test limits (Unused) */ + u16 ee_ctls; + u16 ee_ctl[AR5K_EEPROM_MAX_CTLS]; + + /* Noise Floor Calibration settings */ + s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES]; + s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES]; + s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES]; +}; diff --git a/drivers/net/wireless/ath5k/gpio.c b/drivers/net/wireless/ath5k/gpio.c new file mode 100644 index 00000000000..b77205adc18 --- /dev/null +++ b/drivers/net/wireless/ath5k/gpio.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * + * Permission to use, copy, modify, and 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. + * + */ + +/****************\ + GPIO Functions +\****************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * Set led state + */ +void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) +{ + u32 led; + /*5210 has different led mode handling*/ + u32 led_5210; + + ATH5K_TRACE(ah->ah_sc); + + /*Reset led status*/ + if (ah->ah_version != AR5K_AR5210) + AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, + AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED); + + /* + * Some blinking values, define at your wish + */ + switch (state) { + case AR5K_LED_SCAN: + case AR5K_LED_AUTH: + led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND; + led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL; + break; + + case AR5K_LED_INIT: + led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE; + led_5210 = AR5K_PCICFG_LED_PEND; + break; + + case AR5K_LED_ASSOC: + case AR5K_LED_RUN: + led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC; + led_5210 = AR5K_PCICFG_LED_ASSOC; + break; + + default: + led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE; + led_5210 = AR5K_PCICFG_LED_PEND; + break; + } + + /*Write new status to the register*/ + if (ah->ah_version != AR5K_AR5210) + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); +} + +/* + * Set GPIO inputs + */ +int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) +{ + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return -EINVAL; + + ath5k_hw_reg_write(ah, + (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) + | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); + + return 0; +} + +/* + * Set GPIO outputs + */ +int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) +{ + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return -EINVAL; + + ath5k_hw_reg_write(ah, + (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) + | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); + + return 0; +} + +/* + * Get GPIO state + */ +u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) +{ + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return 0xffffffff; + + /* GPIO input magic */ + return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & + 0x1; +} + +/* + * Set GPIO state + */ +int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) +{ + u32 data; + ATH5K_TRACE(ah->ah_sc); + + if (gpio > AR5K_NUM_GPIO) + return -EINVAL; + + /* GPIO output magic */ + data = ath5k_hw_reg_read(ah, AR5K_GPIODO); + + data &= ~(1 << gpio); + data |= (val & 1) << gpio; + + ath5k_hw_reg_write(ah, data, AR5K_GPIODO); + + return 0; +} + +/* + * Initialize the GPIO interrupt (RFKill switch) + */ +void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, + u32 interrupt_level) +{ + u32 data; + + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return; + + /* + * Set the GPIO interrupt + */ + data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & + ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | + AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | + (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); + + ath5k_hw_reg_write(ah, interrupt_level ? data : + (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); + + ah->ah_imr |= AR5K_IMR_GPIO; + + /* Enable GPIO interrupts */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); +} + diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c deleted file mode 100644 index ad1a5b422c8..00000000000 --- a/drivers/net/wireless/ath5k/hw.c +++ /dev/null @@ -1,4529 +0,0 @@ -/* - * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> - * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com> - * Copyright (c) 2007 Matthew W. S. Bell <mentor@madwifi.org> - * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu> - * Copyright (c) 2007 Pavel Roskin <proski@gnu.org> - * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> - * - * Permission to use, copy, modify, and 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. - * - */ - -/* - * HW related functions for Atheros Wireless LAN devices. - */ - -#include <linux/pci.h> -#include <linux/delay.h> - -#include "reg.h" -#include "base.h" -#include "debug.h" - -/* Rate tables */ -static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A; -static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B; -static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G; -static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO; -static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR; - -/* Prototypes */ -static int ath5k_hw_nic_reset(struct ath5k_hw *, u32); -static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool); -static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, - unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, - unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int); -static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *, - unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, - unsigned int); -static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *, - struct ath5k_tx_status *); -static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, - unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, - unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int); -static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *, - struct ath5k_tx_status *); -static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *, struct ath5k_desc *, - struct ath5k_rx_status *); -static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *, struct ath5k_desc *, - struct ath5k_rx_status *); -static int ath5k_hw_get_capabilities(struct ath5k_hw *); - -static int ath5k_eeprom_init(struct ath5k_hw *); -static int ath5k_eeprom_read_mac(struct ath5k_hw *, u8 *); - -static int ath5k_hw_enable_pspoll(struct ath5k_hw *, u8 *, u16); -static int ath5k_hw_disable_pspoll(struct ath5k_hw *); - -/* - * Enable to overwrite the country code (use "00" for debug) - */ -#if 0 -#define COUNTRYCODE "00" -#endif - -/*******************\ - General Functions -\*******************/ - -/* - * Functions used internaly - */ - -static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) -{ - return turbo ? (usec * 80) : (usec * 40); -} - -static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) -{ - return turbo ? (clock / 80) : (clock / 40); -} - -/* - * Check if a register write has been completed - */ -int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, - bool is_set) -{ - int i; - u32 data; - - for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { - data = ath5k_hw_reg_read(ah, reg); - if (is_set && (data & flag)) - break; - else if ((data & flag) == val) - break; - udelay(15); - } - - return (i <= 0) ? -EAGAIN : 0; -} - - -/***************************************\ - Attach/Detach Functions -\***************************************/ - -/* - * Power On Self Test helper function - */ -static int ath5k_hw_post(struct ath5k_hw *ah) -{ - - int i, c; - u16 cur_reg; - u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)}; - u32 var_pattern; - u32 static_pattern[4] = { - 0x55555555, 0xaaaaaaaa, - 0x66666666, 0x99999999 - }; - u32 init_val; - u32 cur_val; - - for (c = 0; c < 2; c++) { - - cur_reg = regs[c]; - - /* Save previous value */ - init_val = ath5k_hw_reg_read(ah, cur_reg); - - for (i = 0; i < 256; i++) { - var_pattern = i << 16 | i; - ath5k_hw_reg_write(ah, var_pattern, cur_reg); - cur_val = ath5k_hw_reg_read(ah, cur_reg); - - if (cur_val != var_pattern) { - ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); - return -EAGAIN; - } - - /* Found on ndiswrapper dumps */ - var_pattern = 0x0039080f; - ath5k_hw_reg_write(ah, var_pattern, cur_reg); - } - - for (i = 0; i < 4; i++) { - var_pattern = static_pattern[i]; - ath5k_hw_reg_write(ah, var_pattern, cur_reg); - cur_val = ath5k_hw_reg_read(ah, cur_reg); - - if (cur_val != var_pattern) { - ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); - return -EAGAIN; - } - - /* Found on ndiswrapper dumps */ - var_pattern = 0x003b080f; - ath5k_hw_reg_write(ah, var_pattern, cur_reg); - } - - /* Restore previous value */ - ath5k_hw_reg_write(ah, init_val, cur_reg); - - } - - return 0; - -} - -/* - * Check if the device is supported and initialize the needed structs - */ -struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) -{ - struct ath5k_hw *ah; - struct pci_dev *pdev = sc->pdev; - u8 mac[ETH_ALEN]; - int ret; - u32 srev; - - /*If we passed the test malloc a ath5k_hw struct*/ - ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); - if (ah == NULL) { - ret = -ENOMEM; - ATH5K_ERR(sc, "out of memory\n"); - goto err; - } - - ah->ah_sc = sc; - ah->ah_iobase = sc->iobase; - - /* - * HW information - */ - - ah->ah_op_mode = IEEE80211_IF_TYPE_STA; - ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; - ah->ah_turbo = false; - ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; - ah->ah_imr = 0; - ah->ah_atim_window = 0; - ah->ah_aifs = AR5K_TUNE_AIFS; - ah->ah_cw_min = AR5K_TUNE_CWMIN; - ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; - ah->ah_software_retry = false; - ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY; - - /* - * Set the mac revision based on the pci id - */ - ah->ah_version = mac_version; - - /*Fill the ath5k_hw struct with the needed functions*/ - if (ah->ah_version == AR5K_AR5212) - ah->ah_magic = AR5K_EEPROM_MAGIC_5212; - else if (ah->ah_version == AR5K_AR5211) - ah->ah_magic = AR5K_EEPROM_MAGIC_5211; - - if (ah->ah_version == AR5K_AR5212) { - ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; - ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc; - ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status; - } else { - ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; - ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc; - ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; - } - - if (ah->ah_version == AR5K_AR5212) - ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; - else if (ah->ah_version <= AR5K_AR5211) - ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status; - - /* Bring device out of sleep and reset it's units */ - ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true); - if (ret) - goto err_free; - - /* Get MAC, PHY and RADIO revisions */ - srev = ath5k_hw_reg_read(ah, AR5K_SREV); - ah->ah_mac_srev = srev; - ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); - ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); - ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & - 0xffffffff; - ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, - CHANNEL_5GHZ); - - if (ah->ah_version == AR5K_AR5210) - ah->ah_radio_2ghz_revision = 0; - else - ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, - CHANNEL_2GHZ); - - /* Return on unsuported chips (unsupported eeprom etc) */ - if ((srev >= AR5K_SREV_VER_AR5416) && - (srev < AR5K_SREV_VER_AR2425)) { - ATH5K_ERR(sc, "Device not yet supported.\n"); - ret = -ENODEV; - goto err_free; - } else if (srev == AR5K_SREV_VER_AR2425) { - ATH5K_WARN(sc, "Support for RF2425 is under development.\n"); - } - - /* Identify single chip solutions */ - if (((srev <= AR5K_SREV_VER_AR5414) && - (srev >= AR5K_SREV_VER_AR2413)) || - (srev == AR5K_SREV_VER_AR2425)) { - ah->ah_single_chip = true; - } else { - ah->ah_single_chip = false; - } - - /* Single chip radio */ - if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision) - ah->ah_radio_2ghz_revision = 0; - - /* Identify the radio chip*/ - if (ah->ah_version == AR5K_AR5210) { - ah->ah_radio = AR5K_RF5110; - /* - * Register returns 0x0/0x04 for radio revision - * so ath5k_hw_radio_revision doesn't parse the value - * correctly. For now we are based on mac's srev to - * identify RF2425 radio. - */ - } else if (srev == AR5K_SREV_VER_AR2425) { - ah->ah_radio = AR5K_RF2425; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { - ah->ah_radio = AR5K_RF5111; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) { - ah->ah_radio = AR5K_RF5112; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { - ah->ah_radio = AR5K_RF2413; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) { - ah->ah_radio = AR5K_RF5413; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) { - /* AR5424 */ - if (srev >= AR5K_SREV_VER_AR5424) { - ah->ah_radio = AR5K_RF5413; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; - /* AR2424 */ - } else { - ah->ah_radio = AR5K_RF2413; /* For testing */ - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; - } - } - ah->ah_phy = AR5K_PHY(0); - - /* - * Write PCI-E power save settings - */ - if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { - ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080); - ath5k_hw_reg_write(ah, 0x24924924, 0x4080); - ath5k_hw_reg_write(ah, 0x28000039, 0x4080); - ath5k_hw_reg_write(ah, 0x53160824, 0x4080); - ath5k_hw_reg_write(ah, 0xe5980579, 0x4080); - ath5k_hw_reg_write(ah, 0x001defff, 0x4080); - ath5k_hw_reg_write(ah, 0x1aaabe40, 0x4080); - ath5k_hw_reg_write(ah, 0xbe105554, 0x4080); - ath5k_hw_reg_write(ah, 0x000e3007, 0x4080); - ath5k_hw_reg_write(ah, 0x00000000, 0x4084); - } - - /* - * POST - */ - ret = ath5k_hw_post(ah); - if (ret) - goto err_free; - - /* Write AR5K_PCICFG_UNK on 2112B and later chips */ - if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B || - srev > AR5K_SREV_VER_AR2413) { - ath5k_hw_reg_write(ah, AR5K_PCICFG_UNK, AR5K_PCICFG); - } - - /* - * Get card capabilities, values, ... - */ - ret = ath5k_eeprom_init(ah); - if (ret) { - ATH5K_ERR(sc, "unable to init EEPROM\n"); - goto err_free; - } - - /* Get misc capabilities */ - ret = ath5k_hw_get_capabilities(ah); - if (ret) { - ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", - sc->pdev->device); - goto err_free; - } - - /* Get MAC address */ - ret = ath5k_eeprom_read_mac(ah, mac); - if (ret) { - ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", - sc->pdev->device); - goto err_free; - } - - ath5k_hw_set_lladdr(ah, mac); - /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ - memset(ah->ah_bssid, 0xff, ETH_ALEN); - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); - ath5k_hw_set_opmode(ah); - - ath5k_hw_set_rfgain_opt(ah); - - return ah; -err_free: - kfree(ah); -err: - return ERR_PTR(ret); -} - -/* - * Bring up MAC + PHY Chips - */ -static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) -{ - struct pci_dev *pdev = ah->ah_sc->pdev; - u32 turbo, mode, clock, bus_flags; - int ret; - - turbo = 0; - mode = 0; - clock = 0; - - ATH5K_TRACE(ah->ah_sc); - - /* Wakeup the device */ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n"); - return ret; - } - - if (ah->ah_version != AR5K_AR5210) { - /* - * Get channel mode flags - */ - - if (ah->ah_radio >= AR5K_RF5112) { - mode = AR5K_PHY_MODE_RAD_RF5112; - clock = AR5K_PHY_PLL_RF5112; - } else { - mode = AR5K_PHY_MODE_RAD_RF5111; /*Zero*/ - clock = AR5K_PHY_PLL_RF5111; /*Zero*/ - } - - if (flags & CHANNEL_2GHZ) { - mode |= AR5K_PHY_MODE_FREQ_2GHZ; - clock |= AR5K_PHY_PLL_44MHZ; - - if (flags & CHANNEL_CCK) { - mode |= AR5K_PHY_MODE_MOD_CCK; - } else if (flags & CHANNEL_OFDM) { - /* XXX Dynamic OFDM/CCK is not supported by the - * AR5211 so we set MOD_OFDM for plain g (no - * CCK headers) operation. We need to test - * this, 5211 might support ofdm-only g after - * all, there are also initial register values - * in the code for g mode (see initvals.c). */ - if (ah->ah_version == AR5K_AR5211) - mode |= AR5K_PHY_MODE_MOD_OFDM; - else - mode |= AR5K_PHY_MODE_MOD_DYN; - } else { - ATH5K_ERR(ah->ah_sc, - "invalid radio modulation mode\n"); - return -EINVAL; - } - } else if (flags & CHANNEL_5GHZ) { - mode |= AR5K_PHY_MODE_FREQ_5GHZ; - clock |= AR5K_PHY_PLL_40MHZ; - - if (flags & CHANNEL_OFDM) - mode |= AR5K_PHY_MODE_MOD_OFDM; - else { - ATH5K_ERR(ah->ah_sc, - "invalid radio modulation mode\n"); - return -EINVAL; - } - } else { - ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n"); - return -EINVAL; - } - - if (flags & CHANNEL_TURBO) - turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT; - } else { /* Reset the device */ - - /* ...enable Atheros turbo mode if requested */ - if (flags & CHANNEL_TURBO) - ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE, - AR5K_PHY_TURBO); - } - - /* reseting PCI on PCI-E cards results card to hang - * and always return 0xffff... so we ingore that flag - * for PCI-E cards */ - bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; - - /* Reset chipset */ - ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | - AR5K_RESET_CTL_BASEBAND | bus_flags); - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); - return -EIO; - } - - if (ah->ah_version == AR5K_AR5210) - udelay(2300); - - /* ...wakeup again!*/ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); - return ret; - } - - /* ...final warm reset */ - if (ath5k_hw_nic_reset(ah, 0)) { - ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); - return -EIO; - } - - if (ah->ah_version != AR5K_AR5210) { - /* ...set the PHY operating mode */ - ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); - udelay(300); - - ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE); - ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO); - } - - return 0; -} - -/* - * Get the rate table for a specific operation mode - */ -const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, - unsigned int mode) -{ - ATH5K_TRACE(ah->ah_sc); - - if (!test_bit(mode, ah->ah_capabilities.cap_mode)) - return NULL; - - /* Get rate tables */ - switch (mode) { - case AR5K_MODE_11A: - return &ath5k_rt_11a; - case AR5K_MODE_11A_TURBO: - return &ath5k_rt_turbo; - case AR5K_MODE_11B: - return &ath5k_rt_11b; - case AR5K_MODE_11G: - return &ath5k_rt_11g; - case AR5K_MODE_11G_TURBO: - return &ath5k_rt_xr; - } - - return NULL; -} - -/* - * Free the ath5k_hw struct - */ -void ath5k_hw_detach(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - - __set_bit(ATH_STAT_INVALID, ah->ah_sc->status); - - if (ah->ah_rf_banks != NULL) - kfree(ah->ah_rf_banks); - - /* assume interrupts are down */ - kfree(ah); -} - -/****************************\ - Reset function and helpers -\****************************/ - -/** - * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 - * - * @ah: the &struct ath5k_hw - * @channel: the currently set channel upon reset - * - * Write the OFDM timings for the AR5212 upon reset. This is a helper for - * ath5k_hw_reset(). This seems to tune the PLL a specified frequency - * depending on the bandwidth of the channel. - * - */ -static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - /* Get exponent and mantissa and set it */ - u32 coef_scaled, coef_exp, coef_man, - ds_coef_exp, ds_coef_man, clock; - - if (!(ah->ah_version == AR5K_AR5212) || - !(channel->hw_value & CHANNEL_OFDM)) - BUG(); - - /* Seems there are two PLLs, one for baseband sampling and one - * for tuning. Tuning basebands are 40 MHz or 80MHz when in - * turbo. */ - clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40; - coef_scaled = ((5 * (clock << 24)) / 2) / - channel->center_freq; - - for (coef_exp = 31; coef_exp > 0; coef_exp--) - if ((coef_scaled >> coef_exp) & 0x1) - break; - - if (!coef_exp) - return -EINVAL; - - coef_exp = 14 - (coef_exp - 24); - coef_man = coef_scaled + - (1 << (24 - coef_exp - 1)); - ds_coef_man = coef_man >> (24 - coef_exp); - ds_coef_exp = coef_exp - 16; - - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, - AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man); - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, - AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp); - - return 0; -} - -/** - * ath5k_hw_write_rate_duration - set rate duration during hw resets - * - * @ah: the &struct ath5k_hw - * @mode: one of enum ath5k_driver_mode - * - * Write the rate duration table for the current mode upon hw reset. This - * is a helper for ath5k_hw_reset(). It seems all this is doing is setting - * an ACK timeout for the hardware for the current mode for each rate. The - * rates which are capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, - * and 11Mbps) have another register for the short preamble ACK timeout - * calculation. - * - */ -static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, - unsigned int mode) -{ - struct ath5k_softc *sc = ah->ah_sc; - const struct ath5k_rate_table *rt; - struct ieee80211_rate srate = {}; - unsigned int i; - - /* Get rate table for the current operating mode */ - rt = ath5k_hw_get_rate_table(ah, mode); - - /* Write rate duration table */ - for (i = 0; i < rt->rate_count; i++) { - const struct ath5k_rate *rate, *control_rate; - - u32 reg; - u16 tx_time; - - rate = &rt->rates[i]; - control_rate = &rt->rates[rate->control_rate]; - - /* Set ACK timeout */ - reg = AR5K_RATE_DUR(rate->rate_code); - - srate.bitrate = control_rate->rate_kbps/100; - - /* An ACK frame consists of 10 bytes. If you add the FCS, - * which ieee80211_generic_frame_duration() adds, - * its 14 bytes. Note we use the control rate and not the - * actual rate for this rate. See mac80211 tx.c - * ieee80211_duration() for a brief description of - * what rate we should choose to TX ACKs. */ - tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, - sc->vif, 10, &srate)); - - ath5k_hw_reg_write(ah, tx_time, reg); - - if (!HAS_SHPREAMBLE(i)) - continue; - - /* - * We're not distinguishing short preamble here, - * This is true, all we'll get is a longer value here - * which is not necessarilly bad. We could use - * export ieee80211_frame_duration() but that needs to be - * fixed first to be properly used by mac802111 drivers: - * - * - remove erp stuff and let the routine figure ofdm - * erp rates - * - remove passing argument ieee80211_local as - * drivers don't have access to it - * - move drivers using ieee80211_generic_frame_duration() - * to this - */ - ath5k_hw_reg_write(ah, tx_time, - reg + (AR5K_SET_SHORT_PREAMBLE << 2)); - } -} - -/* - * Main reset function - */ -int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, - struct ieee80211_channel *channel, bool change_channel) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct pci_dev *pdev = ah->ah_sc->pdev; - u32 data, s_seq, s_ant, s_led[3], dma_size; - unsigned int i, mode, freq, ee_mode, ant[2]; - int ret; - - ATH5K_TRACE(ah->ah_sc); - - s_seq = 0; - s_ant = 0; - ee_mode = 0; - freq = 0; - mode = 0; - - /* - * Save some registers before a reset - */ - /*DCU/Antenna selection not available on 5210*/ - if (ah->ah_version != AR5K_AR5210) { - if (change_channel) { - /* Seq number for queue 0 -do this for all queues ? */ - s_seq = ath5k_hw_reg_read(ah, - AR5K_QUEUE_DFS_SEQNUM(0)); - /*Default antenna*/ - s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); - } - } - - /*GPIOs*/ - s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE; - s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); - s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); - - if (change_channel && ah->ah_rf_banks != NULL) - ath5k_hw_get_rf_gain(ah); - - - /*Wakeup the device*/ - ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); - if (ret) - return ret; - - /* - * Initialize operating mode - */ - ah->ah_op_mode = op_mode; - - /* - * 5111/5112 Settings - * 5210 only comes with RF5110 - */ - if (ah->ah_version != AR5K_AR5210) { - if (ah->ah_radio != AR5K_RF5111 && - ah->ah_radio != AR5K_RF5112 && - ah->ah_radio != AR5K_RF5413 && - ah->ah_radio != AR5K_RF2413 && - ah->ah_radio != AR5K_RF2425) { - ATH5K_ERR(ah->ah_sc, - "invalid phy radio: %u\n", ah->ah_radio); - return -EINVAL; - } - - switch (channel->hw_value & CHANNEL_MODES) { - case CHANNEL_A: - mode = AR5K_MODE_11A; - freq = AR5K_INI_RFGAIN_5GHZ; - ee_mode = AR5K_EEPROM_MODE_11A; - break; - case CHANNEL_G: - mode = AR5K_MODE_11G; - freq = AR5K_INI_RFGAIN_2GHZ; - ee_mode = AR5K_EEPROM_MODE_11G; - break; - case CHANNEL_B: - mode = AR5K_MODE_11B; - freq = AR5K_INI_RFGAIN_2GHZ; - ee_mode = AR5K_EEPROM_MODE_11B; - break; - case CHANNEL_T: - mode = AR5K_MODE_11A_TURBO; - freq = AR5K_INI_RFGAIN_5GHZ; - ee_mode = AR5K_EEPROM_MODE_11A; - break; - /*Is this ok on 5211 too ?*/ - case CHANNEL_TG: - mode = AR5K_MODE_11G_TURBO; - freq = AR5K_INI_RFGAIN_2GHZ; - ee_mode = AR5K_EEPROM_MODE_11G; - break; - case CHANNEL_XR: - if (ah->ah_version == AR5K_AR5211) { - ATH5K_ERR(ah->ah_sc, - "XR mode not available on 5211"); - return -EINVAL; - } - mode = AR5K_MODE_XR; - freq = AR5K_INI_RFGAIN_5GHZ; - ee_mode = AR5K_EEPROM_MODE_11A; - break; - default: - ATH5K_ERR(ah->ah_sc, - "invalid channel: %d\n", channel->center_freq); - return -EINVAL; - } - - /* PHY access enable */ - ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); - - } - - ret = ath5k_hw_write_initvals(ah, mode, change_channel); - if (ret) - return ret; - - /* - * 5211/5212 Specific - */ - if (ah->ah_version != AR5K_AR5210) { - /* - * Write initial RF gain settings - * This should work for both 5111/5112 - */ - ret = ath5k_hw_rfgain(ah, freq); - if (ret) - return ret; - - mdelay(1); - - /* - * Write some more initial register settings - */ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0x0002a002, 0x982c); - - if (channel->hw_value == CHANNEL_G) - if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413) - ath5k_hw_reg_write(ah, 0x00f80d80, - 0x994c); - else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424) - ath5k_hw_reg_write(ah, 0x00380140, - 0x994c); - else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425) - ath5k_hw_reg_write(ah, 0x00fc0ec0, - 0x994c); - else /* 2425 */ - ath5k_hw_reg_write(ah, 0x00fc0fc0, - 0x994c); - else - ath5k_hw_reg_write(ah, 0x00000000, 0x994c); - - /* Some bits are disabled here, we know nothing about - * register 0xa228 yet, most of the times this ends up - * with a value 0x9b5 -haven't seen any dump with - * a different value- */ - /* Got this from decompiling binary HAL */ - data = ath5k_hw_reg_read(ah, 0xa228); - data &= 0xfffffdff; - ath5k_hw_reg_write(ah, data, 0xa228); - - data = ath5k_hw_reg_read(ah, 0xa228); - data &= 0xfffe03ff; - ath5k_hw_reg_write(ah, data, 0xa228); - data = 0; - - /* Just write 0x9b5 ? */ - /* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */ - ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK); - ath5k_hw_reg_write(ah, 0x00000000, 0xa254); - ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL); - } - - /* Fix for first revision of the RF5112 RF chipset */ - if (ah->ah_radio >= AR5K_RF5112 && - ah->ah_radio_5ghz_revision < - AR5K_SREV_RAD_5112A) { - ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, - AR5K_PHY_CCKTXCTL); - if (channel->hw_value & CHANNEL_5GHZ) - data = 0xffb81020; - else - data = 0xffb80d20; - ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL); - data = 0; - } - - /* - * Set TX power (FIXME) - */ - ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER); - if (ret) - return ret; - - /* Write rate duration table only on AR5212 and if - * virtual interface has already been brought up - * XXX: rethink this after new mode changes to - * mac80211 are integrated */ - if (ah->ah_version == AR5K_AR5212 && - ah->ah_sc->vif != NULL) - ath5k_hw_write_rate_duration(ah, mode); - - /* - * Write RF registers - */ - ret = ath5k_hw_rfregs(ah, channel, mode); - if (ret) - return ret; - - /* - * Configure additional registers - */ - - /* Write OFDM timings on 5212*/ - if (ah->ah_version == AR5K_AR5212 && - channel->hw_value & CHANNEL_OFDM) { - ret = ath5k_hw_write_ofdm_timings(ah, channel); - if (ret) - return ret; - } - - /*Enable/disable 802.11b mode on 5111 - (enable 2111 frequency converter + CCK)*/ - if (ah->ah_radio == AR5K_RF5111) { - if (mode == AR5K_MODE_11B) - AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_B_MODE); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_B_MODE); - } - - /* - * Set channel and calibrate the PHY - */ - ret = ath5k_hw_channel(ah, channel); - if (ret) - return ret; - - /* Set antenna mode */ - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL, - ah->ah_antenna[ee_mode][0], 0xfffffc06); - - /* - * In case a fixed antenna was set as default - * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE - * registers. - */ - if (s_ant != 0){ - if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */ - ant[0] = ant[1] = AR5K_ANT_FIXED_A; - else /* 2 - Aux */ - ant[0] = ant[1] = AR5K_ANT_FIXED_B; - } else { - ant[0] = AR5K_ANT_FIXED_A; - ant[1] = AR5K_ANT_FIXED_B; - } - - ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]], - AR5K_PHY_ANT_SWITCH_TABLE_0); - ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]], - AR5K_PHY_ANT_SWITCH_TABLE_1); - - /* Commit values from EEPROM */ - if (ah->ah_radio == AR5K_RF5111) - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, - AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip); - - ath5k_hw_reg_write(ah, - AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), - AR5K_PHY_NFTHRES); - - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING, - (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, - 0xffffc07f); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN, - (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, - 0xfffc0fff); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, - (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | - ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00), - 0xffff0000); - - ath5k_hw_reg_write(ah, - (ee->ee_tx_end2xpa_disable[ee_mode] << 24) | - (ee->ee_tx_end2xpa_disable[ee_mode] << 16) | - (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) | - (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4); - - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3, - ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF, - (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01); - - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_CORR_ENABLE | - (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) | - ee->ee_q_cal[ee_mode]); - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ, - AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX, - ee->ee_margin_tx_rx[ee_mode]); - - } else { - mdelay(1); - /* Disable phy and wait */ - ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); - mdelay(1); - } - - /* - * Restore saved values - */ - /*DCU/Antenna selection not available on 5210*/ - if (ah->ah_version != AR5K_AR5210) { - ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0)); - ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); - } - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]); - ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR); - ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); - - /* - * Misc - */ - /* XXX: add ah->aid once mac80211 gives this to us */ - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); - - ath5k_hw_set_opmode(ah); - /*PISR/SISR Not available on 5210*/ - if (ah->ah_version != AR5K_AR5210) { - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); - /* If we later allow tuning for this, store into sc structure */ - data = AR5K_TUNE_RSSI_THRES | - AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S; - ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR); - } - - /* - * Set Rx/Tx DMA Configuration - * - * Set maximum DMA size (512) except for PCI-E cards since - * it causes rx overruns and tx errors (tested on 5424 but since - * rx overruns also occur on 5416/5418 with madwifi we set 128 - * for all PCI-E cards to be safe). - * - * In dumps this is 128 for allchips. - * - * XXX: need to check 5210 for this - * TODO: Check out tx triger level, it's always 64 on dumps but I - * guess we can tweak it and see how it goes ;-) - */ - dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B; - if (ah->ah_version != AR5K_AR5210) { - AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_SDMAMR, dma_size); - AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, - AR5K_RXCFG_SDMAMW, dma_size); - } - - /* - * Enable the PHY and wait until completion - */ - ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - - /* - * On 5211+ read activation -> rx delay - * and use it. - */ - if (ah->ah_version != AR5K_AR5210) { - data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & - AR5K_PHY_RX_DELAY_M; - data = (channel->hw_value & CHANNEL_CCK) ? - ((data << 2) / 22) : (data / 10); - - udelay(100 + (2 * data)); - data = 0; - } else { - mdelay(1); - } - - /* - * Perform ADC test (?) - */ - data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); - ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); - for (i = 0; i <= 20; i++) { - if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) - break; - udelay(200); - } - ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1); - data = 0; - - /* - * Start automatic gain calibration - * - * During AGC calibration RX path is re-routed to - * a signal detector so we don't receive anything. - * - * This method is used to calibrate some static offsets - * used together with on-the fly I/Q calibration (the - * one performed via ath5k_hw_phy_calibrate), that doesn't - * interrupt rx path. - * - * If we are in a noisy environment AGC calibration may time - * out. - */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_CAL); - - /* At the same time start I/Q calibration for QAM constellation - * -no need for CCK- */ - ah->ah_calibration = false; - if (!(mode == AR5K_MODE_11B)) { - ah->ah_calibration = true; - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_RUN); - } - - /* Wait for gain calibration to finish (we check for I/Q calibration - * during ath5k_phy_calibrate) */ - if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_CAL, 0, false)) { - ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n", - channel->center_freq); - return -EAGAIN; - } - - /* - * Start noise floor calibration - * - * If we run NF calibration before AGC, it always times out. - * Binary HAL starts NF and AGC calibration at the same time - * and only waits for AGC to finish. I believe that's wrong because - * during NF calibration, rx path is also routed to a detector, so if - * it doesn't finish we won't have RX. - * - * XXX: Find an interval that's OK for all cards... - */ - ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - if (ret) - return ret; - - /* - * Reset queues and start beacon timers at the end of the reset routine - */ - for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) { - /*No QCU on 5210*/ - if (ah->ah_version != AR5K_AR5210) - AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i); - - ret = ath5k_hw_reset_tx_queue(ah, i); - if (ret) { - ATH5K_ERR(ah->ah_sc, - "failed to reset TX queue #%d\n", i); - return ret; - } - } - - /* Pre-enable interrupts on 5211/5212*/ - if (ah->ah_version != AR5K_AR5210) - ath5k_hw_set_intr(ah, AR5K_INT_RX | AR5K_INT_TX | - AR5K_INT_FATAL); - - /* - * Set RF kill flags if supported by the device (read from the EEPROM) - * Disable gpio_intr for now since it results system hang. - * TODO: Handle this in ath5k_intr - */ -#if 0 - if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { - ath5k_hw_set_gpio_input(ah, 0); - ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); - if (ah->ah_gpio[0] == 0) - ath5k_hw_set_gpio_intr(ah, 0, 1); - else - ath5k_hw_set_gpio_intr(ah, 0, 0); - } -#endif - - /* - * Set the 32MHz reference clock on 5212 phy clock sleep register - * - * TODO: Find out how to switch to external 32Khz clock to save power - */ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); - ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT); - ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); - ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); - ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); - ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING); - - data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ; - data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ? - 0x00000f80 : 0x00001380 ; - ath5k_hw_reg_write(ah, data, AR5K_USEC_5211); - data = 0; - } - - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0x000100aa, 0x8118); - ath5k_hw_reg_write(ah, 0x00003210, 0x811c); - ath5k_hw_reg_write(ah, 0x00000052, 0x8108); - if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413) - ath5k_hw_reg_write(ah, 0x00000004, 0x8120); - } - - /* - * Disable beacons and reset the register - */ - AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE | - AR5K_BEACON_RESET_TSF); - - return 0; -} - -/* - * Reset chipset - */ -static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) -{ - int ret; - u32 mask = val ? val : ~0U; - - ATH5K_TRACE(ah->ah_sc); - - /* Read-and-clear RX Descriptor Pointer*/ - ath5k_hw_reg_read(ah, AR5K_RXDP); - - /* - * Reset the device and wait until success - */ - ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); - - /* Wait at least 128 PCI clocks */ - udelay(15); - - if (ah->ah_version == AR5K_AR5210) { - val &= AR5K_RESET_CTL_CHIP; - mask &= AR5K_RESET_CTL_CHIP; - } else { - val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; - mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; - } - - ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false); - - /* - * Reset configuration register (for hw byte-swap). Note that this - * is only set for big endian. We do the necessary magic in - * AR5K_INIT_CFG. - */ - if ((val & AR5K_RESET_CTL_PCU) == 0) - ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG); - - return ret; -} - -/* - * Power management functions - */ - -/* - * Sleep control - */ -int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, - bool set_chip, u16 sleep_duration) -{ - unsigned int i; - u32 staid, data; - - ATH5K_TRACE(ah->ah_sc); - staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); - - switch (mode) { - case AR5K_PM_AUTO: - staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; - /* fallthrough */ - case AR5K_PM_NETWORK_SLEEP: - if (set_chip) - ath5k_hw_reg_write(ah, - AR5K_SLEEP_CTL_SLE_ALLOW | - sleep_duration, - AR5K_SLEEP_CTL); - - staid |= AR5K_STA_ID1_PWR_SV; - break; - - case AR5K_PM_FULL_SLEEP: - if (set_chip) - ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP, - AR5K_SLEEP_CTL); - - staid |= AR5K_STA_ID1_PWR_SV; - break; - - case AR5K_PM_AWAKE: - - staid &= ~AR5K_STA_ID1_PWR_SV; - - if (!set_chip) - goto commit; - - /* Preserve sleep duration */ - data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); - if( data & 0xffc00000 ){ - data = 0; - } else { - data = data & 0xfffcffff; - } - - ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); - udelay(15); - - for (i = 50; i > 0; i--) { - /* Check if the chip did wake up */ - if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & - AR5K_PCICFG_SPWR_DN) == 0) - break; - - /* Wait a bit and retry */ - udelay(200); - ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); - } - - /* Fail if the chip didn't wake up */ - if (i <= 0) - return -EIO; - - break; - - default: - return -EINVAL; - } - -commit: - ah->ah_power_mode = mode; - ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1); - - return 0; -} - -/***********************\ - DMA Related Functions -\***********************/ - -/* - * Receive functions - */ - -/* - * Start DMA receive - */ -void ath5k_hw_start_rx(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); - ath5k_hw_reg_read(ah, AR5K_CR); -} - -/* - * Stop DMA receive - */ -int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) -{ - unsigned int i; - - ATH5K_TRACE(ah->ah_sc); - ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR); - - /* - * It may take some time to disable the DMA receive unit - */ - for (i = 2000; i > 0 && - (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; - i--) - udelay(10); - - return i ? 0 : -EBUSY; -} - -/* - * Get the address of the RX Descriptor - */ -u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah) -{ - return ath5k_hw_reg_read(ah, AR5K_RXDP); -} - -/* - * Set the address of the RX Descriptor - */ -void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr) -{ - ATH5K_TRACE(ah->ah_sc); - - /*TODO:Shouldn't we check if RX is enabled first ?*/ - ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); -} - -/* - * Transmit functions - */ - -/* - * Start DMA transmit for a specific queue - * (see also QCU/DCU functions) - */ -int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue) -{ - u32 tx_queue; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* Return if queue is declared inactive */ - if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return -EIO; - - if (ah->ah_version == AR5K_AR5210) { - tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); - - /* - * Set the queue by type on 5210 - */ - switch (ah->ah_txq[queue].tqi_type) { - case AR5K_TX_QUEUE_DATA: - tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0; - break; - case AR5K_TX_QUEUE_BEACON: - tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; - ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, - AR5K_BSR); - break; - case AR5K_TX_QUEUE_CAB: - tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; - ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V | - AR5K_BCR_BDMAE, AR5K_BSR); - break; - default: - return -EINVAL; - } - /* Start queue */ - ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); - ath5k_hw_reg_read(ah, AR5K_CR); - } else { - /* Return if queue is disabled */ - if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue)) - return -EIO; - - /* Start queue */ - AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue); - } - - return 0; -} - -/* - * Stop DMA transmit for a specific queue - * (see also QCU/DCU functions) - */ -int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) -{ - unsigned int i = 100; - u32 tx_queue, pending; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* Return if queue is declared inactive */ - if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return -EIO; - - if (ah->ah_version == AR5K_AR5210) { - tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); - - /* - * Set by queue type - */ - switch (ah->ah_txq[queue].tqi_type) { - case AR5K_TX_QUEUE_DATA: - tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0; - break; - case AR5K_TX_QUEUE_BEACON: - case AR5K_TX_QUEUE_CAB: - /* XXX Fix me... */ - tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1; - ath5k_hw_reg_write(ah, 0, AR5K_BSR); - break; - default: - return -EINVAL; - } - - /* Stop queue */ - ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); - ath5k_hw_reg_read(ah, AR5K_CR); - } else { - /* - * Schedule TX disable and wait until queue is empty - */ - AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue); - - /*Check for pending frames*/ - do { - pending = ath5k_hw_reg_read(ah, - AR5K_QUEUE_STATUS(queue)) & - AR5K_QCU_STS_FRMPENDCNT; - udelay(100); - } while (--i && pending); - - /* Clear register */ - ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); - if (pending) - return -EBUSY; - } - - /* TODO: Check for success else return error */ - return 0; -} - -/* - * Get the address of the TX Descriptor for a specific queue - * (see also QCU/DCU functions) - */ -u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue) -{ - u16 tx_reg; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* - * Get the transmit queue descriptor pointer from the selected queue - */ - /*5210 doesn't have QCU*/ - if (ah->ah_version == AR5K_AR5210) { - switch (ah->ah_txq[queue].tqi_type) { - case AR5K_TX_QUEUE_DATA: - tx_reg = AR5K_NOQCU_TXDP0; - break; - case AR5K_TX_QUEUE_BEACON: - case AR5K_TX_QUEUE_CAB: - tx_reg = AR5K_NOQCU_TXDP1; - break; - default: - return 0xffffffff; - } - } else { - tx_reg = AR5K_QUEUE_TXDP(queue); - } - - return ath5k_hw_reg_read(ah, tx_reg); -} - -/* - * Set the address of the TX Descriptor for a specific queue - * (see also QCU/DCU functions) - */ -int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) -{ - u16 tx_reg; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* - * Set the transmit queue descriptor pointer register by type - * on 5210 - */ - if (ah->ah_version == AR5K_AR5210) { - switch (ah->ah_txq[queue].tqi_type) { - case AR5K_TX_QUEUE_DATA: - tx_reg = AR5K_NOQCU_TXDP0; - break; - case AR5K_TX_QUEUE_BEACON: - case AR5K_TX_QUEUE_CAB: - tx_reg = AR5K_NOQCU_TXDP1; - break; - default: - return -EINVAL; - } - } else { - /* - * Set the transmit queue descriptor pointer for - * the selected queue on QCU for 5211+ - * (this won't work if the queue is still active) - */ - if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) - return -EIO; - - tx_reg = AR5K_QUEUE_TXDP(queue); - } - - /* Set descriptor pointer */ - ath5k_hw_reg_write(ah, phys_addr, tx_reg); - - return 0; -} - -/* - * Update tx trigger level - */ -int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) -{ - u32 trigger_level, imr; - int ret = -EIO; - - ATH5K_TRACE(ah->ah_sc); - - /* - * Disable interrupts by setting the mask - */ - imr = ath5k_hw_set_intr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL); - - /*TODO: Boundary check on trigger_level*/ - trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG), - AR5K_TXCFG_TXFULL); - - if (!increase) { - if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) - goto done; - } else - trigger_level += - ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2); - - /* - * Update trigger level on success - */ - if (ah->ah_version == AR5K_AR5210) - ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL); - else - AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_TXFULL, trigger_level); - - ret = 0; - -done: - /* - * Restore interrupt mask - */ - ath5k_hw_set_intr(ah, imr); - - return ret; -} - -/* - * Interrupt handling - */ - -/* - * Check if we have pending interrupts - */ -bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_reg_read(ah, AR5K_INTPEND); -} - -/* - * Get interrupt mask (ISR) - */ -int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) -{ - u32 data; - - ATH5K_TRACE(ah->ah_sc); - - /* - * Read interrupt status from the Interrupt Status register - * on 5210 - */ - if (ah->ah_version == AR5K_AR5210) { - data = ath5k_hw_reg_read(ah, AR5K_ISR); - if (unlikely(data == AR5K_INT_NOCARD)) { - *interrupt_mask = data; - return -ENODEV; - } - } else { - /* - * Read interrupt status from the Read-And-Clear shadow register - * Note: PISR/SISR Not available on 5210 - */ - data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); - } - - /* - * Get abstract interrupt mask (driver-compatible) - */ - *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; - - if (unlikely(data == AR5K_INT_NOCARD)) - return -ENODEV; - - if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR)) - *interrupt_mask |= AR5K_INT_RX; - - if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR - | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL)) - *interrupt_mask |= AR5K_INT_TX; - - if (ah->ah_version != AR5K_AR5210) { - /*HIU = Host Interface Unit (PCI etc)*/ - if (unlikely(data & (AR5K_ISR_HIUERR))) - *interrupt_mask |= AR5K_INT_FATAL; - - /*Beacon Not Ready*/ - if (unlikely(data & (AR5K_ISR_BNR))) - *interrupt_mask |= AR5K_INT_BNR; - } - - /* - * XXX: BMISS interrupts may occur after association. - * I found this on 5210 code but it needs testing. If this is - * true we should disable them before assoc and re-enable them - * after a successfull assoc + some jiffies. - */ -#if 0 - interrupt_mask &= ~AR5K_INT_BMISS; -#endif - - /* - * In case we didn't handle anything, - * print the register value. - */ - if (unlikely(*interrupt_mask == 0 && net_ratelimit())) - ATH5K_PRINTF("0x%08x\n", data); - - return 0; -} - -/* - * Set interrupt mask - */ -enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask) -{ - enum ath5k_int old_mask, int_mask; - - /* - * Disable card interrupts to prevent any race conditions - * (they will be re-enabled afterwards). - */ - ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); - - old_mask = ah->ah_imr; - - /* - * Add additional, chipset-dependent interrupt mask flags - * and write them to the IMR (interrupt mask register). - */ - int_mask = new_mask & AR5K_INT_COMMON; - - if (new_mask & AR5K_INT_RX) - int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN | - AR5K_IMR_RXDESC; - - if (new_mask & AR5K_INT_TX) - int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC | - AR5K_IMR_TXURN; - - if (ah->ah_version != AR5K_AR5210) { - if (new_mask & AR5K_INT_FATAL) { - int_mask |= AR5K_IMR_HIUERR; - AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT | - AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); - } - } - - ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); - - /* Store new interrupt mask */ - ah->ah_imr = new_mask; - - /* ..re-enable interrupts */ - ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); - - return old_mask; -} - - -/*************************\ - EEPROM access functions -\*************************/ - -/* - * Read from eeprom - */ -static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) -{ - u32 status, timeout; - - ATH5K_TRACE(ah->ah_sc); - /* - * Initialize EEPROM access - */ - if (ah->ah_version == AR5K_AR5210) { - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); - (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset)); - } else { - ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); - AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, - AR5K_EEPROM_CMD_READ); - } - - for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { - status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); - if (status & AR5K_EEPROM_STAT_RDDONE) { - if (status & AR5K_EEPROM_STAT_RDERR) - return -EIO; - *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & - 0xffff); - return 0; - } - udelay(15); - } - - return -ETIMEDOUT; -} - -/* - * Write to eeprom - currently disabled, use at your own risk - */ -#if 0 -static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data) -{ - - u32 status, timeout; - - ATH5K_TRACE(ah->ah_sc); - - /* - * Initialize eeprom access - */ - - if (ah->ah_version == AR5K_AR5210) { - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); - } else { - AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, - AR5K_EEPROM_CMD_RESET); - } - - /* - * Write data to data register - */ - - if (ah->ah_version == AR5K_AR5210) { - ath5k_hw_reg_write(ah, data, AR5K_EEPROM_BASE + (4 * offset)); - } else { - ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); - ath5k_hw_reg_write(ah, data, AR5K_EEPROM_DATA); - AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, - AR5K_EEPROM_CMD_WRITE); - } - - /* - * Check status - */ - - for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { - status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); - if (status & AR5K_EEPROM_STAT_WRDONE) { - if (status & AR5K_EEPROM_STAT_WRERR) - return EIO; - return 0; - } - udelay(15); - } - - ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!"); - return -EIO; -} -#endif - -/* - * Translate binary channel representation in EEPROM to frequency - */ -static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, unsigned int mode) -{ - u16 val; - - if (bin == AR5K_EEPROM_CHANNEL_DIS) - return bin; - - if (mode == AR5K_EEPROM_MODE_11A) { - if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) - val = (5 * bin) + 4800; - else - val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 : - (bin * 10) + 5100; - } else { - if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) - val = bin + 2300; - else - val = bin + 2400; - } - - return val; -} - -/* - * Read antenna infos from eeprom - */ -static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, - unsigned int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 o = *offset; - u16 val; - int ret, i = 0; - - AR5K_EEPROM_READ(o++, val); - ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; - ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; - ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; - - AR5K_EEPROM_READ(o++, val); - ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; - ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; - ee->ee_ant_control[mode][i++] = val & 0x3f; - - AR5K_EEPROM_READ(o++, val); - ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f; - ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f; - ee->ee_ant_control[mode][i] = (val << 2) & 0x3f; - - AR5K_EEPROM_READ(o++, val); - ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3; - ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f; - ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f; - ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; - - AR5K_EEPROM_READ(o++, val); - ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; - ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; - ee->ee_ant_control[mode][i++] = val & 0x3f; - - /* Get antenna modes */ - ah->ah_antenna[mode][0] = - (ee->ee_ant_control[mode][0] << 4) | 0x1; - ah->ah_antenna[mode][AR5K_ANT_FIXED_A] = - ee->ee_ant_control[mode][1] | - (ee->ee_ant_control[mode][2] << 6) | - (ee->ee_ant_control[mode][3] << 12) | - (ee->ee_ant_control[mode][4] << 18) | - (ee->ee_ant_control[mode][5] << 24); - ah->ah_antenna[mode][AR5K_ANT_FIXED_B] = - ee->ee_ant_control[mode][6] | - (ee->ee_ant_control[mode][7] << 6) | - (ee->ee_ant_control[mode][8] << 12) | - (ee->ee_ant_control[mode][9] << 18) | - (ee->ee_ant_control[mode][10] << 24); - - /* return new offset */ - *offset = o; - - return 0; -} - -/* - * Read supported modes from eeprom - */ -static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, - unsigned int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 o = *offset; - u16 val; - int ret; - - AR5K_EEPROM_READ(o++, val); - ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; - ee->ee_thr_62[mode] = val & 0xff; - - if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) - ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28; - - AR5K_EEPROM_READ(o++, val); - ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff; - ee->ee_tx_frm2xpa_enable[mode] = val & 0xff; - - AR5K_EEPROM_READ(o++, val); - ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff; - - if ((val & 0xff) & 0x80) - ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1); - else - ee->ee_noise_floor_thr[mode] = val & 0xff; - - if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) - ee->ee_noise_floor_thr[mode] = - mode == AR5K_EEPROM_MODE_11A ? -54 : -1; - - AR5K_EEPROM_READ(o++, val); - ee->ee_xlna_gain[mode] = (val >> 5) & 0xff; - ee->ee_x_gain[mode] = (val >> 1) & 0xf; - ee->ee_xpd[mode] = val & 0x1; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) - ee->ee_fixed_bias[mode] = (val >> 13) & 0x1; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) { - AR5K_EEPROM_READ(o++, val); - ee->ee_false_detect[mode] = (val >> 6) & 0x7f; - - if (mode == AR5K_EEPROM_MODE_11A) - ee->ee_xr_power[mode] = val & 0x3f; - else { - ee->ee_ob[mode][0] = val & 0x7; - ee->ee_db[mode][0] = (val >> 3) & 0x7; - } - } - - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) { - ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN; - ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA; - } else { - ee->ee_i_gain[mode] = (val >> 13) & 0x7; - - AR5K_EEPROM_READ(o++, val); - ee->ee_i_gain[mode] |= (val << 3) & 0x38; - - if (mode == AR5K_EEPROM_MODE_11G) - ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; - } - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && - mode == AR5K_EEPROM_MODE_11A) { - ee->ee_i_cal[mode] = (val >> 8) & 0x3f; - ee->ee_q_cal[mode] = (val >> 3) & 0x1f; - } - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 && - mode == AR5K_EEPROM_MODE_11G) - ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; - - /* return new offset */ - *offset = o; - - return 0; -} - -/* - * Initialize eeprom & capabilities structs - */ -static int ath5k_eeprom_init(struct ath5k_hw *ah) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - unsigned int mode, i; - int ret; - u32 offset; - u16 val; - - /* Initial TX thermal adjustment values */ - ee->ee_tx_clip = 4; - ee->ee_pwd_84 = ee->ee_pwd_90 = 1; - ee->ee_gain_select = 1; - - /* - * Read values from EEPROM and store them in the capability structure - */ - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); - - /* Return if we have an old EEPROM */ - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) - return 0; - -#ifdef notyet - /* - * Validate the checksum of the EEPROM date. There are some - * devices with invalid EEPROMs. - */ - for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { - AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); - cksum ^= val; - } - if (cksum != AR5K_EEPROM_INFO_CKSUM) { - ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); - return -EIO; - } -#endif - - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), - ee_ant_gain); - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); - } - - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { - AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); - ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; - ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; - - AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); - ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; - ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; - } - - /* - * Get conformance test limit values - */ - offset = AR5K_EEPROM_CTL(ah->ah_ee_version); - ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version); - - for (i = 0; i < ee->ee_ctls; i++) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_ctl[i] = (val >> 8) & 0xff; - ee->ee_ctl[i + 1] = val & 0xff; - } - - /* - * Get values for 802.11a (5GHz) - */ - mode = AR5K_EEPROM_MODE_11A; - - ee->ee_turbo_max_power[mode] = - AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); - - offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); - - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][3] = (val >> 5) & 0x7; - ee->ee_db[mode][3] = (val >> 2) & 0x7; - ee->ee_ob[mode][2] = (val << 1) & 0x7; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_ob[mode][2] |= (val >> 15) & 0x1; - ee->ee_db[mode][2] = (val >> 12) & 0x7; - ee->ee_ob[mode][1] = (val >> 9) & 0x7; - ee->ee_db[mode][1] = (val >> 6) & 0x7; - ee->ee_ob[mode][0] = (val >> 3) & 0x7; - ee->ee_db[mode][0] = val & 0x7; - - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_margin_tx_rx[mode] = val & 0x3f; - } - - /* - * Get values for 802.11b (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11B; - offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); - - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][1] = (val >> 4) & 0x7; - ee->ee_db[mode][1] = val & 0x7; - - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][0] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - ee->ee_cal_pier[mode][1] = - ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); - - AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - } - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; - - /* - * Get values for 802.11g (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11G; - offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); - - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][1] = (val >> 4) & 0x7; - ee->ee_db[mode][1] = val & 0x7; - - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][0] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - ee->ee_cal_pier[mode][1] = - ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); - - AR5K_EEPROM_READ(offset++, val); - ee->ee_turbo_max_power[mode] = val & 0x7f; - ee->ee_xr_power[mode] = (val >> 7) & 0x3f; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_i_cal[mode] = (val >> 8) & 0x3f; - ee->ee_q_cal[mode] = (val >> 3) & 0x1f; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_cck_ofdm_gain_delta = val & 0xff; - } - } - - /* - * Read 5GHz EEPROM channels - */ - - return 0; -} - -/* - * Read the MAC address from eeprom - */ -static int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) -{ - u8 mac_d[ETH_ALEN]; - u32 total, offset; - u16 data; - int octet, ret; - - memset(mac, 0, ETH_ALEN); - memset(mac_d, 0, ETH_ALEN); - - ret = ath5k_hw_eeprom_read(ah, 0x20, &data); - if (ret) - return ret; - - for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { - ret = ath5k_hw_eeprom_read(ah, offset, &data); - if (ret) - return ret; - - total += data; - mac_d[octet + 1] = data & 0xff; - mac_d[octet] = data >> 8; - octet += 2; - } - - memcpy(mac, mac_d, ETH_ALEN); - - if (!total || total == 3 * 0xffff) - return -EINVAL; - - return 0; -} - -/* - * Fill the capabilities struct - */ -static int ath5k_hw_get_capabilities(struct ath5k_hw *ah) -{ - u16 ee_header; - - ATH5K_TRACE(ah->ah_sc); - /* Capabilities stored in the EEPROM */ - ee_header = ah->ah_capabilities.cap_eeprom.ee_header; - - if (ah->ah_version == AR5K_AR5210) { - /* - * Set radio capabilities - * (The AR5110 only supports the middle 5GHz band) - */ - ah->ah_capabilities.cap_range.range_5ghz_min = 5120; - ah->ah_capabilities.cap_range.range_5ghz_max = 5430; - ah->ah_capabilities.cap_range.range_2ghz_min = 0; - ah->ah_capabilities.cap_range.range_2ghz_max = 0; - - /* Set supported modes */ - __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode); - __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode); - } else { - /* - * XXX The tranceiver supports frequencies from 4920 to 6100GHz - * XXX and from 2312 to 2732GHz. There are problems with the - * XXX current ieee80211 implementation because the IEEE - * XXX channel mapping does not support negative channel - * XXX numbers (2312MHz is channel -19). Of course, this - * XXX doesn't matter because these channels are out of range - * XXX but some regulation domains like MKK (Japan) will - * XXX support frequencies somewhere around 4.8GHz. - */ - - /* - * Set radio capabilities - */ - - if (AR5K_EEPROM_HDR_11A(ee_header)) { - ah->ah_capabilities.cap_range.range_5ghz_min = 5005; /* 4920 */ - ah->ah_capabilities.cap_range.range_5ghz_max = 6100; - - /* Set supported modes */ - __set_bit(AR5K_MODE_11A, - ah->ah_capabilities.cap_mode); - __set_bit(AR5K_MODE_11A_TURBO, - ah->ah_capabilities.cap_mode); - if (ah->ah_version == AR5K_AR5212) - __set_bit(AR5K_MODE_11G_TURBO, - ah->ah_capabilities.cap_mode); - } - - /* Enable 802.11b if a 2GHz capable radio (2111/5112) is - * connected */ - if (AR5K_EEPROM_HDR_11B(ee_header) || - AR5K_EEPROM_HDR_11G(ee_header)) { - ah->ah_capabilities.cap_range.range_2ghz_min = 2412; /* 2312 */ - ah->ah_capabilities.cap_range.range_2ghz_max = 2732; - - if (AR5K_EEPROM_HDR_11B(ee_header)) - __set_bit(AR5K_MODE_11B, - ah->ah_capabilities.cap_mode); - - if (AR5K_EEPROM_HDR_11G(ee_header)) - __set_bit(AR5K_MODE_11G, - ah->ah_capabilities.cap_mode); - } - } - - /* GPIO */ - ah->ah_gpio_npins = AR5K_NUM_GPIO; - - /* Set number of supported TX queues */ - if (ah->ah_version == AR5K_AR5210) - ah->ah_capabilities.cap_queues.q_tx_num = - AR5K_NUM_TX_QUEUES_NOQCU; - else - ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; - - return 0; -} - -/*********************************\ - Protocol Control Unit Functions -\*********************************/ - -/* - * Set Operation mode - */ -int ath5k_hw_set_opmode(struct ath5k_hw *ah) -{ - u32 pcu_reg, beacon_reg, low_id, high_id; - - pcu_reg = 0; - beacon_reg = 0; - - ATH5K_TRACE(ah->ah_sc); - - switch (ah->ah_op_mode) { - case IEEE80211_IF_TYPE_IBSS: - pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); - beacon_reg |= AR5K_BCR_ADHOC; - break; - - case IEEE80211_IF_TYPE_AP: - pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); - beacon_reg |= AR5K_BCR_AP; - break; - - case IEEE80211_IF_TYPE_STA: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_PWR_SV : 0); - case IEEE80211_IF_TYPE_MNTR: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); - break; - - default: - return -EINVAL; - } - - /* - * Set PCU registers - */ - low_id = AR5K_LOW_ID(ah->ah_sta_id); - high_id = AR5K_HIGH_ID(ah->ah_sta_id); - ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); - ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); - - /* - * Set Beacon Control Register on 5210 - */ - if (ah->ah_version == AR5K_AR5210) - ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); - - return 0; -} - -/* - * BSSID Functions - */ - -/* - * Get station id - */ -void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) -{ - ATH5K_TRACE(ah->ah_sc); - memcpy(mac, ah->ah_sta_id, ETH_ALEN); -} - -/* - * Set station id - */ -int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) -{ - u32 low_id, high_id; - - ATH5K_TRACE(ah->ah_sc); - /* Set new station ID */ - memcpy(ah->ah_sta_id, mac, ETH_ALEN); - - low_id = AR5K_LOW_ID(mac); - high_id = AR5K_HIGH_ID(mac); - - ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); - ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1); - - return 0; -} - -/* - * Set BSSID - */ -void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) -{ - u32 low_id, high_id; - u16 tim_offset = 0; - - /* - * Set simple BSSID mask on 5212 - */ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1); - } - - /* - * Set BSSID which triggers the "SME Join" operation - */ - low_id = AR5K_LOW_ID(bssid); - high_id = AR5K_HIGH_ID(bssid); - ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); - ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << - AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); - - if (assoc_id == 0) { - ath5k_hw_disable_pspoll(ah); - return; - } - - AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, - tim_offset ? tim_offset + 4 : 0); - - ath5k_hw_enable_pspoll(ah, NULL, 0); -} -/** - * ath5k_hw_set_bssid_mask - set common bits we should listen to - * - * The bssid_mask is a utility used by AR5212 hardware to inform the hardware - * which bits of the interface's MAC address should be looked at when trying - * to decide which packets to ACK. In station mode every bit matters. In AP - * mode with a single BSS every bit matters as well. In AP mode with - * multiple BSSes not every bit matters. - * - * @ah: the &struct ath5k_hw - * @mask: the bssid_mask, a u8 array of size ETH_ALEN - * - * Note that this is a simple filter and *does* not filter out all - * relevant frames. Some non-relevant frames will get through, probability - * jocks are welcomed to compute. - * - * When handling multiple BSSes (or VAPs) you can get the BSSID mask by - * computing the set of: - * - * ~ ( MAC XOR BSSID ) - * - * When you do this you are essentially computing the common bits. Later it - * is assumed the harware will "and" (&) the BSSID mask with the MAC address - * to obtain the relevant bits which should match on the destination frame. - * - * Simple example: on your card you have have two BSSes you have created with - * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. - * There is another BSSID-03 but you are not part of it. For simplicity's sake, - * assuming only 4 bits for a mac address and for BSSIDs you can then have: - * - * \ - * MAC: 0001 | - * BSSID-01: 0100 | --> Belongs to us - * BSSID-02: 1001 | - * / - * ------------------- - * BSSID-03: 0110 | --> External - * ------------------- - * - * Our bssid_mask would then be: - * - * On loop iteration for BSSID-01: - * ~(0001 ^ 0100) -> ~(0101) - * -> 1010 - * bssid_mask = 1010 - * - * On loop iteration for BSSID-02: - * bssid_mask &= ~(0001 ^ 1001) - * bssid_mask = (1010) & ~(0001 ^ 1001) - * bssid_mask = (1010) & ~(1001) - * bssid_mask = (1010) & (0110) - * bssid_mask = 0010 - * - * A bssid_mask of 0010 means "only pay attention to the second least - * significant bit". This is because its the only bit common - * amongst the MAC and all BSSIDs we support. To findout what the real - * common bit is we can simply "&" the bssid_mask now with any BSSID we have - * or our MAC address (we assume the hardware uses the MAC address). - * - * Now, suppose there's an incoming frame for BSSID-03: - * - * IFRAME-01: 0110 - * - * An easy eye-inspeciton of this already should tell you that this frame - * will not pass our check. This is beacuse the bssid_mask tells the - * hardware to only look at the second least significant bit and the - * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB - * as 1, which does not match 0. - * - * So with IFRAME-01 we *assume* the hardware will do: - * - * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; - * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; - * --> allow = (0010) == 0000 ? 1 : 0; - * --> allow = 0 - * - * Lets now test a frame that should work: - * - * IFRAME-02: 0001 (we should allow) - * - * allow = (0001 & 1010) == 1010 - * - * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; - * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; - * --> allow = (0010) == (0010) - * --> allow = 1 - * - * Other examples: - * - * IFRAME-03: 0100 --> allowed - * IFRAME-04: 1001 --> allowed - * IFRAME-05: 1101 --> allowed but its not for us!!! - * - */ -int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) -{ - u32 low_id, high_id; - ATH5K_TRACE(ah->ah_sc); - - if (ah->ah_version == AR5K_AR5212) { - low_id = AR5K_LOW_ID(mask); - high_id = AR5K_HIGH_ID(mask); - - ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); - - return 0; - } - - return -EIO; -} - -/* - * Receive start/stop functions - */ - -/* - * Start receive on PCU - */ -void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); - - /* TODO: ANI Support */ -} - -/* - * Stop receive on PCU - */ -void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); - - /* TODO: ANI Support */ -} - -/* - * RX Filter functions - */ - -/* - * Set multicast filter - */ -void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) -{ - ATH5K_TRACE(ah->ah_sc); - /* Set the multicat filter */ - ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); - ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); -} - -/* - * Set multicast filter by index - */ -int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index) -{ - - ATH5K_TRACE(ah->ah_sc); - if (index >= 64) - return -EINVAL; - else if (index >= 32) - AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1, - (1 << (index - 32))); - else - AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); - - return 0; -} - -/* - * Clear Multicast filter by index - */ -int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index) -{ - - ATH5K_TRACE(ah->ah_sc); - if (index >= 64) - return -EINVAL; - else if (index >= 32) - AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1, - (1 << (index - 32))); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); - - return 0; -} - -/* - * Get current rx filter - */ -u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) -{ - u32 data, filter = 0; - - ATH5K_TRACE(ah->ah_sc); - filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); - - /*Radar detection for 5212*/ - if (ah->ah_version == AR5K_AR5212) { - data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); - - if (data & AR5K_PHY_ERR_FIL_RADAR) - filter |= AR5K_RX_FILTER_RADARERR; - if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) - filter |= AR5K_RX_FILTER_PHYERR; - } - - return filter; -} - -/* - * Set rx filter - */ -void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) -{ - u32 data = 0; - - ATH5K_TRACE(ah->ah_sc); - - /* Set PHY error filter register on 5212*/ - if (ah->ah_version == AR5K_AR5212) { - if (filter & AR5K_RX_FILTER_RADARERR) - data |= AR5K_PHY_ERR_FIL_RADAR; - if (filter & AR5K_RX_FILTER_PHYERR) - data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; - } - - /* - * The AR5210 uses promiscous mode to detect radar activity - */ - if (ah->ah_version == AR5K_AR5210 && - (filter & AR5K_RX_FILTER_RADARERR)) { - filter &= ~AR5K_RX_FILTER_RADARERR; - filter |= AR5K_RX_FILTER_PROM; - } - - /*Zero length DMA*/ - if (data) - AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); - - /*Write RX Filter register*/ - ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); - - /*Write PHY error filter register on 5212*/ - if (ah->ah_version == AR5K_AR5212) - ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); - -} - -/* - * Beacon related functions - */ - -/* - * Get a 32bit TSF - */ -u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_reg_read(ah, AR5K_TSF_L32); -} - -/* - * Get the full 64bit TSF - */ -u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) -{ - u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); - ATH5K_TRACE(ah->ah_sc); - - return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); -} - -/* - * Force a TSF reset - */ -void ath5k_hw_reset_tsf(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF); -} - -/* - * Initialize beacon timers - */ -void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) -{ - u32 timer1, timer2, timer3; - - ATH5K_TRACE(ah->ah_sc); - /* - * Set the additional timers by mode - */ - switch (ah->ah_op_mode) { - case IEEE80211_IF_TYPE_STA: - if (ah->ah_version == AR5K_AR5210) { - timer1 = 0xffffffff; - timer2 = 0xffffffff; - } else { - timer1 = 0x0000ffff; - timer2 = 0x0007ffff; - } - break; - - default: - timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; - timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; - } - - timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); - - /* - * Set the beacon register and enable all timers. - * (next beacon, DMA beacon, software beacon, ATIM window time) - */ - ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); - ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); - ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); - ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); - - ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | - AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), - AR5K_BEACON); -} - -#if 0 -/* - * Set beacon timers - */ -int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, - const struct ath5k_beacon_state *state) -{ - u32 cfp_period, next_cfp, dtim, interval, next_beacon; - - /* - * TODO: should be changed through *state - * review struct ath5k_beacon_state struct - * - * XXX: These are used for cfp period bellow, are they - * ok ? Is it O.K. for tsf here to be 0 or should we use - * get_tsf ? - */ - u32 dtim_count = 0; /* XXX */ - u32 cfp_count = 0; /* XXX */ - u32 tsf = 0; /* XXX */ - - ATH5K_TRACE(ah->ah_sc); - /* Return on an invalid beacon state */ - if (state->bs_interval < 1) - return -EINVAL; - - interval = state->bs_interval; - dtim = state->bs_dtim_period; - - /* - * PCF support? - */ - if (state->bs_cfp_period > 0) { - /* - * Enable PCF mode and set the CFP - * (Contention Free Period) and timer registers - */ - cfp_period = state->bs_cfp_period * state->bs_dtim_period * - state->bs_interval; - next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * - state->bs_interval; - - AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_DEFAULT_ANTENNA | - AR5K_STA_ID1_PCF); - ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); - ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, - AR5K_CFP_DUR); - ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : - next_cfp)) << 3, AR5K_TIMER2); - } else { - /* Disable PCF mode */ - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_DEFAULT_ANTENNA | - AR5K_STA_ID1_PCF); - } - - /* - * Enable the beacon timer register - */ - ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); - - /* - * Start the beacon timers - */ - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &~ - (AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | - AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, - AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, - AR5K_BEACON_PERIOD), AR5K_BEACON); - - /* - * Write new beacon miss threshold, if it appears to be valid - * XXX: Figure out right values for min <= bs_bmiss_threshold <= max - * and return if its not in range. We can test this by reading value and - * setting value to a largest value and seeing which values register. - */ - - AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, - state->bs_bmiss_threshold); - - /* - * Set sleep control register - * XXX: Didn't find this in 5210 code but since this register - * exists also in ar5k's 5210 headers i leave it as common code. - */ - AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, - (state->bs_sleep_duration - 3) << 3); - - /* - * Set enhanced sleep registers on 5212 - */ - if (ah->ah_version == AR5K_AR5212) { - if (state->bs_sleep_duration > state->bs_interval && - roundup(state->bs_sleep_duration, interval) == - state->bs_sleep_duration) - interval = state->bs_sleep_duration; - - if (state->bs_sleep_duration > dtim && (dtim == 0 || - roundup(state->bs_sleep_duration, dtim) == - state->bs_sleep_duration)) - dtim = state->bs_sleep_duration; - - if (interval > dtim) - return -EINVAL; - - next_beacon = interval == dtim ? state->bs_next_dtim : - state->bs_next_beacon; - - ath5k_hw_reg_write(ah, - AR5K_REG_SM((state->bs_next_dtim - 3) << 3, - AR5K_SLEEP0_NEXT_DTIM) | - AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | - AR5K_SLEEP0_ENH_SLEEP_EN | - AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); - - ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, - AR5K_SLEEP1_NEXT_TIM) | - AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); - - ath5k_hw_reg_write(ah, - AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | - AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); - } - - return 0; -} - -/* - * Reset beacon timers - */ -void ath5k_hw_reset_beacon(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - /* - * Disable beacon timer - */ - ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); - - /* - * Disable some beacon register values - */ - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); - ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON); -} - -/* - * Wait for beacon queue to finish - */ -int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) -{ - unsigned int i; - int ret; - - ATH5K_TRACE(ah->ah_sc); - - /* 5210 doesn't have QCU*/ - if (ah->ah_version == AR5K_AR5210) { - /* - * Wait for beaconn queue to finish by checking - * Control Register and Beacon Status Register. - */ - for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) { - if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F) - || - !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F)) - break; - udelay(10); - } - - /* Timeout... */ - if (i <= 0) { - /* - * Re-schedule the beacon queue - */ - ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1); - ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, - AR5K_BCR); - - return -EIO; - } - ret = 0; - } else { - /*5211/5212*/ - ret = ath5k_hw_register_timeout(ah, - AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON), - AR5K_QCU_STS_FRMPENDCNT, 0, false); - - if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON)) - return -EIO; - } - - return ret; -} -#endif - -/* - * Update mib counters (statistics) - */ -void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, - struct ieee80211_low_level_stats *stats) -{ - ATH5K_TRACE(ah->ah_sc); - - /* Read-And-Clear */ - stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); - stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); - stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK); - stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); - - /* XXX: Should we use this to track beacon count ? - * -we read it anyway to clear the register */ - ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); - - /* Reset profile count registers on 5212*/ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); - } -} - -/** ath5k_hw_set_ack_bitrate - set bitrate for ACKs - * - * @ah: the &struct ath5k_hw - * @high: determines if to use low bit rate or now - */ -void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) -{ - if (ah->ah_version != AR5K_AR5212) - return; - else { - u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; - if (high) - AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); - } -} - - -/* - * ACK/CTS Timeouts - */ - -/* - * Set ACK timeout on PCU - */ -int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) -{ - ATH5K_TRACE(ah->ah_sc); - if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), - ah->ah_turbo) <= timeout) - return -EINVAL; - - AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, - ath5k_hw_htoclock(timeout, ah->ah_turbo)); - - return 0; -} - -/* - * Read the ACK timeout from PCU - */ -unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - - return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); -} - -/* - * Set CTS timeout on PCU - */ -int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) -{ - ATH5K_TRACE(ah->ah_sc); - if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), - ah->ah_turbo) <= timeout) - return -EINVAL; - - AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, - ath5k_hw_htoclock(timeout, ah->ah_turbo)); - - return 0; -} - -/* - * Read CTS timeout from PCU - */ -unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); -} - -/* - * Key table (WEP) functions - */ - -int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) -{ - unsigned int i; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - - for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) - ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); - - /* - * Set NULL encryption on AR5212+ - * - * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) - * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 - * - * Note2: Windows driver (ndiswrapper) sets this to - * 0x00000714 instead of 0x00000007 - */ - if (ah->ah_version > AR5K_AR5211) - ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, - AR5K_KEYTABLE_TYPE(entry)); - - return 0; -} - -int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - - /* Check the validation flag at the end of the entry */ - return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) & - AR5K_KEYTABLE_VALID; -} - -int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, - const struct ieee80211_key_conf *key, const u8 *mac) -{ - unsigned int i; - __le32 key_v[5] = {}; - u32 keytype; - - ATH5K_TRACE(ah->ah_sc); - - /* key->keylen comes in from mac80211 in bytes */ - - if (key->keylen > AR5K_KEYTABLE_SIZE / 8) - return -EOPNOTSUPP; - - switch (key->keylen) { - /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ - case 40 / 8: - memcpy(&key_v[0], key->key, 5); - keytype = AR5K_KEYTABLE_TYPE_40; - break; - - /* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit */ - case 104 / 8: - memcpy(&key_v[0], &key->key[0], 6); - memcpy(&key_v[2], &key->key[6], 6); - memcpy(&key_v[4], &key->key[12], 1); - keytype = AR5K_KEYTABLE_TYPE_104; - break; - /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ - case 128 / 8: - memcpy(&key_v[0], &key->key[0], 6); - memcpy(&key_v[2], &key->key[6], 6); - memcpy(&key_v[4], &key->key[12], 4); - keytype = AR5K_KEYTABLE_TYPE_128; - break; - - default: - return -EINVAL; /* shouldn't happen */ - } - - for (i = 0; i < ARRAY_SIZE(key_v); i++) - ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), - AR5K_KEYTABLE_OFF(entry, i)); - - ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); - - return ath5k_hw_set_key_lladdr(ah, entry, mac); -} - -int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) -{ - u32 low_id, high_id; - - ATH5K_TRACE(ah->ah_sc); - /* Invalid entry (key table overflow) */ - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - - /* MAC may be NULL if it's a broadcast key. In this case no need to - * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */ - if (unlikely(mac == NULL)) { - low_id = 0xffffffff; - high_id = 0xffff | AR5K_KEYTABLE_VALID; - } else { - low_id = AR5K_LOW_ID(mac); - high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID; - } - - ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); - ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry)); - - return 0; -} - - -/********************************************\ -Queue Control Unit, DFS Control Unit Functions -\********************************************/ - -/* - * Initialize a transmit queue - */ -int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, - struct ath5k_txq_info *queue_info) -{ - unsigned int queue; - int ret; - - ATH5K_TRACE(ah->ah_sc); - - /* - * Get queue by type - */ - /*5210 only has 2 queues*/ - if (ah->ah_version == AR5K_AR5210) { - switch (queue_type) { - case AR5K_TX_QUEUE_DATA: - queue = AR5K_TX_QUEUE_ID_NOQCU_DATA; - break; - case AR5K_TX_QUEUE_BEACON: - case AR5K_TX_QUEUE_CAB: - queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON; - break; - default: - return -EINVAL; - } - } else { - switch (queue_type) { - case AR5K_TX_QUEUE_DATA: - for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; - ah->ah_txq[queue].tqi_type != - AR5K_TX_QUEUE_INACTIVE; queue++) { - - if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) - return -EINVAL; - } - break; - case AR5K_TX_QUEUE_UAPSD: - queue = AR5K_TX_QUEUE_ID_UAPSD; - break; - case AR5K_TX_QUEUE_BEACON: - queue = AR5K_TX_QUEUE_ID_BEACON; - break; - case AR5K_TX_QUEUE_CAB: - queue = AR5K_TX_QUEUE_ID_CAB; - break; - case AR5K_TX_QUEUE_XR_DATA: - if (ah->ah_version != AR5K_AR5212) - ATH5K_ERR(ah->ah_sc, - "XR data queues only supported in" - " 5212!\n"); - queue = AR5K_TX_QUEUE_ID_XR_DATA; - break; - default: - return -EINVAL; - } - } - - /* - * Setup internal queue structure - */ - memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info)); - ah->ah_txq[queue].tqi_type = queue_type; - - if (queue_info != NULL) { - queue_info->tqi_type = queue_type; - ret = ath5k_hw_setup_tx_queueprops(ah, queue, queue_info); - if (ret) - return ret; - } - /* - * We use ah_txq_status to hold a temp value for - * the Secondary interrupt mask registers on 5211+ - * check out ath5k_hw_reset_tx_queue - */ - AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue); - - return queue; -} - -/* - * Setup a transmit queue - */ -int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, - const struct ath5k_txq_info *queue_info) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return -EIO; - - memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info)); - - /*XXX: Is this supported on 5210 ?*/ - if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA && - ((queue_info->tqi_subtype == AR5K_WME_AC_VI) || - (queue_info->tqi_subtype == AR5K_WME_AC_VO))) || - queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD) - ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; - - return 0; -} - -/* - * Get properties for a specific transmit queue - */ -int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, - struct ath5k_txq_info *queue_info) -{ - ATH5K_TRACE(ah->ah_sc); - memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); - return 0; -} - -/* - * Set a transmit queue inactive - */ -void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) -{ - ATH5K_TRACE(ah->ah_sc); - if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) - return; - - /* This queue will be skipped in further operations */ - ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE; - /*For SIMR setup*/ - AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); -} - -/* - * Set DFS params for a transmit queue - */ -int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) -{ - u32 cw_min, cw_max, retry_lg, retry_sh; - struct ath5k_txq_info *tq = &ah->ah_txq[queue]; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - tq = &ah->ah_txq[queue]; - - if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE) - return 0; - - if (ah->ah_version == AR5K_AR5210) { - /* Only handle data queues, others will be ignored */ - if (tq->tqi_type != AR5K_TX_QUEUE_DATA) - return 0; - - /* Set Slot time */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME, - AR5K_SLOT_TIME); - /* Set ACK_CTS timeout */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - AR5K_INIT_ACK_CTS_TIMEOUT_TURBO : - AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME); - /* Set Transmit Latency */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - AR5K_INIT_TRANSMIT_LATENCY_TURBO : - AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210); - /* Set IFS0 */ - if (ah->ah_turbo) - ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO + - (ah->ah_aifs + tq->tqi_aifs) * - AR5K_INIT_SLOT_TIME_TURBO) << - AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO, - AR5K_IFS0); - else - ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS + - (ah->ah_aifs + tq->tqi_aifs) * - AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) | - AR5K_INIT_SIFS, AR5K_IFS0); - - /* Set IFS1 */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - AR5K_INIT_PROTO_TIME_CNTRL_TURBO : - AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1); - /* Set AR5K_PHY_SETTLING */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) - | 0x38 : - (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) - | 0x1C, - AR5K_PHY_SETTLING); - /* Set Frame Control Register */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE | - AR5K_PHY_TURBO_SHORT | 0x2020) : - (AR5K_PHY_FRAME_CTL_INI | 0x1020), - AR5K_PHY_FRAME_CTL_5210); - } - - /* - * Calculate cwmin/max by channel mode - */ - cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN; - cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX; - ah->ah_aifs = AR5K_TUNE_AIFS; - /*XR is only supported on 5212*/ - if (IS_CHAN_XR(ah->ah_current_channel) && - ah->ah_version == AR5K_AR5212) { - cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR; - cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR; - ah->ah_aifs = AR5K_TUNE_AIFS_XR; - /*B mode is not supported on 5210*/ - } else if (IS_CHAN_B(ah->ah_current_channel) && - ah->ah_version != AR5K_AR5210) { - cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B; - cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B; - ah->ah_aifs = AR5K_TUNE_AIFS_11B; - } - - cw_min = 1; - while (cw_min < ah->ah_cw_min) - cw_min = (cw_min << 1) | 1; - - cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) : - ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); - cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) : - ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1); - - /* - * Calculate and set retry limits - */ - if (ah->ah_software_retry) { - /* XXX Need to test this */ - retry_lg = ah->ah_limit_tx_retries; - retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? - AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg; - } else { - retry_lg = AR5K_INIT_LG_RETRY; - retry_sh = AR5K_INIT_SH_RETRY; - } - - /*No QCU/DCU [5210]*/ - if (ah->ah_version == AR5K_AR5210) { - ath5k_hw_reg_write(ah, - (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) - | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, - AR5K_NODCU_RETRY_LMT_SLG_RETRY) - | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, - AR5K_NODCU_RETRY_LMT_SSH_RETRY) - | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY) - | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY), - AR5K_NODCU_RETRY_LMT); - } else { - /*QCU/DCU [5211+]*/ - ath5k_hw_reg_write(ah, - AR5K_REG_SM(AR5K_INIT_SLG_RETRY, - AR5K_DCU_RETRY_LMT_SLG_RETRY) | - AR5K_REG_SM(AR5K_INIT_SSH_RETRY, - AR5K_DCU_RETRY_LMT_SSH_RETRY) | - AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) | - AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY), - AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); - - /*===Rest is also for QCU/DCU only [5211+]===*/ - - /* - * Set initial content window (cw_min/cw_max) - * and arbitrated interframe space (aifs)... - */ - ath5k_hw_reg_write(ah, - AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | - AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | - AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs, - AR5K_DCU_LCL_IFS_AIFS), - AR5K_QUEUE_DFS_LOCAL_IFS(queue)); - - /* - * Set misc registers - */ - ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY, - AR5K_QUEUE_MISC(queue)); - - if (tq->tqi_cbr_period) { - ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period, - AR5K_QCU_CBRCFG_INTVAL) | - AR5K_REG_SM(tq->tqi_cbr_overflow_limit, - AR5K_QCU_CBRCFG_ORN_THRES), - AR5K_QUEUE_CBRCFG(queue)); - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_CBR); - if (tq->tqi_cbr_overflow_limit) - AR5K_REG_ENABLE_BITS(ah, - AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_CBR_THRES_ENABLE); - } - - if (tq->tqi_ready_time) - ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, - AR5K_QCU_RDYTIMECFG_INTVAL) | - AR5K_QCU_RDYTIMECFG_ENABLE, - AR5K_QUEUE_RDYTIMECFG(queue)); - - if (tq->tqi_burst_time) { - ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time, - AR5K_DCU_CHAN_TIME_DUR) | - AR5K_DCU_CHAN_TIME_ENABLE, - AR5K_QUEUE_DFS_CHANNEL_TIME(queue)); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) - AR5K_REG_ENABLE_BITS(ah, - AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_RDY_VEOL_POLICY); - } - - if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) - ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS, - AR5K_QUEUE_DFS_MISC(queue)); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) - ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG, - AR5K_QUEUE_DFS_MISC(queue)); - - /* - * Set registers by queue type - */ - switch (tq->tqi_type) { - case AR5K_TX_QUEUE_BEACON: - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_DBA_GT | - AR5K_QCU_MISC_CBREXP_BCN | - AR5K_QCU_MISC_BCN_ENABLE); - - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), - (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << - AR5K_DCU_MISC_ARBLOCK_CTL_S) | - AR5K_DCU_MISC_POST_FR_BKOFF_DIS | - AR5K_DCU_MISC_BCN_ENABLE); - - ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - - (AR5K_TUNE_SW_BEACON_RESP - - AR5K_TUNE_DMA_BEACON_RESP) - - AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | - AR5K_QCU_RDYTIMECFG_ENABLE, - AR5K_QUEUE_RDYTIMECFG(queue)); - break; - - case AR5K_TX_QUEUE_CAB: - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_DBA_GT | - AR5K_QCU_MISC_CBREXP | - AR5K_QCU_MISC_CBREXP_BCN); - - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), - (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << - AR5K_DCU_MISC_ARBLOCK_CTL_S)); - break; - - case AR5K_TX_QUEUE_UAPSD: - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_CBREXP); - break; - - case AR5K_TX_QUEUE_DATA: - default: - break; - } - - /* - * Enable interrupts for this tx queue - * in the secondary interrupt mask registers - */ - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); - - - /* Update secondary interrupt mask registers */ - ah->ah_txq_imr_txok &= ah->ah_txq_status; - ah->ah_txq_imr_txerr &= ah->ah_txq_status; - ah->ah_txq_imr_txurn &= ah->ah_txq_status; - ah->ah_txq_imr_txdesc &= ah->ah_txq_status; - ah->ah_txq_imr_txeol &= ah->ah_txq_status; - - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, - AR5K_SIMR0_QCU_TXOK) | - AR5K_REG_SM(ah->ah_txq_imr_txdesc, - AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0); - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr, - AR5K_SIMR1_QCU_TXERR) | - AR5K_REG_SM(ah->ah_txq_imr_txeol, - AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn, - AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2); - } - - return 0; -} - -/* - * Get number of pending frames - * for a specific queue [5211+] - */ -u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) { - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* Return if queue is declared inactive */ - if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return false; - - /* XXX: How about AR5K_CFG_TXCNT ? */ - if (ah->ah_version == AR5K_AR5210) - return false; - - return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT; -} - -/* - * Set slot time - */ -int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) -{ - ATH5K_TRACE(ah->ah_sc); - if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX) - return -EINVAL; - - if (ah->ah_version == AR5K_AR5210) - ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time, - ah->ah_turbo), AR5K_SLOT_TIME); - else - ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT); - - return 0; -} - -/* - * Get slot time - */ -unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - if (ah->ah_version == AR5K_AR5210) - return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah, - AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo); - else - return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff; -} - - -/******************************\ - Hardware Descriptor Functions -\******************************/ - -/* - * TX Descriptor - */ - -/* - * Initialize the 2-word tx descriptor on 5210/5211 - */ -static int -ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, - unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, - unsigned int key_index, unsigned int antenna_mode, unsigned int flags, - unsigned int rtscts_rate, unsigned int rtscts_duration) -{ - u32 frame_type; - struct ath5k_hw_2w_tx_ctl *tx_ctl; - unsigned int frame_len; - - tx_ctl = &desc->ud.ds_tx5210.tx_ctl; - - /* - * Validate input - * - Zero retries don't make sense. - * - A zero rate will put the HW into a mode where it continously sends - * noise on the channel, so it is important to avoid this. - */ - if (unlikely(tx_tries0 == 0)) { - ATH5K_ERR(ah->ah_sc, "zero retries\n"); - WARN_ON(1); - return -EINVAL; - } - if (unlikely(tx_rate0 == 0)) { - ATH5K_ERR(ah->ah_sc, "zero rate\n"); - WARN_ON(1); - return -EINVAL; - } - - /* Clear descriptor */ - memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); - - /* Setup control descriptor */ - - /* Verify and set frame length */ - - /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; - - if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) - return -EINVAL; - - tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; - - /* Verify and set buffer length */ - - /* NB: beacon's BufLen must be a multiple of 4 bytes */ - if(type == AR5K_PKT_TYPE_BEACON) - pkt_len = roundup(pkt_len, 4); - - if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) - return -EINVAL; - - tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; - - /* - * Verify and set header length - * XXX: I only found that on 5210 code, does it work on 5211 ? - */ - if (ah->ah_version == AR5K_AR5210) { - if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) - return -EINVAL; - tx_ctl->tx_control_0 |= - AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); - } - - /*Diferences between 5210-5211*/ - if (ah->ah_version == AR5K_AR5210) { - switch (type) { - case AR5K_PKT_TYPE_BEACON: - case AR5K_PKT_TYPE_PROBE_RESP: - frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; - case AR5K_PKT_TYPE_PIFS: - frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; - default: - frame_type = type /*<< 2 ?*/; - } - - tx_ctl->tx_control_0 |= - AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | - AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); - } else { - tx_ctl->tx_control_0 |= - AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | - AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); - tx_ctl->tx_control_1 |= - AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); - } -#define _TX_FLAGS(_c, _flag) \ - if (flags & AR5K_TXDESC_##_flag) \ - tx_ctl->tx_control_##_c |= \ - AR5K_2W_TX_DESC_CTL##_c##_##_flag - - _TX_FLAGS(0, CLRDMASK); - _TX_FLAGS(0, VEOL); - _TX_FLAGS(0, INTREQ); - _TX_FLAGS(0, RTSENA); - _TX_FLAGS(1, NOACK); - -#undef _TX_FLAGS - - /* - * WEP crap - */ - if (key_index != AR5K_TXKEYIX_INVALID) { - tx_ctl->tx_control_0 |= - AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; - tx_ctl->tx_control_1 |= - AR5K_REG_SM(key_index, - AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); - } - - /* - * RTS/CTS Duration [5210 ?] - */ - if ((ah->ah_version == AR5K_AR5210) && - (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) - tx_ctl->tx_control_1 |= rtscts_duration & - AR5K_2W_TX_DESC_CTL1_RTS_DURATION; - - return 0; -} - -/* - * Initialize the 4-word tx descriptor on 5212 - */ -static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, - struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, - enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, - unsigned int tx_tries0, unsigned int key_index, - unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, - unsigned int rtscts_duration) -{ - struct ath5k_hw_4w_tx_ctl *tx_ctl; - unsigned int frame_len; - - ATH5K_TRACE(ah->ah_sc); - tx_ctl = &desc->ud.ds_tx5212.tx_ctl; - - /* - * Validate input - * - Zero retries don't make sense. - * - A zero rate will put the HW into a mode where it continously sends - * noise on the channel, so it is important to avoid this. - */ - if (unlikely(tx_tries0 == 0)) { - ATH5K_ERR(ah->ah_sc, "zero retries\n"); - WARN_ON(1); - return -EINVAL; - } - if (unlikely(tx_rate0 == 0)) { - ATH5K_ERR(ah->ah_sc, "zero rate\n"); - WARN_ON(1); - return -EINVAL; - } - - /* Clear descriptor */ - memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); - - /* Setup control descriptor */ - - /* Verify and set frame length */ - - /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; - - if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) - return -EINVAL; - - tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; - - /* Verify and set buffer length */ - - /* NB: beacon's BufLen must be a multiple of 4 bytes */ - if(type == AR5K_PKT_TYPE_BEACON) - pkt_len = roundup(pkt_len, 4); - - if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) - return -EINVAL; - - tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; - - tx_ctl->tx_control_0 |= - AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | - AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); - tx_ctl->tx_control_1 |= AR5K_REG_SM(type, - AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); - tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); - tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; - -#define _TX_FLAGS(_c, _flag) \ - if (flags & AR5K_TXDESC_##_flag) \ - tx_ctl->tx_control_##_c |= \ - AR5K_4W_TX_DESC_CTL##_c##_##_flag - - _TX_FLAGS(0, CLRDMASK); - _TX_FLAGS(0, VEOL); - _TX_FLAGS(0, INTREQ); - _TX_FLAGS(0, RTSENA); - _TX_FLAGS(0, CTSENA); - _TX_FLAGS(1, NOACK); - -#undef _TX_FLAGS - - /* - * WEP crap - */ - if (key_index != AR5K_TXKEYIX_INVALID) { - tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; - tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, - AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); - } - - /* - * RTS/CTS - */ - if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { - if ((flags & AR5K_TXDESC_RTSENA) && - (flags & AR5K_TXDESC_CTSENA)) - return -EINVAL; - tx_ctl->tx_control_2 |= rtscts_duration & - AR5K_4W_TX_DESC_CTL2_RTS_DURATION; - tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, - AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); - } - - return 0; -} - -/* - * Initialize a 4-word multirate tx descriptor on 5212 - */ -static int -ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, - unsigned int tx_rate3, u_int tx_tries3) -{ - struct ath5k_hw_4w_tx_ctl *tx_ctl; - - /* - * Rates can be 0 as long as the retry count is 0 too. - * A zero rate and nonzero retry count will put the HW into a mode where - * it continously sends noise on the channel, so it is important to - * avoid this. - */ - if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || - (tx_rate2 == 0 && tx_tries2 != 0) || - (tx_rate3 == 0 && tx_tries3 != 0))) { - ATH5K_ERR(ah->ah_sc, "zero rate\n"); - WARN_ON(1); - return -EINVAL; - } - - if (ah->ah_version == AR5K_AR5212) { - tx_ctl = &desc->ud.ds_tx5212.tx_ctl; - -#define _XTX_TRIES(_n) \ - if (tx_tries##_n) { \ - tx_ctl->tx_control_2 |= \ - AR5K_REG_SM(tx_tries##_n, \ - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ - tx_ctl->tx_control_3 |= \ - AR5K_REG_SM(tx_rate##_n, \ - AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ - } - - _XTX_TRIES(1); - _XTX_TRIES(2); - _XTX_TRIES(3); - -#undef _XTX_TRIES - - return 1; - } - - return 0; -} - -/* - * Proccess the tx status descriptor on 5210/5211 - */ -static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, struct ath5k_tx_status *ts) -{ - struct ath5k_hw_2w_tx_ctl *tx_ctl; - struct ath5k_hw_tx_status *tx_status; - - ATH5K_TRACE(ah->ah_sc); - - tx_ctl = &desc->ud.ds_tx5210.tx_ctl; - tx_status = &desc->ud.ds_tx5210.tx_stat; - - /* No frame has been send or error */ - if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) - return -EINPROGRESS; - - /* - * Get descriptor status - */ - ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); - ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); - /*TODO: ts->ts_virtcol + test*/ - ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_SEQ_NUM); - ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - ts->ts_antenna = 1; - ts->ts_status = 0; - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0, - AR5K_2W_TX_DESC_CTL0_XMIT_RATE); - - if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ - if (tx_status->tx_status_0 & - AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) - ts->ts_status |= AR5K_TXERR_XRETRY; - - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) - ts->ts_status |= AR5K_TXERR_FIFO; - - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) - ts->ts_status |= AR5K_TXERR_FILT; - } - - return 0; -} - -/* - * Proccess a tx descriptor on 5212 - */ -static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, struct ath5k_tx_status *ts) -{ - struct ath5k_hw_4w_tx_ctl *tx_ctl; - struct ath5k_hw_tx_status *tx_status; - - ATH5K_TRACE(ah->ah_sc); - - tx_ctl = &desc->ud.ds_tx5212.tx_ctl; - tx_status = &desc->ud.ds_tx5212.tx_stat; - - /* No frame has been send or error */ - if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) - return -EINPROGRESS; - - /* - * Get descriptor status - */ - ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); - ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); - ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_SEQ_NUM); - ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - ts->ts_antenna = (tx_status->tx_status_1 & - AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; - ts->ts_status = 0; - - switch (AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { - case 0: - ts->ts_rate = tx_ctl->tx_control_3 & - AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; - break; - case 1: - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); - ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); - break; - case 2: - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); - ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); - break; - case 3: - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); - ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); - break; - } - - if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ - if (tx_status->tx_status_0 & - AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) - ts->ts_status |= AR5K_TXERR_XRETRY; - - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) - ts->ts_status |= AR5K_TXERR_FIFO; - - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) - ts->ts_status |= AR5K_TXERR_FILT; - } - - return 0; -} - -/* - * RX Descriptor - */ - -/* - * Initialize an rx descriptor - */ -int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - u32 size, unsigned int flags) -{ - struct ath5k_hw_rx_ctl *rx_ctl; - - ATH5K_TRACE(ah->ah_sc); - rx_ctl = &desc->ud.ds_rx.rx_ctl; - - /* - * Clear the descriptor - * If we don't clean the status descriptor, - * while scanning we get too many results, - * most of them virtual, after some secs - * of scanning system hangs. M.F. - */ - memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc)); - - /* Setup descriptor */ - rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; - if (unlikely(rx_ctl->rx_control_1 != size)) - return -EINVAL; - - if (flags & AR5K_RXDESC_INTREQ) - rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; - - return 0; -} - -/* - * Proccess the rx status descriptor on 5210/5211 - */ -static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, struct ath5k_rx_status *rs) -{ - struct ath5k_hw_rx_status *rx_status; - - rx_status = &desc->ud.ds_rx.u.rx_stat; - - /* No frame received / not ready */ - if (unlikely((rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_DONE) - == 0)) - return -EINPROGRESS; - - /* - * Frame receive status - */ - rs->rs_datalen = rx_status->rx_status_0 & - AR5K_5210_RX_DESC_STATUS0_DATA_LEN; - rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL); - rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE); - rs->rs_antenna = rx_status->rx_status_0 & - AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA; - rs->rs_more = rx_status->rx_status_0 & - AR5K_5210_RX_DESC_STATUS0_MORE; - /* TODO: this timestamp is 13 bit, later on we assume 15 bit */ - rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); - rs->rs_status = 0; - rs->rs_phyerr = 0; - - /* - * Key table status - */ - if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID) - rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5210_RX_DESC_STATUS1_KEY_INDEX); - else - rs->rs_keyix = AR5K_RXKEYIX_INVALID; - - /* - * Receive/descriptor errors - */ - if ((rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { - if (rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_CRC_ERROR) - rs->rs_status |= AR5K_RXERR_CRC; - - if (rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN) - rs->rs_status |= AR5K_RXERR_FIFO; - - if (rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { - rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); - } - - if (rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) - rs->rs_status |= AR5K_RXERR_DECRYPT; - } - - return 0; -} - -/* - * Proccess the rx status descriptor on 5212 - */ -static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, struct ath5k_rx_status *rs) -{ - struct ath5k_hw_rx_status *rx_status; - struct ath5k_hw_rx_error *rx_err; - - ATH5K_TRACE(ah->ah_sc); - rx_status = &desc->ud.ds_rx.u.rx_stat; - - /* Overlay on error */ - rx_err = &desc->ud.ds_rx.u.rx_err; - - /* No frame received / not ready */ - if (unlikely((rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE) - == 0)) - return -EINPROGRESS; - - /* - * Frame receive status - */ - rs->rs_datalen = rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_DATA_LEN; - rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); - rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); - rs->rs_antenna = rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA; - rs->rs_more = rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_MORE; - rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); - rs->rs_status = 0; - rs->rs_phyerr = 0; - - /* - * Key table status - */ - if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) - rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); - else - rs->rs_keyix = AR5K_RXKEYIX_INVALID; - - /* - * Receive/descriptor errors - */ - if ((rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) - rs->rs_status |= AR5K_RXERR_CRC; - - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { - rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, - AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); - } - - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) - rs->rs_status |= AR5K_RXERR_DECRYPT; - - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) - rs->rs_status |= AR5K_RXERR_MIC; - } - - return 0; -} - - -/****************\ - GPIO Functions -\****************/ - -/* - * Set led state - */ -void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) -{ - u32 led; - /*5210 has different led mode handling*/ - u32 led_5210; - - ATH5K_TRACE(ah->ah_sc); - - /*Reset led status*/ - if (ah->ah_version != AR5K_AR5210) - AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, - AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED); - - /* - * Some blinking values, define at your wish - */ - switch (state) { - case AR5K_LED_SCAN: - case AR5K_LED_AUTH: - led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND; - led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL; - break; - - case AR5K_LED_INIT: - led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE; - led_5210 = AR5K_PCICFG_LED_PEND; - break; - - case AR5K_LED_ASSOC: - case AR5K_LED_RUN: - led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC; - led_5210 = AR5K_PCICFG_LED_ASSOC; - break; - - default: - led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE; - led_5210 = AR5K_PCICFG_LED_PEND; - break; - } - - /*Write new status to the register*/ - if (ah->ah_version != AR5K_AR5210) - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led); - else - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); -} - -/* - * Set GPIO outputs - */ -int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) -{ - ATH5K_TRACE(ah->ah_sc); - if (gpio > AR5K_NUM_GPIO) - return -EINVAL; - - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~ - AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); - - return 0; -} - -/* - * Set GPIO inputs - */ -int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) -{ - ATH5K_TRACE(ah->ah_sc); - if (gpio > AR5K_NUM_GPIO) - return -EINVAL; - - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~ - AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); - - return 0; -} - -/* - * Get GPIO state - */ -u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) -{ - ATH5K_TRACE(ah->ah_sc); - if (gpio > AR5K_NUM_GPIO) - return 0xffffffff; - - /* GPIO input magic */ - return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & - 0x1; -} - -/* - * Set GPIO state - */ -int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) -{ - u32 data; - ATH5K_TRACE(ah->ah_sc); - - if (gpio > AR5K_NUM_GPIO) - return -EINVAL; - - /* GPIO output magic */ - data = ath5k_hw_reg_read(ah, AR5K_GPIODO); - - data &= ~(1 << gpio); - data |= (val & 1) << gpio; - - ath5k_hw_reg_write(ah, data, AR5K_GPIODO); - - return 0; -} - -/* - * Initialize the GPIO interrupt (RFKill switch) - */ -void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, - u32 interrupt_level) -{ - u32 data; - - ATH5K_TRACE(ah->ah_sc); - if (gpio > AR5K_NUM_GPIO) - return; - - /* - * Set the GPIO interrupt - */ - data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & - ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | - AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | - (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); - - ath5k_hw_reg_write(ah, interrupt_level ? data : - (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); - - ah->ah_imr |= AR5K_IMR_GPIO; - - /* Enable GPIO interrupts */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); -} - - - - -/****************\ - Misc functions -\****************/ - -int ath5k_hw_get_capability(struct ath5k_hw *ah, - enum ath5k_capability_type cap_type, - u32 capability, u32 *result) -{ - ATH5K_TRACE(ah->ah_sc); - - switch (cap_type) { - case AR5K_CAP_NUM_TXQUEUES: - if (result) { - if (ah->ah_version == AR5K_AR5210) - *result = AR5K_NUM_TX_QUEUES_NOQCU; - else - *result = AR5K_NUM_TX_QUEUES; - goto yes; - } - case AR5K_CAP_VEOL: - goto yes; - case AR5K_CAP_COMPRESSION: - if (ah->ah_version == AR5K_AR5212) - goto yes; - else - goto no; - case AR5K_CAP_BURST: - goto yes; - case AR5K_CAP_TPC: - goto yes; - case AR5K_CAP_BSSIDMASK: - if (ah->ah_version == AR5K_AR5212) - goto yes; - else - goto no; - case AR5K_CAP_XR: - if (ah->ah_version == AR5K_AR5212) - goto yes; - else - goto no; - default: - goto no; - } - -no: - return -EINVAL; -yes: - return 0; -} - -static int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, - u16 assoc_id) -{ - ATH5K_TRACE(ah->ah_sc); - - if (ah->ah_version == AR5K_AR5210) { - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); - return 0; - } - - return -EIO; -} - -static int ath5k_hw_disable_pspoll(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - - if (ah->ah_version == AR5K_AR5210) { - AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); - return 0; - } - - return -EIO; -} diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c index 2806b21bf90..ea2e1a20b49 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath5k/initvals.c @@ -1,9 +1,9 @@ /* * Initial register settings functions * - * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> - * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com> - * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> + * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,13 +20,9 @@ */ #include "ath5k.h" -#include "base.h" #include "reg.h" - -/* - * MAC/PHY REGISTERS - */ - +#include "debug.h" +#include "base.h" /* * Mode-independent initial register writes @@ -65,10 +61,10 @@ static const struct ath5k_ini ar5210_ini[] = { { AR5K_TXCFG, AR5K_DMASIZE_128B }, { AR5K_RXCFG, AR5K_DMASIZE_128B }, { AR5K_CFG, AR5K_INIT_CFG }, - { AR5K_TOPS, AR5K_INIT_TOPS }, - { AR5K_RXNOFRM, AR5K_INIT_RXNOFRM }, - { AR5K_RPGTO, AR5K_INIT_RPGTO }, - { AR5K_TXNOFRM, AR5K_INIT_TXNOFRM }, + { AR5K_TOPS, 8 }, + { AR5K_RXNOFRM, 8 }, + { AR5K_RPGTO, 0 }, + { AR5K_TXNOFRM, 0 }, { AR5K_SFR, 0 }, { AR5K_MIBC, 0 }, { AR5K_MISC, 0 }, diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c new file mode 100644 index 00000000000..a47df9a24aa --- /dev/null +++ b/drivers/net/wireless/ath5k/pcu.c @@ -0,0 +1,1014 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007-2008 Matthew W. S. Bell <mentor@madwifi.org> + * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu> + * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org> + * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> + * + * Permission to use, copy, modify, and 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. + * + */ + +/*********************************\ +* Protocol Control Unit Functions * +\*********************************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/*******************\ +* Generic functions * +\*******************/ + +/** + * ath5k_hw_set_opmode - Set PCU operating mode + * + * @ah: The &struct ath5k_hw + * + * Initialize PCU for the various operating modes (AP/STA etc) + * + * NOTE: ah->ah_op_mode must be set before calling this. + */ +int ath5k_hw_set_opmode(struct ath5k_hw *ah) +{ + u32 pcu_reg, beacon_reg, low_id, high_id; + + pcu_reg = 0; + beacon_reg = 0; + + ATH5K_TRACE(ah->ah_sc); + + switch (ah->ah_op_mode) { + case NL80211_IFTYPE_ADHOC: + pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_NO_PSPOLL : 0); + beacon_reg |= AR5K_BCR_ADHOC; + break; + + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_NO_PSPOLL : 0); + beacon_reg |= AR5K_BCR_AP; + break; + + case NL80211_IFTYPE_STATION: + pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_PWR_SV : 0); + case NL80211_IFTYPE_MONITOR: + pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_NO_PSPOLL : 0); + break; + + default: + return -EINVAL; + } + + /* + * Set PCU registers + */ + low_id = AR5K_LOW_ID(ah->ah_sta_id); + high_id = AR5K_HIGH_ID(ah->ah_sta_id); + ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); + ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); + + /* + * Set Beacon Control Register on 5210 + */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); + + return 0; +} + +/** + * ath5k_hw_update - Update mib counters (mac layer statistics) + * + * @ah: The &struct ath5k_hw + * @stats: The &struct ieee80211_low_level_stats we use to track + * statistics on the driver + * + * Reads MIB counters from PCU and updates sw statistics. Must be + * called after a MIB interrupt. + */ +void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, + struct ieee80211_low_level_stats *stats) +{ + ATH5K_TRACE(ah->ah_sc); + + /* Read-And-Clear */ + stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); + stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); + stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK); + stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); + + /* XXX: Should we use this to track beacon count ? + * -we read it anyway to clear the register */ + ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); + + /* Reset profile count registers on 5212*/ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); + } +} + +/** + * ath5k_hw_set_ack_bitrate - set bitrate for ACKs + * + * @ah: The &struct ath5k_hw + * @high: Flag to determine if we want to use high transmition rate + * for ACKs or not + * + * If high flag is set, we tell hw to use a set of control rates based on + * the current transmition rate (check out control_rates array inside reset.c). + * If not hw just uses the lowest rate available for the current modulation + * scheme being used (1Mbit for CCK and 6Mbits for OFDM). + */ +void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) +{ + if (ah->ah_version != AR5K_AR5212) + return; + else { + u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; + if (high) + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); + } +} + + +/******************\ +* ACK/CTS Timeouts * +\******************/ + +/** + * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec + * + * @ah: The &struct ath5k_hw + */ +unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + + return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); +} + +/** + * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU + * + * @ah: The &struct ath5k_hw + * @timeout: Timeout in usec + */ +int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) +{ + ATH5K_TRACE(ah->ah_sc); + if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), + ah->ah_turbo) <= timeout) + return -EINVAL; + + AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, + ath5k_hw_htoclock(timeout, ah->ah_turbo)); + + return 0; +} + +/** + * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec + * + * @ah: The &struct ath5k_hw + */ +unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); +} + +/** + * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU + * + * @ah: The &struct ath5k_hw + * @timeout: Timeout in usec + */ +int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) +{ + ATH5K_TRACE(ah->ah_sc); + if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), + ah->ah_turbo) <= timeout) + return -EINVAL; + + AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, + ath5k_hw_htoclock(timeout, ah->ah_turbo)); + + return 0; +} + + +/****************\ +* BSSID handling * +\****************/ + +/** + * ath5k_hw_get_lladdr - Get station id + * + * @ah: The &struct ath5k_hw + * @mac: The card's mac address + * + * Initialize ah->ah_sta_id using the mac address provided + * (just a memcpy). + * + * TODO: Remove it once we merge ath5k_softc and ath5k_hw + */ +void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) +{ + ATH5K_TRACE(ah->ah_sc); + memcpy(mac, ah->ah_sta_id, ETH_ALEN); +} + +/** + * ath5k_hw_set_lladdr - Set station id + * + * @ah: The &struct ath5k_hw + * @mac: The card's mac address + * + * Set station id on hw using the provided mac address + */ +int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) +{ + u32 low_id, high_id; + + ATH5K_TRACE(ah->ah_sc); + /* Set new station ID */ + memcpy(ah->ah_sta_id, mac, ETH_ALEN); + + low_id = AR5K_LOW_ID(mac); + high_id = AR5K_HIGH_ID(mac); + + ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); + ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1); + + return 0; +} + +/** + * ath5k_hw_set_associd - Set BSSID for association + * + * @ah: The &struct ath5k_hw + * @bssid: BSSID + * @assoc_id: Assoc id + * + * Sets the BSSID which trigers the "SME Join" operation + */ +void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) +{ + u32 low_id, high_id; + u16 tim_offset = 0; + + /* + * Set simple BSSID mask on 5212 + */ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1); + } + + /* + * Set BSSID which triggers the "SME Join" operation + */ + low_id = AR5K_LOW_ID(bssid); + high_id = AR5K_HIGH_ID(bssid); + ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); + ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << + AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); + + if (assoc_id == 0) { + ath5k_hw_disable_pspoll(ah); + return; + } + + AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, + tim_offset ? tim_offset + 4 : 0); + + ath5k_hw_enable_pspoll(ah, NULL, 0); +} + +/** + * ath5k_hw_set_bssid_mask - filter out bssids we listen + * + * @ah: the &struct ath5k_hw + * @mask: the bssid_mask, a u8 array of size ETH_ALEN + * + * BSSID masking is a method used by AR5212 and newer hardware to inform PCU + * which bits of the interface's MAC address should be looked at when trying + * to decide which packets to ACK. In station mode and AP mode with a single + * BSS every bit matters since we lock to only one BSS. In AP mode with + * multiple BSSes (virtual interfaces) not every bit matters because hw must + * accept frames for all BSSes and so we tweak some bits of our mac address + * in order to have multiple BSSes. + * + * NOTE: This is a simple filter and does *not* filter out all + * relevant frames. Some frames that are not for us might get ACKed from us + * by PCU because they just match the mask. + * + * When handling multiple BSSes you can get the BSSID mask by computing the + * set of ~ ( MAC XOR BSSID ) for all bssids we handle. + * + * When you do this you are essentially computing the common bits of all your + * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with + * the MAC address to obtain the relevant bits and compare the result with + * (frame's BSSID & mask) to see if they match. + */ +/* + * Simple example: on your card you have have two BSSes you have created with + * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. + * There is another BSSID-03 but you are not part of it. For simplicity's sake, + * assuming only 4 bits for a mac address and for BSSIDs you can then have: + * + * \ + * MAC: 0001 | + * BSSID-01: 0100 | --> Belongs to us + * BSSID-02: 1001 | + * / + * ------------------- + * BSSID-03: 0110 | --> External + * ------------------- + * + * Our bssid_mask would then be: + * + * On loop iteration for BSSID-01: + * ~(0001 ^ 0100) -> ~(0101) + * -> 1010 + * bssid_mask = 1010 + * + * On loop iteration for BSSID-02: + * bssid_mask &= ~(0001 ^ 1001) + * bssid_mask = (1010) & ~(0001 ^ 1001) + * bssid_mask = (1010) & ~(1001) + * bssid_mask = (1010) & (0110) + * bssid_mask = 0010 + * + * A bssid_mask of 0010 means "only pay attention to the second least + * significant bit". This is because its the only bit common + * amongst the MAC and all BSSIDs we support. To findout what the real + * common bit is we can simply "&" the bssid_mask now with any BSSID we have + * or our MAC address (we assume the hardware uses the MAC address). + * + * Now, suppose there's an incoming frame for BSSID-03: + * + * IFRAME-01: 0110 + * + * An easy eye-inspeciton of this already should tell you that this frame + * will not pass our check. This is beacuse the bssid_mask tells the + * hardware to only look at the second least significant bit and the + * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB + * as 1, which does not match 0. + * + * So with IFRAME-01 we *assume* the hardware will do: + * + * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; + * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; + * --> allow = (0010) == 0000 ? 1 : 0; + * --> allow = 0 + * + * Lets now test a frame that should work: + * + * IFRAME-02: 0001 (we should allow) + * + * allow = (0001 & 1010) == 1010 + * + * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; + * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; + * --> allow = (0010) == (0010) + * --> allow = 1 + * + * Other examples: + * + * IFRAME-03: 0100 --> allowed + * IFRAME-04: 1001 --> allowed + * IFRAME-05: 1101 --> allowed but its not for us!!! + * + */ +int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) +{ + u32 low_id, high_id; + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_version == AR5K_AR5212) { + low_id = AR5K_LOW_ID(mask); + high_id = AR5K_HIGH_ID(mask); + + ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); + + return 0; + } + + return -EIO; +} + + +/************\ +* RX Control * +\************/ + +/** + * ath5k_hw_start_rx_pcu - Start RX engine + * + * @ah: The &struct ath5k_hw + * + * Starts RX engine on PCU so that hw can process RXed frames + * (ACK etc). + * + * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma + * TODO: Init ANI here + */ +void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); +} + +/** + * at5k_hw_stop_rx_pcu - Stop RX engine + * + * @ah: The &struct ath5k_hw + * + * Stops RX engine on PCU + * + * TODO: Detach ANI here + */ +void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); +} + +/* + * Set multicast filter + */ +void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) +{ + ATH5K_TRACE(ah->ah_sc); + /* Set the multicat filter */ + ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); + ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); +} + +/* + * Set multicast filter by index + */ +int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index) +{ + + ATH5K_TRACE(ah->ah_sc); + if (index >= 64) + return -EINVAL; + else if (index >= 32) + AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1, + (1 << (index - 32))); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); + + return 0; +} + +/* + * Clear Multicast filter by index + */ +int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index) +{ + + ATH5K_TRACE(ah->ah_sc); + if (index >= 64) + return -EINVAL; + else if (index >= 32) + AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1, + (1 << (index - 32))); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); + + return 0; +} + +/** + * ath5k_hw_get_rx_filter - Get current rx filter + * + * @ah: The &struct ath5k_hw + * + * Returns the RX filter by reading rx filter and + * phy error filter registers. RX filter is used + * to set the allowed frame types that PCU will accept + * and pass to the driver. For a list of frame types + * check out reg.h. + */ +u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) +{ + u32 data, filter = 0; + + ATH5K_TRACE(ah->ah_sc); + filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); + + /*Radar detection for 5212*/ + if (ah->ah_version == AR5K_AR5212) { + data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); + + if (data & AR5K_PHY_ERR_FIL_RADAR) + filter |= AR5K_RX_FILTER_RADARERR; + if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) + filter |= AR5K_RX_FILTER_PHYERR; + } + + return filter; +} + +/** + * ath5k_hw_set_rx_filter - Set rx filter + * + * @ah: The &struct ath5k_hw + * @filter: RX filter mask (see reg.h) + * + * Sets RX filter register and also handles PHY error filter + * register on 5212 and newer chips so that we have proper PHY + * error reporting. + */ +void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) +{ + u32 data = 0; + + ATH5K_TRACE(ah->ah_sc); + + /* Set PHY error filter register on 5212*/ + if (ah->ah_version == AR5K_AR5212) { + if (filter & AR5K_RX_FILTER_RADARERR) + data |= AR5K_PHY_ERR_FIL_RADAR; + if (filter & AR5K_RX_FILTER_PHYERR) + data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; + } + + /* + * The AR5210 uses promiscous mode to detect radar activity + */ + if (ah->ah_version == AR5K_AR5210 && + (filter & AR5K_RX_FILTER_RADARERR)) { + filter &= ~AR5K_RX_FILTER_RADARERR; + filter |= AR5K_RX_FILTER_PROM; + } + + /*Zero length DMA*/ + if (data) + AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); + + /*Write RX Filter register*/ + ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); + + /*Write PHY error filter register on 5212*/ + if (ah->ah_version == AR5K_AR5212) + ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); + +} + + +/****************\ +* Beacon control * +\****************/ + +/** + * ath5k_hw_get_tsf32 - Get a 32bit TSF + * + * @ah: The &struct ath5k_hw + * + * Returns lower 32 bits of current TSF + */ +u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + return ath5k_hw_reg_read(ah, AR5K_TSF_L32); +} + +/** + * ath5k_hw_get_tsf64 - Get the full 64bit TSF + * + * @ah: The &struct ath5k_hw + * + * Returns the current TSF + */ +u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) +{ + u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + ATH5K_TRACE(ah->ah_sc); + + return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); +} + +/** + * ath5k_hw_reset_tsf - Force a TSF reset + * + * @ah: The &struct ath5k_hw + * + * Forces a TSF reset on PCU + */ +void ath5k_hw_reset_tsf(struct ath5k_hw *ah) +{ + u32 val; + + ATH5K_TRACE(ah->ah_sc); + + val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF; + + /* + * Each write to the RESET_TSF bit toggles a hardware internal + * signal to reset TSF, but if left high it will cause a TSF reset + * on the next chip reset as well. Thus we always write the value + * twice to clear the signal. + */ + ath5k_hw_reg_write(ah, val, AR5K_BEACON); + ath5k_hw_reg_write(ah, val, AR5K_BEACON); +} + +/* + * Initialize beacon timers + */ +void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) +{ + u32 timer1, timer2, timer3; + + ATH5K_TRACE(ah->ah_sc); + /* + * Set the additional timers by mode + */ + switch (ah->ah_op_mode) { + case NL80211_IFTYPE_STATION: + if (ah->ah_version == AR5K_AR5210) { + timer1 = 0xffffffff; + timer2 = 0xffffffff; + } else { + timer1 = 0x0000ffff; + timer2 = 0x0007ffff; + } + break; + + default: + timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; + timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; + } + + timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); + + /* + * Set the beacon register and enable all timers. + * (next beacon, DMA beacon, software beacon, ATIM window time) + */ + ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); + ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); + ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); + ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); + + ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | + AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), + AR5K_BEACON); +} + +#if 0 +/* + * Set beacon timers + */ +int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, + const struct ath5k_beacon_state *state) +{ + u32 cfp_period, next_cfp, dtim, interval, next_beacon; + + /* + * TODO: should be changed through *state + * review struct ath5k_beacon_state struct + * + * XXX: These are used for cfp period bellow, are they + * ok ? Is it O.K. for tsf here to be 0 or should we use + * get_tsf ? + */ + u32 dtim_count = 0; /* XXX */ + u32 cfp_count = 0; /* XXX */ + u32 tsf = 0; /* XXX */ + + ATH5K_TRACE(ah->ah_sc); + /* Return on an invalid beacon state */ + if (state->bs_interval < 1) + return -EINVAL; + + interval = state->bs_interval; + dtim = state->bs_dtim_period; + + /* + * PCF support? + */ + if (state->bs_cfp_period > 0) { + /* + * Enable PCF mode and set the CFP + * (Contention Free Period) and timer registers + */ + cfp_period = state->bs_cfp_period * state->bs_dtim_period * + state->bs_interval; + next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * + state->bs_interval; + + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_DEFAULT_ANTENNA | + AR5K_STA_ID1_PCF); + ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); + ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, + AR5K_CFP_DUR); + ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : + next_cfp)) << 3, AR5K_TIMER2); + } else { + /* Disable PCF mode */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_DEFAULT_ANTENNA | + AR5K_STA_ID1_PCF); + } + + /* + * Enable the beacon timer register + */ + ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); + + /* + * Start the beacon timers + */ + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) & + ~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | + AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, + AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, + AR5K_BEACON_PERIOD), AR5K_BEACON); + + /* + * Write new beacon miss threshold, if it appears to be valid + * XXX: Figure out right values for min <= bs_bmiss_threshold <= max + * and return if its not in range. We can test this by reading value and + * setting value to a largest value and seeing which values register. + */ + + AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, + state->bs_bmiss_threshold); + + /* + * Set sleep control register + * XXX: Didn't find this in 5210 code but since this register + * exists also in ar5k's 5210 headers i leave it as common code. + */ + AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, + (state->bs_sleep_duration - 3) << 3); + + /* + * Set enhanced sleep registers on 5212 + */ + if (ah->ah_version == AR5K_AR5212) { + if (state->bs_sleep_duration > state->bs_interval && + roundup(state->bs_sleep_duration, interval) == + state->bs_sleep_duration) + interval = state->bs_sleep_duration; + + if (state->bs_sleep_duration > dtim && (dtim == 0 || + roundup(state->bs_sleep_duration, dtim) == + state->bs_sleep_duration)) + dtim = state->bs_sleep_duration; + + if (interval > dtim) + return -EINVAL; + + next_beacon = interval == dtim ? state->bs_next_dtim : + state->bs_next_beacon; + + ath5k_hw_reg_write(ah, + AR5K_REG_SM((state->bs_next_dtim - 3) << 3, + AR5K_SLEEP0_NEXT_DTIM) | + AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | + AR5K_SLEEP0_ENH_SLEEP_EN | + AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); + + ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, + AR5K_SLEEP1_NEXT_TIM) | + AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); + + ath5k_hw_reg_write(ah, + AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | + AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); + } + + return 0; +} + +/* + * Reset beacon timers + */ +void ath5k_hw_reset_beacon(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + /* + * Disable beacon timer + */ + ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); + + /* + * Disable some beacon register values + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); + ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON); +} + +/* + * Wait for beacon queue to finish + */ +int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) +{ + unsigned int i; + int ret; + + ATH5K_TRACE(ah->ah_sc); + + /* 5210 doesn't have QCU*/ + if (ah->ah_version == AR5K_AR5210) { + /* + * Wait for beaconn queue to finish by checking + * Control Register and Beacon Status Register. + */ + for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) { + if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F) + || + !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F)) + break; + udelay(10); + } + + /* Timeout... */ + if (i <= 0) { + /* + * Re-schedule the beacon queue + */ + ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1); + ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, + AR5K_BCR); + + return -EIO; + } + ret = 0; + } else { + /*5211/5212*/ + ret = ath5k_hw_register_timeout(ah, + AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON), + AR5K_QCU_STS_FRMPENDCNT, 0, false); + + if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON)) + return -EIO; + } + + return ret; +} +#endif + + +/*********************\ +* Key table functions * +\*********************/ + +/* + * Reset a key entry on the table + */ +int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) +{ + unsigned int i; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); + + /* + * Set NULL encryption on AR5212+ + * + * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) + * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 + * + * Note2: Windows driver (ndiswrapper) sets this to + * 0x00000714 instead of 0x00000007 + */ + if (ah->ah_version > AR5K_AR5211) + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(entry)); + + return 0; +} + +/* + * Check if a table entry is valid + */ +int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + /* Check the validation flag at the end of the entry */ + return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) & + AR5K_KEYTABLE_VALID; +} + +/* + * Set a key entry on the table + */ +int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, + const struct ieee80211_key_conf *key, const u8 *mac) +{ + unsigned int i; + __le32 key_v[5] = {}; + u32 keytype; + + ATH5K_TRACE(ah->ah_sc); + + /* key->keylen comes in from mac80211 in bytes */ + + if (key->keylen > AR5K_KEYTABLE_SIZE / 8) + return -EOPNOTSUPP; + + switch (key->keylen) { + /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ + case 40 / 8: + memcpy(&key_v[0], key->key, 5); + keytype = AR5K_KEYTABLE_TYPE_40; + break; + + /* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit */ + case 104 / 8: + memcpy(&key_v[0], &key->key[0], 6); + memcpy(&key_v[2], &key->key[6], 6); + memcpy(&key_v[4], &key->key[12], 1); + keytype = AR5K_KEYTABLE_TYPE_104; + break; + /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ + case 128 / 8: + memcpy(&key_v[0], &key->key[0], 6); + memcpy(&key_v[2], &key->key[6], 6); + memcpy(&key_v[4], &key->key[12], 4); + keytype = AR5K_KEYTABLE_TYPE_128; + break; + + default: + return -EINVAL; /* shouldn't happen */ + } + + for (i = 0; i < ARRAY_SIZE(key_v); i++) + ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), + AR5K_KEYTABLE_OFF(entry, i)); + + ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); + + return ath5k_hw_set_key_lladdr(ah, entry, mac); +} + +int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) +{ + u32 low_id, high_id; + + ATH5K_TRACE(ah->ah_sc); + /* Invalid entry (key table overflow) */ + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + /* MAC may be NULL if it's a broadcast key. In this case no need to + * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */ + if (unlikely(mac == NULL)) { + low_id = 0xffffffff; + high_id = 0xffff | AR5K_KEYTABLE_VALID; + } else { + low_id = AR5K_LOW_ID(mac); + high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID; + } + + ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); + ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry)); + + return 0; +} + diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index fa0d47faf57..e43f6563e61 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -1,9 +1,9 @@ /* * PHY functions * - * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> - * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com> - * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> + * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +19,8 @@ * */ +#define _ATH5K_PHY + #include <linux/delay.h> #include "ath5k.h" @@ -2122,7 +2124,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - udelay(2300); + mdelay(2); /* * Set the channel (with AGC turned off) @@ -2501,3 +2503,5 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power) return ath5k_hw_txpower(ah, channel, power); } + +#undef _ATH5K_PHY diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c new file mode 100644 index 00000000000..01bf09176d2 --- /dev/null +++ b/drivers/net/wireless/ath5k/qcu.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * + * Permission to use, copy, modify, and 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. + * + */ + +/********************************************\ +Queue Control Unit, DFS Control Unit Functions +\********************************************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * Get properties for a transmit queue + */ +int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, + struct ath5k_txq_info *queue_info) +{ + ATH5K_TRACE(ah->ah_sc); + memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); + return 0; +} + +/* + * Set properties for a transmit queue + */ +int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, + const struct ath5k_txq_info *queue_info) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return -EIO; + + memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info)); + + /*XXX: Is this supported on 5210 ?*/ + if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA && + ((queue_info->tqi_subtype == AR5K_WME_AC_VI) || + (queue_info->tqi_subtype == AR5K_WME_AC_VO))) || + queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD) + ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; + + return 0; +} + +/* + * Initialize a transmit queue + */ +int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, + struct ath5k_txq_info *queue_info) +{ + unsigned int queue; + int ret; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Get queue by type + */ + /*5210 only has 2 queues*/ + if (ah->ah_version == AR5K_AR5210) { + switch (queue_type) { + case AR5K_TX_QUEUE_DATA: + queue = AR5K_TX_QUEUE_ID_NOQCU_DATA; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON; + break; + default: + return -EINVAL; + } + } else { + switch (queue_type) { + case AR5K_TX_QUEUE_DATA: + for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; + ah->ah_txq[queue].tqi_type != + AR5K_TX_QUEUE_INACTIVE; queue++) { + + if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) + return -EINVAL; + } + break; + case AR5K_TX_QUEUE_UAPSD: + queue = AR5K_TX_QUEUE_ID_UAPSD; + break; + case AR5K_TX_QUEUE_BEACON: + queue = AR5K_TX_QUEUE_ID_BEACON; + break; + case AR5K_TX_QUEUE_CAB: + queue = AR5K_TX_QUEUE_ID_CAB; + break; + case AR5K_TX_QUEUE_XR_DATA: + if (ah->ah_version != AR5K_AR5212) + ATH5K_ERR(ah->ah_sc, + "XR data queues only supported in" + " 5212!\n"); + queue = AR5K_TX_QUEUE_ID_XR_DATA; + break; + default: + return -EINVAL; + } + } + + /* + * Setup internal queue structure + */ + memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info)); + ah->ah_txq[queue].tqi_type = queue_type; + + if (queue_info != NULL) { + queue_info->tqi_type = queue_type; + ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info); + if (ret) + return ret; + } + + /* + * We use ah_txq_status to hold a temp value for + * the Secondary interrupt mask registers on 5211+ + * check out ath5k_hw_reset_tx_queue + */ + AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue); + + return queue; +} + +/* + * Get number of pending frames + * for a specific queue [5211+] + */ +u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* Return if queue is declared inactive */ + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return false; + + /* XXX: How about AR5K_CFG_TXCNT ? */ + if (ah->ah_version == AR5K_AR5210) + return false; + + return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT; +} + +/* + * Set a transmit queue inactive + */ +void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) +{ + ATH5K_TRACE(ah->ah_sc); + if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) + return; + + /* This queue will be skipped in further operations */ + ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE; + /*For SIMR setup*/ + AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); +} + +/* + * Set DFS properties for a transmit queue on DCU + */ +int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) +{ + u32 cw_min, cw_max, retry_lg, retry_sh; + struct ath5k_txq_info *tq = &ah->ah_txq[queue]; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + tq = &ah->ah_txq[queue]; + + if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE) + return 0; + + if (ah->ah_version == AR5K_AR5210) { + /* Only handle data queues, others will be ignored */ + if (tq->tqi_type != AR5K_TX_QUEUE_DATA) + return 0; + + /* Set Slot time */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME, + AR5K_SLOT_TIME); + /* Set ACK_CTS timeout */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + AR5K_INIT_ACK_CTS_TIMEOUT_TURBO : + AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME); + /* Set Transmit Latency */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + AR5K_INIT_TRANSMIT_LATENCY_TURBO : + AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210); + + /* Set IFS0 */ + if (ah->ah_turbo) { + ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO + + (ah->ah_aifs + tq->tqi_aifs) * + AR5K_INIT_SLOT_TIME_TURBO) << + AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO, + AR5K_IFS0); + } else { + ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS + + (ah->ah_aifs + tq->tqi_aifs) * + AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) | + AR5K_INIT_SIFS, AR5K_IFS0); + } + + /* Set IFS1 */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + AR5K_INIT_PROTO_TIME_CNTRL_TURBO : + AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1); + /* Set AR5K_PHY_SETTLING */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) + | 0x38 : + (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) + | 0x1C, + AR5K_PHY_SETTLING); + /* Set Frame Control Register */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE | + AR5K_PHY_TURBO_SHORT | 0x2020) : + (AR5K_PHY_FRAME_CTL_INI | 0x1020), + AR5K_PHY_FRAME_CTL_5210); + } + + /* + * Calculate cwmin/max by channel mode + */ + cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN; + cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX; + ah->ah_aifs = AR5K_TUNE_AIFS; + /*XR is only supported on 5212*/ + if (IS_CHAN_XR(ah->ah_current_channel) && + ah->ah_version == AR5K_AR5212) { + cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR; + cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR; + ah->ah_aifs = AR5K_TUNE_AIFS_XR; + /*B mode is not supported on 5210*/ + } else if (IS_CHAN_B(ah->ah_current_channel) && + ah->ah_version != AR5K_AR5210) { + cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B; + cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B; + ah->ah_aifs = AR5K_TUNE_AIFS_11B; + } + + cw_min = 1; + while (cw_min < ah->ah_cw_min) + cw_min = (cw_min << 1) | 1; + + cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) : + ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); + cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) : + ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1); + + /* + * Calculate and set retry limits + */ + if (ah->ah_software_retry) { + /* XXX Need to test this */ + retry_lg = ah->ah_limit_tx_retries; + retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? + AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg; + } else { + retry_lg = AR5K_INIT_LG_RETRY; + retry_sh = AR5K_INIT_SH_RETRY; + } + + /*No QCU/DCU [5210]*/ + if (ah->ah_version == AR5K_AR5210) { + ath5k_hw_reg_write(ah, + (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) + | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, + AR5K_NODCU_RETRY_LMT_SLG_RETRY) + | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, + AR5K_NODCU_RETRY_LMT_SSH_RETRY) + | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY) + | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY), + AR5K_NODCU_RETRY_LMT); + } else { + /*QCU/DCU [5211+]*/ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(AR5K_INIT_SLG_RETRY, + AR5K_DCU_RETRY_LMT_SLG_RETRY) | + AR5K_REG_SM(AR5K_INIT_SSH_RETRY, + AR5K_DCU_RETRY_LMT_SSH_RETRY) | + AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) | + AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY), + AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); + + /*===Rest is also for QCU/DCU only [5211+]===*/ + + /* + * Set initial content window (cw_min/cw_max) + * and arbitrated interframe space (aifs)... + */ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | + AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | + AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs, + AR5K_DCU_LCL_IFS_AIFS), + AR5K_QUEUE_DFS_LOCAL_IFS(queue)); + + /* + * Set misc registers + */ + ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY, + AR5K_QUEUE_MISC(queue)); + + if (tq->tqi_cbr_period) { + ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period, + AR5K_QCU_CBRCFG_INTVAL) | + AR5K_REG_SM(tq->tqi_cbr_overflow_limit, + AR5K_QCU_CBRCFG_ORN_THRES), + AR5K_QUEUE_CBRCFG(queue)); + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_FRSHED_CBR); + if (tq->tqi_cbr_overflow_limit) + AR5K_REG_ENABLE_BITS(ah, + AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_CBR_THRES_ENABLE); + } + + if (tq->tqi_ready_time) + ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, + AR5K_QCU_RDYTIMECFG_INTVAL) | + AR5K_QCU_RDYTIMECFG_ENABLE, + AR5K_QUEUE_RDYTIMECFG(queue)); + + if (tq->tqi_burst_time) { + ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time, + AR5K_DCU_CHAN_TIME_DUR) | + AR5K_DCU_CHAN_TIME_ENABLE, + AR5K_QUEUE_DFS_CHANNEL_TIME(queue)); + + if (tq->tqi_flags + & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) + AR5K_REG_ENABLE_BITS(ah, + AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_RDY_VEOL_POLICY); + } + + if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) + ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS, + AR5K_QUEUE_DFS_MISC(queue)); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) + ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG, + AR5K_QUEUE_DFS_MISC(queue)); + + /* + * Set registers by queue type + */ + switch (tq->tqi_type) { + case AR5K_TX_QUEUE_BEACON: + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_FRSHED_DBA_GT | + AR5K_QCU_MISC_CBREXP_BCN_DIS | + AR5K_QCU_MISC_BCN_ENABLE); + + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), + (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << + AR5K_DCU_MISC_ARBLOCK_CTL_S) | + AR5K_DCU_MISC_POST_FR_BKOFF_DIS | + AR5K_DCU_MISC_BCN_ENABLE); + + ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - + (AR5K_TUNE_SW_BEACON_RESP - + AR5K_TUNE_DMA_BEACON_RESP) - + AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | + AR5K_QCU_RDYTIMECFG_ENABLE, + AR5K_QUEUE_RDYTIMECFG(queue)); + break; + + case AR5K_TX_QUEUE_CAB: + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_FRSHED_DBA_GT | + AR5K_QCU_MISC_CBREXP_DIS | + AR5K_QCU_MISC_CBREXP_BCN_DIS); + + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), + (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << + AR5K_DCU_MISC_ARBLOCK_CTL_S)); + break; + + case AR5K_TX_QUEUE_UAPSD: + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_CBREXP_DIS); + break; + + case AR5K_TX_QUEUE_DATA: + default: + break; + } + + /* + * Enable interrupts for this tx queue + * in the secondary interrupt mask registers + */ + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); + + + /* Update secondary interrupt mask registers */ + ah->ah_txq_imr_txok &= ah->ah_txq_status; + ah->ah_txq_imr_txerr &= ah->ah_txq_status; + ah->ah_txq_imr_txurn &= ah->ah_txq_status; + ah->ah_txq_imr_txdesc &= ah->ah_txq_status; + ah->ah_txq_imr_txeol &= ah->ah_txq_status; + + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, + AR5K_SIMR0_QCU_TXOK) | + AR5K_REG_SM(ah->ah_txq_imr_txdesc, + AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr, + AR5K_SIMR1_QCU_TXERR) | + AR5K_REG_SM(ah->ah_txq_imr_txeol, + AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn, + AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2); + } + + return 0; +} + +/* + * Get slot time from DCU + */ +unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + if (ah->ah_version == AR5K_AR5210) + return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah, + AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo); + else + return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff; +} + +/* + * Set slot time on DCU + */ +int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) +{ + ATH5K_TRACE(ah->ah_sc); + if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX) + return -EINVAL; + + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time, + ah->ah_turbo), AR5K_SLOT_TIME); + else + ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT); + + return 0; +} + diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 7562bf173d3..e557fe178bb 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2007 Nick Kossifidis <mickflemm@gmail.com> - * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> - * Copyright (c) 2007 Michael Taylor <mike.taylor@apprion.com> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2007-2008 Michael Taylor <mike.taylor@apprion.com> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,6 +29,10 @@ * http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf * * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf + * + * This file also contains register values found on a memory dump of + * Atheros's ART program (Atheros Radio Test), on ath9k, on legacy-hal + * released by Atheros and on various debug messages found on the net. */ @@ -295,7 +299,7 @@ #define AR5K_ISR_RXPHY 0x00004000 /* PHY error */ #define AR5K_ISR_RXKCM 0x00008000 /* RX Key cache miss */ #define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */ -#define AR5K_ISR_BRSSI 0x00020000 +#define AR5K_ISR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ #define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ #define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ #define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ @@ -303,46 +307,56 @@ #define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */ #define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */ #define AR5K_ISR_DPERR 0x00400000 /* Det par Error (?) [5210] */ -#define AR5K_ISR_TIM 0x00800000 /* [5210] */ -#define AR5K_ISR_BCNMISC 0x00800000 /* [5212+] */ -#define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill)*/ -#define AR5K_ISR_QCBRORN 0x02000000 /* CBR overrun (?) [5211+] */ -#define AR5K_ISR_QCBRURN 0x04000000 /* CBR underrun (?) [5211+] */ -#define AR5K_ISR_QTRIG 0x08000000 /* [5211+] */ +#define AR5K_ISR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ +#define AR5K_ISR_TIM 0x00800000 /* [5211+] */ +#define AR5K_ISR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, + CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ +#define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill) */ +#define AR5K_ISR_QCBRORN 0x02000000 /* QCU CBR overrun [5211+] */ +#define AR5K_ISR_QCBRURN 0x04000000 /* QCU CBR underrun [5211+] */ +#define AR5K_ISR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ /* * Secondary status registers [5211+] (0 - 4) * - * I guess from the names that these give the status for each - * queue, that's why only masks are defined here, haven't got - * any info about them (couldn't find them anywhere in ar5k code). + * These give the status for each QCU, only QCUs 0-9 are + * represented. */ #define AR5K_SISR0 0x0084 /* Register Address [5211+] */ #define AR5K_SISR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ +#define AR5K_SISR0_QCU_TXOK_S 0 #define AR5K_SISR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ +#define AR5K_SISR0_QCU_TXDESC_S 16 #define AR5K_SISR1 0x0088 /* Register Address [5211+] */ #define AR5K_SISR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ +#define AR5K_SISR1_QCU_TXERR_S 0 #define AR5K_SISR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ +#define AR5K_SISR1_QCU_TXEOL_S 16 #define AR5K_SISR2 0x008c /* Register Address [5211+] */ #define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ +#define AR5K_SISR2_QCU_TXURN_S 0 #define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */ #define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */ -#define AR5K_SISR2_DPERR 0x00400000 /* Det par Error (?) */ +#define AR5K_SISR2_DPERR 0x00400000 /* Bus parity error */ #define AR5K_SISR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */ #define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ #define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ #define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */ +#define AR5K_SISR2_TSFOOR 0x80000000 /* TSF OOR (?) */ #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ +#define AR5K_SISR3_QCBORN_S 0 #define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ +#define AR5K_SISR3_QCBRURN_S 16 #define AR5K_SISR4 0x0094 /* Register Address [5211+] */ #define AR5K_SISR4_QTRIG 0x000003ff /* Mask for QTRIG */ +#define AR5K_SISR4_QTRIG_S 0 /* * Shadow read-and-clear interrupt status registers [5211+] @@ -379,7 +393,7 @@ #define AR5K_IMR_RXPHY 0x00004000 /* PHY error*/ #define AR5K_IMR_RXKCM 0x00008000 /* RX Key cache miss */ #define AR5K_IMR_SWBA 0x00010000 /* Software beacon alert*/ -#define AR5K_IMR_BRSSI 0x00020000 +#define AR5K_IMR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ #define AR5K_IMR_BMISS 0x00040000 /* Beacon missed*/ #define AR5K_IMR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ #define AR5K_IMR_BNR 0x00100000 /* Beacon not ready [5211+] */ @@ -387,12 +401,14 @@ #define AR5K_IMR_RXCHIRP 0x00200000 /* CHIRP Received [5212+]*/ #define AR5K_IMR_SSERR 0x00200000 /* Signaled System Error [5210] */ #define AR5K_IMR_DPERR 0x00400000 /* Det par Error (?) [5210] */ +#define AR5K_IMR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ #define AR5K_IMR_TIM 0x00800000 /* [5211+] */ -#define AR5K_IMR_BCNMISC 0x00800000 /* [5212+] */ +#define AR5K_IMR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, + CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ #define AR5K_IMR_GPIO 0x01000000 /* GPIO (rf kill)*/ -#define AR5K_IMR_QCBRORN 0x02000000 /* CBR overrun (?) [5211+] */ -#define AR5K_IMR_QCBRURN 0x04000000 /* CBR underrun (?) [5211+] */ -#define AR5K_IMR_QTRIG 0x08000000 /* [5211+] */ +#define AR5K_IMR_QCBRORN 0x02000000 /* QCU CBR overrun (?) [5211+] */ +#define AR5K_IMR_QCBRURN 0x04000000 /* QCU CBR underrun (?) [5211+] */ +#define AR5K_IMR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ /* * Secondary interrupt mask registers [5211+] (0 - 4) @@ -414,13 +430,14 @@ #define AR5K_SIMR2_QCU_TXURN_S 0 #define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */ #define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */ -#define AR5K_SIMR2_DPERR 0x00400000 /* Det par Error (?) */ +#define AR5K_SIMR2_DPERR 0x00400000 /* Bus parity error */ #define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */ #define AR5K_SIMR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ #define AR5K_SIMR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ #define AR5K_SIMR2_DTIM 0x20000000 /* [5212+] */ +#define AR5K_SIMR2_TSFOOR 0x80000000 /* TSF OOR (?) */ #define AR5K_SIMR3 0x00b0 /* Register Address [5211+] */ #define AR5K_SIMR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ @@ -586,15 +603,15 @@ #define AR5K_QCU_MISC_FRSHED_M 0x0000000f /* Frame sheduling mask */ #define AR5K_QCU_MISC_FRSHED_ASAP 0 /* ASAP */ #define AR5K_QCU_MISC_FRSHED_CBR 1 /* Constant Bit Rate */ -#define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated (?) */ -#define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* Time gated (?) */ -#define AR5K_QCU_MISC_FRSHED_BCN_SENT_GT 4 /* Beacon sent gated (?) */ +#define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated */ +#define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* TIMT gated */ +#define AR5K_QCU_MISC_FRSHED_BCN_SENT_GT 4 /* Beacon sent gated */ #define AR5K_QCU_MISC_ONESHOT_ENABLE 0x00000010 /* Oneshot enable */ -#define AR5K_QCU_MISC_CBREXP 0x00000020 /* CBR expired (normal queue) */ -#define AR5K_QCU_MISC_CBREXP_BCN 0x00000040 /* CBR expired (beacon queue) */ +#define AR5K_QCU_MISC_CBREXP_DIS 0x00000020 /* Disable CBR expired counter (normal queue) */ +#define AR5K_QCU_MISC_CBREXP_BCN_DIS 0x00000040 /* Disable CBR expired counter (beacon queue) */ #define AR5K_QCU_MISC_BCN_ENABLE 0x00000080 /* Enable Beacon use */ -#define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR threshold enabled */ -#define AR5K_QCU_MISC_RDY_VEOL_POLICY 0x00000200 /* TXE reset when RDYTIME enalbed */ +#define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR expired threshold enabled */ +#define AR5K_QCU_MISC_RDY_VEOL_POLICY 0x00000200 /* TXE reset when RDYTIME expired or VEOL */ #define AR5K_QCU_MISC_CBR_RESET_CNT 0x00000400 /* CBR threshold (counter) reset */ #define AR5K_QCU_MISC_DCU_EARLY 0x00000800 /* DCU early termination */ #define AR5K_QCU_MISC_DCU_CMP_EN 0x00001000 /* Enable frame compression */ @@ -663,6 +680,7 @@ #define AR5K_DCU_LCL_IFS_CW_MAX_S 10 #define AR5K_DCU_LCL_IFS_AIFS 0x0ff00000 /* Arbitrated Interframe Space */ #define AR5K_DCU_LCL_IFS_AIFS_S 20 +#define AR5K_DCU_LCL_IFS_AIFS_MAX 0xfc /* Anything above that can cause DCU to hang */ #define AR5K_QUEUE_DFS_LOCAL_IFS(_q) AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q) /* @@ -691,11 +709,7 @@ /* * DCU misc registers [5211+] * - * For some of the registers i couldn't find in the code - * (only backoff stuff is there realy) i tried to match the - * names with 802.11e parameters etc, so i guess VIRTCOL here - * means Virtual Collision and HCFPOLL means Hybrid Coordination - * factor Poll (CF- Poll). Arbiter lockout control controls the + * Note: Arbiter lockout control controls the * behaviour on low priority queues when we have multiple queues * with pending frames. Intra-frame lockout means we wait until * the queue's current frame transmits (with post frame backoff and bursting) @@ -705,15 +719,20 @@ * No lockout means there is no special handling. */ #define AR5K_DCU_MISC_BASE 0x1100 /* Register Address -Queue0 DCU_MISC */ -#define AR5K_DCU_MISC_BACKOFF 0x000007ff /* Mask for backoff threshold */ +#define AR5K_DCU_MISC_BACKOFF 0x0000003f /* Mask for backoff threshold */ +#define AR5K_DCU_MISC_ETS_RTS_POL 0x00000040 /* End of transmission series + station RTS/data failure count + reset policy (?) */ +#define AR5K_DCU_MISC_ETS_CW_POL 0x00000080 /* End of transmission series + CW reset policy */ +#define AR5K_DCU_MISC_FRAG_WAIT 0x00000100 /* Wait for next fragment */ #define AR5K_DCU_MISC_BACKOFF_FRAG 0x00000200 /* Enable backoff while bursting */ #define AR5K_DCU_MISC_HCFPOLL_ENABLE 0x00000800 /* CF - Poll enable */ #define AR5K_DCU_MISC_BACKOFF_PERSIST 0x00001000 /* Persistent backoff */ #define AR5K_DCU_MISC_FRMPRFTCH_ENABLE 0x00002000 /* Enable frame pre-fetch */ #define AR5K_DCU_MISC_VIRTCOL 0x0000c000 /* Mask for Virtual Collision (?) */ -#define AR5K_DCU_MISC_VIRTCOL_NORMAL 0 -#define AR5K_DCU_MISC_VIRTCOL_MODIFIED 1 -#define AR5K_DCU_MISC_VIRTCOL_IGNORE 2 +#define AR5K_DCU_MISC_VIRTCOL_NORMAL 0 +#define AR5K_DCU_MISC_VIRTCOL_IGNORE 1 #define AR5K_DCU_MISC_BCN_ENABLE 0x00010000 /* Enable Beacon use */ #define AR5K_DCU_MISC_ARBLOCK_CTL 0x00060000 /* Arbiter lockout control mask */ #define AR5K_DCU_MISC_ARBLOCK_CTL_S 17 @@ -768,8 +787,9 @@ #define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode */ #define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask */ #define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00 /* USEC Duration mask */ +#define AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S 10 #define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000 /* DCU Arbiter delay mask */ -#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST 0x00400000 /* SIFC cnt reset policy (?) */ +#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST 0x00400000 /* SIFS cnt reset policy (?) */ #define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST 0x00800000 /* AIFS cnt reset policy (?) */ #define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS 0x01000000 /* Disable random LFSR slice */ @@ -820,8 +840,6 @@ #define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) [5210] */ #define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset [5210] */ #define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */ -#define AR5K_RESET_CTL_CHIP (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA | \ - AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY) /* * Sleep control register @@ -833,9 +851,11 @@ #define AR5K_SLEEP_CTL_SLE_S 16 #define AR5K_SLEEP_CTL_SLE_WAKE 0x00000000 /* Force chip awake */ #define AR5K_SLEEP_CTL_SLE_SLP 0x00010000 /* Force chip sleep */ -#define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000 +#define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000 /* Normal sleep policy */ #define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* [5211+] */ -/* more bits */ +#define AR5K_SLEEP_CTL_DUR_TIM_POL 0x00040000 /* Sleep duration timing policy */ +#define AR5K_SLEEP_CTL_DUR_WRITE_POL 0x00080000 /* Sleep duration write policy */ +#define AR5K_SLEEP_CTL_SLE_POL 0x00100000 /* Sleep policy mode */ /* * Interrupt pending register @@ -851,27 +871,28 @@ /* * PCI configuration register + * TODO: Fix LED stuff */ #define AR5K_PCICFG 0x4010 /* Register Address */ #define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */ -#define AR5K_PCICFG_SLEEP_CLOCK_EN 0x00000002 /* Enable sleep clock (?) */ +#define AR5K_PCICFG_SLEEP_CLOCK_EN 0x00000002 /* Enable sleep clock */ #define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */ #define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */ #define AR5K_PCICFG_EESIZE_S 3 #define AR5K_PCICFG_EESIZE_4K 0 /* 4K */ #define AR5K_PCICFG_EESIZE_8K 1 /* 8K */ #define AR5K_PCICFG_EESIZE_16K 2 /* 16K */ -#define AR5K_PCICFG_EESIZE_FAIL 3 /* Failed to get size (?) [5211+] */ +#define AR5K_PCICFG_EESIZE_FAIL 3 /* Failed to get size [5211+] */ #define AR5K_PCICFG_LED 0x00000060 /* Led status [5211+] */ #define AR5K_PCICFG_LED_NONE 0x00000000 /* Default [5211+] */ #define AR5K_PCICFG_LED_PEND 0x00000020 /* Scan / Auth pending */ #define AR5K_PCICFG_LED_ASSOC 0x00000040 /* Associated */ #define AR5K_PCICFG_BUS_SEL 0x00000380 /* Mask for "bus select" [5211+] (?) */ -#define AR5K_PCICFG_CBEFIX_DIS 0x00000400 /* Disable CBE fix (?) */ -#define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep (?) */ +#define AR5K_PCICFG_CBEFIX_DIS 0x00000400 /* Disable CBE fix */ +#define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep */ #define AR5K_PCICFG_LED_BCTL 0x00001000 /* Led blink (?) [5210] */ -#define AR5K_PCICFG_UNK 0x00001000 /* Passed on some parts durring attach (?) */ -#define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even whith pending interrupts (?) */ +#define AR5K_PCICFG_RETRY_FIX 0x00001000 /* Enable pci core retry fix */ +#define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even whith pending interrupts*/ #define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status */ #define AR5K_PCICFG_LEDMODE 0x000e0000 /* Ledmode [5211+] */ #define AR5K_PCICFG_LEDMODE_PROP 0x00000000 /* Blink on standard traffic [5211+] */ @@ -884,7 +905,8 @@ #define AR5K_PCICFG_LEDSTATE \ (AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE | \ AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW) -#define AR5K_PCICFG_SLEEP_CLOCK_RATE 0x03000000 /* Sleep clock rate (field) */ +#define AR5K_PCICFG_SLEEP_CLOCK_RATE 0x03000000 /* Sleep clock rate */ +#define AR5K_PCICFG_SLEEP_CLOCK_RATE_S 24 /* * "General Purpose Input/Output" (GPIO) control register @@ -906,8 +928,8 @@ #define AR5K_GPIOCR 0x4014 /* Register Address */ #define AR5K_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO interrupt */ -#define AR5K_GPIOCR_INT_SELL 0x00000000 /* Generate interrupt when pin is off (?) */ -#define AR5K_GPIOCR_INT_SELH 0x00010000 /* Generate interrupt when pin is on */ +#define AR5K_GPIOCR_INT_SELL 0x00000000 /* Generate interrupt when pin is low */ +#define AR5K_GPIOCR_INT_SELH 0x00010000 /* Generate interrupt when pin is high */ #define AR5K_GPIOCR_IN(n) (0 << ((n) * 2)) /* Mode 0 for pin n */ #define AR5K_GPIOCR_OUT0(n) (1 << ((n) * 2)) /* Mode 1 for pin n */ #define AR5K_GPIOCR_OUT1(n) (2 << ((n) * 2)) /* Mode 2 for pin n */ @@ -925,7 +947,6 @@ #define AR5K_GPIODI 0x401c #define AR5K_GPIODI_M 0x0000002f - /* * Silicon revision register */ @@ -935,7 +956,59 @@ #define AR5K_SREV_VER 0x000000ff /* Mask for version */ #define AR5K_SREV_VER_S 4 +/* + * TXE write posting register + */ +#define AR5K_TXEPOST 0x4028 + +/* + * QCU sleep mask + */ +#define AR5K_QCU_SLEEP_MASK 0x402c + +/* 0x4068 is compression buffer configuration + * register on 5414 and pm configuration register + * on 5424 and newer pci-e chips. */ + +/* + * Compression buffer configuration + * register (enable/disable) [5414] + */ +#define AR5K_5414_CBCFG 0x4068 +#define AR5K_5414_CBCFG_BUF_DIS 0x10 /* Disable buffer */ + +/* + * PCI-E Power managment configuration + * and status register [5424+] + */ +#define AR5K_PCIE_PM_CTL 0x4068 /* Register address */ +/* Only 5424 */ +#define AR5K_PCIE_PM_CTL_L1_WHEN_D2 0x00000001 /* enable PCIe core enter L1 + when d2_sleep_en is asserted */ +#define AR5K_PCIE_PM_CTL_L0_L0S_CLEAR 0x00000002 /* Clear L0 and L0S counters */ +#define AR5K_PCIE_PM_CTL_L0_L0S_EN 0x00000004 /* Start L0 nd L0S counters */ +#define AR5K_PCIE_PM_CTL_LDRESET_EN 0x00000008 /* Enable reset when link goes + down */ +/* Wake On Wireless */ +#define AR5K_PCIE_PM_CTL_PME_EN 0x00000010 /* PME Enable */ +#define AR5K_PCIE_PM_CTL_AUX_PWR_DET 0x00000020 /* Aux power detect */ +#define AR5K_PCIE_PM_CTL_PME_CLEAR 0x00000040 /* Clear PME */ +#define AR5K_PCIE_PM_CTL_PSM_D0 0x00000080 +#define AR5K_PCIE_PM_CTL_PSM_D1 0x00000100 +#define AR5K_PCIE_PM_CTL_PSM_D2 0x00000200 +#define AR5K_PCIE_PM_CTL_PSM_D3 0x00000400 + +/* + * PCI-E Workaround enable register + */ +#define AR5K_PCIE_WAEN 0x407c +/* + * PCI-E Serializer/Desirializer + * registers + */ +#define AR5K_PCIE_SERDES 0x4080 +#define AR5K_PCIE_SERDES_RESET 0x4084 /*====EEPROM REGISTERS====*/ @@ -977,98 +1050,6 @@ #define AR5K_EEPROM_BASE 0x6000 /* - * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) - */ -#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ -#define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ -#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ -#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ -#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ - -#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ -#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ -#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ -#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ -#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 -#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ -#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 -#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ -#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 -#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ -#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 -#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ -#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 -#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ -#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 -#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ -#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 -#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ -#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ -#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) -#define AR5K_EEPROM_INFO_CKSUM 0xffff -#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n)) - -#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */ -#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */ -#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */ -#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */ -#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */ -#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */ -#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ -#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */ -#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */ -#define AR5K_EEPROM_VERSION_4_3 0x4003 -#define AR5K_EEPROM_VERSION_4_4 0x4004 -#define AR5K_EEPROM_VERSION_4_5 0x4005 -#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */ -#define AR5K_EEPROM_VERSION_4_7 0x4007 - -#define AR5K_EEPROM_MODE_11A 0 -#define AR5K_EEPROM_MODE_11B 1 -#define AR5K_EEPROM_MODE_11G 2 - -#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */ -#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) -#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) -#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) -#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */ -#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ -#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) -#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */ -#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ - -#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c -#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 -#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002 -#define AR5K_EEPROM_RFKILL_POLARITY_S 1 - -/* Newer EEPROMs are using a different offset */ -#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \ - (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0) - -#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3) -#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff)) -#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff)) - -/* calibration settings */ -#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4) -#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2) -#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d) -#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */ - -/* [3.1 - 3.3] */ -#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec -#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed - -/* Misc values available since EEPROM 4.0 */ -#define AR5K_EEPROM_MISC0 0x00c4 -#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) -#define AR5K_EEPROM_MISC1 0x00c5 -#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) - -/* * EEPROM data register */ #define AR5K_EEPROM_DATA_5211 0x6004 @@ -1100,14 +1081,28 @@ * EEPROM config register */ #define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ -#define AR5K_EEPROM_CFG_SIZE_OVR 0x00000001 +#define AR5K_EEPROM_CFG_SIZE 0x00000003 /* Size determination override */ +#define AR5K_EEPROM_CFG_SIZE_AUTO 0 +#define AR5K_EEPROM_CFG_SIZE_4KBIT 1 +#define AR5K_EEPROM_CFG_SIZE_8KBIT 2 +#define AR5K_EEPROM_CFG_SIZE_16KBIT 3 #define AR5K_EEPROM_CFG_WR_WAIT_DIS 0x00000004 /* Disable write wait */ #define AR5K_EEPROM_CFG_CLK_RATE 0x00000018 /* Clock rate */ -#define AR5K_EEPROM_CFG_PROT_KEY 0x00ffff00 /* Protectio key */ +#define AR5K_EEPROM_CFG_CLK_RATE_S 3 +#define AR5K_EEPROM_CFG_CLK_RATE_156KHZ 0 +#define AR5K_EEPROM_CFG_CLK_RATE_312KHZ 1 +#define AR5K_EEPROM_CFG_CLK_RATE_625KHZ 2 +#define AR5K_EEPROM_CFG_PROT_KEY 0x00ffff00 /* Protection key */ +#define AR5K_EEPROM_CFG_PROT_KEY_S 8 #define AR5K_EEPROM_CFG_LIND_EN 0x01000000 /* Enable length indicator (?) */ /* + * TODO: Wake On Wireless registers + * Range 0x7000 - 0x7ce0 + */ + +/* * Protocol Control Unit (PCU) registers */ /* @@ -1139,11 +1134,13 @@ #define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ #define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */ #define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS */ -#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate (for ACK/CTS ?) [5211+] */ -#define AR5K_STA_ID1_SELF_GEN_SECTORE 0x04000000 /* Self generate sectore (?) */ +#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK/CTS [5211+] */ +#define AR5K_STA_ID1_SELFGEN_DEF_ANT 0x04000000 /* Use def. antenna for self generated frames */ #define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */ -#define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Keysearch mode (?) */ +#define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Look up key when key id != 0 */ #define AR5K_STA_ID1_PRESERVE_SEQ_NUM 0x20000000 /* Preserve sequence number */ +#define AR5K_STA_ID1_CBCIV_ENDIAN 0x40000000 /* ??? */ +#define AR5K_STA_ID1_KEYSRCH_MCAST 0x80000000 /* Do key cache search for mcast frames */ /* * First BSSID register (MAC address, lower 32bits) @@ -1402,16 +1399,16 @@ #define AR5K_DIAG_SW_LOOP_BACK_5211 0x00000040 #define AR5K_DIAG_SW_LOOP_BACK (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211) -#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 +#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Corrupted FCS */ #define AR5K_DIAG_SW_CORR_FCS_5211 0x00000080 #define AR5K_DIAG_SW_CORR_FCS (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211) -#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 +#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Dump channel info */ #define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100 #define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211) -#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 /* Enable scrambler seed */ -#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210 0x00000400 +#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210 0x00000400 /* Enable fixed scrambler seed */ +#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 #define AR5K_DIAG_SW_EN_SCRAM_SEED (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211) #define AR5K_DIAG_SW_ECO_ENABLE 0x00000400 /* [5211+] */ @@ -1420,12 +1417,15 @@ #define AR5K_DIAG_SW_SCRAM_SEED_S 10 #define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */ #define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000 -#define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 +#define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 /* Accept frames of non-zero protocol number */ #define AR5K_DIAG_SW_FRAME_NV0 (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211) -#define AR5K_DIAG_SW_OBSPT_M 0x000c0000 +#define AR5K_DIAG_SW_OBSPT_M 0x000c0000 /* Observation point select (?) */ #define AR5K_DIAG_SW_OBSPT_S 18 -/* more bits */ +#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */ +#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */ +#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high */ +#define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */ /* * TSF (clock) register (lower 32 bits) @@ -1636,16 +1636,16 @@ * * XXX: PCDAC steps (0.5dbm) or DBM ? * - * XXX: Mask changes for newer chips to 7f - * like tx power table ? */ #define AR5K_TXPC 0x80e8 /* Register Address */ -#define AR5K_TXPC_ACK_M 0x0000003f /* Mask for ACK tx power */ +#define AR5K_TXPC_ACK_M 0x0000003f /* ACK tx power */ #define AR5K_TXPC_ACK_S 0 -#define AR5K_TXPC_CTS_M 0x00003f00 /* Mask for CTS tx power */ +#define AR5K_TXPC_CTS_M 0x00003f00 /* CTS tx power */ #define AR5K_TXPC_CTS_S 8 -#define AR5K_TXPC_CHIRP_M 0x003f0000 /* Mask for CHIRP tx power */ -#define AR5K_TXPC_CHIRP_S 22 +#define AR5K_TXPC_CHIRP_M 0x003f0000 /* CHIRP tx power */ +#define AR5K_TXPC_CHIRP_S 16 +#define AR5K_TXPC_DOPPLER 0x0f000000 /* Doppler chirp span (?) */ +#define AR5K_TXPC_DOPPLER_S 24 /* * Profile count registers @@ -1656,14 +1656,19 @@ #define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ /* - * Quiet (period) control registers (?) + * Quiet period control registers */ #define AR5K_QUIET_CTL1 0x80fc /* Register Address */ -#define AR5K_QUIET_CTL1_NEXT_QT 0x0000ffff /* Mask for next quiet (period?) (?) */ -#define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet (period?) */ +#define AR5K_QUIET_CTL1_NEXT_QT_TSF 0x0000ffff /* Next quiet period TSF (TU) */ +#define AR5K_QUIET_CTL1_NEXT_QT_TSF_S 0 +#define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet period */ +#define AR5K_QUIET_CTL1_ACK_CTS_EN 0x00020000 /* Send ACK/CTS during quiet period */ + #define AR5K_QUIET_CTL2 0x8100 /* Register Address */ -#define AR5K_QUIET_CTL2_QT_PER 0x0000ffff /* Mask for quiet period (?) */ -#define AR5K_QUIET_CTL2_QT_DUR 0xffff0000 /* Mask for quiet duration (?) */ +#define AR5K_QUIET_CTL2_QT_PER 0x0000ffff /* Mask for quiet period periodicity */ +#define AR5K_QUIET_CTL2_QT_PER_S 0 +#define AR5K_QUIET_CTL2_QT_DUR 0xffff0000 /* Mask for quiet period duration */ +#define AR5K_QUIET_CTL2_QT_DUR_S 16 /* * TSF parameter register @@ -1673,12 +1678,15 @@ #define AR5K_TSF_PARM_INC_S 0 /* - * QoS register (?) + * QoS NOACK policy */ -#define AR5K_QOS 0x8108 /* Register Address */ -#define AR5K_QOS_NOACK_2BIT_VALUES 0x00000000 /* (field) */ -#define AR5K_QOS_NOACK_BIT_OFFSET 0x00000020 /* (field) */ -#define AR5K_QOS_NOACK_BYTE_OFFSET 0x00000080 /* (field) */ +#define AR5K_QOS_NOACK 0x8108 /* Register Address */ +#define AR5K_QOS_NOACK_2BIT_VALUES 0x0000000f /* ??? */ +#define AR5K_QOS_NOACK_2BIT_VALUES_S 0 +#define AR5K_QOS_NOACK_BIT_OFFSET 0x00000070 /* ??? */ +#define AR5K_QOS_NOACK_BIT_OFFSET_S 4 +#define AR5K_QOS_NOACK_BYTE_OFFSET 0x00000180 /* ??? */ +#define AR5K_QOS_NOACK_BYTE_OFFSET_S 8 /* * PHY error filter register @@ -1702,29 +1710,15 @@ /* * MIC QoS control register (?) */ -#define AR5K_MIC_QOS_CTL 0x8118 /* Register Address */ -#define AR5K_MIC_QOS_CTL_0 0x00000001 /* MIC QoS control 0 (?) */ -#define AR5K_MIC_QOS_CTL_1 0x00000004 /* MIC QoS control 1 (?) */ -#define AR5K_MIC_QOS_CTL_2 0x00000010 /* MIC QoS control 2 (?) */ -#define AR5K_MIC_QOS_CTL_3 0x00000040 /* MIC QoS control 3 (?) */ -#define AR5K_MIC_QOS_CTL_4 0x00000100 /* MIC QoS control 4 (?) */ -#define AR5K_MIC_QOS_CTL_5 0x00000400 /* MIC QoS control 5 (?) */ -#define AR5K_MIC_QOS_CTL_6 0x00001000 /* MIC QoS control 6 (?) */ -#define AR5K_MIC_QOS_CTL_7 0x00004000 /* MIC QoS control 7 (?) */ -#define AR5K_MIC_QOS_CTL_MQ_EN 0x00010000 /* Enable MIC QoS */ +#define AR5K_MIC_QOS_CTL 0x8118 /* Register Address */ +#define AR5K_MIC_QOS_CTL_OFF(_n) (1 << (_n * 2)) +#define AR5K_MIC_QOS_CTL_MQ_EN 0x00010000 /* Enable MIC QoS */ /* * MIC QoS select register (?) */ -#define AR5K_MIC_QOS_SEL 0x811c -#define AR5K_MIC_QOS_SEL_0 0x00000001 -#define AR5K_MIC_QOS_SEL_1 0x00000010 -#define AR5K_MIC_QOS_SEL_2 0x00000100 -#define AR5K_MIC_QOS_SEL_3 0x00001000 -#define AR5K_MIC_QOS_SEL_4 0x00010000 -#define AR5K_MIC_QOS_SEL_5 0x00100000 -#define AR5K_MIC_QOS_SEL_6 0x01000000 -#define AR5K_MIC_QOS_SEL_7 0x10000000 +#define AR5K_MIC_QOS_SEL 0x811c +#define AR5K_MIC_QOS_SEL_OFF(_n) (1 << (_n * 4)) /* * Misc mode control register (?) @@ -1759,6 +1753,11 @@ #define AR5K_TSF_THRES 0x813c /* + * TODO: Wake On Wireless registers + * Range: 0x8147 - 0x818c + */ + +/* * Rate -> ACK SIFS mapping table (32 entries) */ #define AR5K_RATE_ACKSIFS_BASE 0x8680 /* Register Address */ @@ -1873,7 +1872,8 @@ */ #define AR5K_PHY_TURBO 0x9804 /* Register Address */ #define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */ -#define AR5K_PHY_TURBO_SHORT 0x00000002 /* Short mode (20Mhz channels) (?) */ +#define AR5K_PHY_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode */ +#define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo mimo */ /* * PHY agility command register @@ -1883,6 +1883,11 @@ #define AR5K_PHY_TST1 0x9808 #define AR5K_PHY_AGC_DISABLE 0x08000000 /* Disable AGC to A2 (?)*/ #define AR5K_PHY_TST1_TXHOLD 0x00003800 /* Set tx hold (?) */ +#define AR5K_PHY_TST1_TXSRC_SRC 0x00000002 /* Used with bit 7 (?) */ +#define AR5K_PHY_TST1_TXSRC_SRC_S 1 +#define AR5K_PHY_TST1_TXSRC_ALT 0x00000080 /* Set input to tsdac (?) */ +#define AR5K_PHY_TST1_TXSRC_ALT_S 7 + /* * PHY timing register 3 [5112+] @@ -1907,15 +1912,23 @@ /* * PHY RF control registers - * (i think these are delay times, - * these calibration values exist - * in EEPROM) */ #define AR5K_PHY_RF_CTL2 0x9824 /* Register Address */ -#define AR5K_PHY_RF_CTL2_TXF2TXD_START 0x0000000f /* Mask for TX frame to TX d(esc?) start */ +#define AR5K_PHY_RF_CTL2_TXF2TXD_START 0x0000000f /* TX frame to TX data start */ +#define AR5K_PHY_RF_CTL2_TXF2TXD_START_S 0 #define AR5K_PHY_RF_CTL3 0x9828 /* Register Address */ -#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000000f /* Mask for TX end to XLNA on */ +#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000000f /* TX end to XLNA on */ +#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S 0 + +#define AR5K_PHY_ADC_CTL 0x982c +#define AR5K_PHY_ADC_CTL_INBUFGAIN_OFF 0x00000003 +#define AR5K_PHY_ADC_CTL_INBUFGAIN_OFF_S 0 +#define AR5K_PHY_ADC_CTL_PWD_DAC_OFF 0x00002000 +#define AR5K_PHY_ADC_CTL_PWD_BAND_GAP_OFF 0x00004000 +#define AR5K_PHY_ADC_CTL_PWD_ADC_OFF 0x00008000 +#define AR5K_PHY_ADC_CTL_INBUFGAIN_ON 0x00030000 +#define AR5K_PHY_ADC_CTL_INBUFGAIN_ON_S 16 #define AR5K_PHY_RF_CTL4 0x9834 /* Register Address */ #define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON 0x00000001 /* TX frame to XPA A on (field) */ @@ -1937,35 +1950,43 @@ * PHY settling register */ #define AR5K_PHY_SETTLING 0x9844 /* Register Address */ -#define AR5K_PHY_SETTLING_AGC 0x0000007f /* Mask for AGC settling time */ -#define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Mask for Switch settlig time */ +#define AR5K_PHY_SETTLING_AGC 0x0000007f /* AGC settling time */ +#define AR5K_PHY_SETTLING_AGC_S 0 +#define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Switch settlig time */ +#define AR5K_PHY_SETTLINK_SWITCH_S 7 /* * PHY Gain registers */ #define AR5K_PHY_GAIN 0x9848 /* Register Address */ -#define AR5K_PHY_GAIN_TXRX_ATTEN 0x0003f000 /* Mask for TX-RX Attenuation */ +#define AR5K_PHY_GAIN_TXRX_ATTEN 0x0003f000 /* TX-RX Attenuation */ +#define AR5K_PHY_GAIN_TXRX_ATTEN_S 12 +#define AR5K_PHY_GAIN_TXRX_RF_MAX 0x007c0000 +#define AR5K_PHY_GAIN_TXRX_RF_MAX_S 18 #define AR5K_PHY_GAIN_OFFSET 0x984c /* Register Address */ #define AR5K_PHY_GAIN_OFFSET_RXTX_FLAG 0x00020000 /* RX-TX flag (?) */ /* - * Desired size register + * Desired ADC/PGA size register * (for more infos read ANI patent) */ #define AR5K_PHY_DESIRED_SIZE 0x9850 /* Register Address */ -#define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* Mask for ADC desired size */ -#define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* Mask for PGA desired size */ -#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Mask for Total desired size (?) */ +#define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* ADC desired size */ +#define AR5K_PHY_DESIRED_SIZE_ADC_S 0 +#define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* PGA desired size */ +#define AR5K_PHY_DESIRED_SIZE_PGA_S 8 +#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Total desired size */ +#define AR5K_PHY_DESIRED_SIZE_TOT_S 20 /* * PHY signal register * (for more infos read ANI patent) */ #define AR5K_PHY_SIG 0x9858 /* Register Address */ -#define AR5K_PHY_SIG_FIRSTEP 0x0003f000 /* Mask for FIRSTEP */ +#define AR5K_PHY_SIG_FIRSTEP 0x0003f000 /* FIRSTEP */ #define AR5K_PHY_SIG_FIRSTEP_S 12 -#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* Mask for FIPWR */ +#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* FIPWR */ #define AR5K_PHY_SIG_FIRPWR_S 18 /* @@ -1973,9 +1994,9 @@ * (for more infos read ANI patent) */ #define AR5K_PHY_AGCCOARSE 0x985c /* Register Address */ -#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* Mask for AGC Coarse low */ +#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* AGC Coarse low */ #define AR5K_PHY_AGCCOARSE_LO_S 7 -#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* Mask for AGC Coarse high */ +#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* AGC Coarse high */ #define AR5K_PHY_AGCCOARSE_HI_S 15 /* @@ -1984,6 +2005,8 @@ #define AR5K_PHY_AGCCTL 0x9860 /* Register address */ #define AR5K_PHY_AGCCTL_CAL 0x00000001 /* Enable PHY calibration */ #define AR5K_PHY_AGCCTL_NF 0x00000002 /* Enable Noise Floor calibration */ +#define AR5K_PHY_AGCCTL_NF_EN 0x00008000 /* Enable nf calibration to happen (?) */ +#define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */ /* * PHY noise floor status register @@ -1994,7 +2017,10 @@ #define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M) #define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1) #define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9)) -#define AR5K_PHY_NF_THRESH62 0x00001000 /* Thresh62 -check ANI patent- (field) */ +#define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */ +#define AR5K_PHY_NF_THRESH62_S 12 +#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* ??? */ +#define AR5K_PHY_NF_MINCCA_PWR_S 19 /* * PHY ADC saturation register [5110] @@ -2034,24 +2060,31 @@ */ #define AR5K_PHY_SCR 0x9870 #define AR5K_PHY_SCR_32MHZ 0x0000001f + #define AR5K_PHY_SLMT 0x9874 #define AR5K_PHY_SLMT_32MHZ 0x0000007f + #define AR5K_PHY_SCAL 0x9878 #define AR5K_PHY_SCAL_32MHZ 0x0000000e + /* * PHY PLL (Phase Locked Loop) control register */ #define AR5K_PHY_PLL 0x987c -#define AR5K_PHY_PLL_20MHZ 0x13 /* For half rate (?) [5111+] */ -#define AR5K_PHY_PLL_40MHZ_5211 0x18 /* For 802.11a */ +#define AR5K_PHY_PLL_20MHZ 0x00000013 /* For half rate (?) */ +/* 40MHz -> 5GHz band */ +#define AR5K_PHY_PLL_40MHZ_5211 0x00000018 #define AR5K_PHY_PLL_40MHZ_5212 0x000000aa +#define AR5K_PHY_PLL_40MHZ_5413 0x00000004 #define AR5K_PHY_PLL_40MHZ (ah->ah_version == AR5K_AR5211 ? \ AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212) -#define AR5K_PHY_PLL_44MHZ_5211 0x19 /* For 802.11b/g */ +/* 44MHz -> 2.4GHz band */ +#define AR5K_PHY_PLL_44MHZ_5211 0x00000019 #define AR5K_PHY_PLL_44MHZ_5212 0x000000ab #define AR5K_PHY_PLL_44MHZ (ah->ah_version == AR5K_AR5211 ? \ AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212) + #define AR5K_PHY_PLL_RF5111 0x00000000 #define AR5K_PHY_PLL_RF5112 0x00000040 #define AR5K_PHY_PLL_HALF_RATE 0x00000100 @@ -2118,6 +2151,19 @@ #define AR5K_PHY_RFSTG_DISABLE 0x00000021 /* + * BIN masks (?) + */ +#define AR5K_PHY_BIN_MASK_1 0x9900 +#define AR5K_PHY_BIN_MASK_2 0x9904 +#define AR5K_PHY_BIN_MASK_3 0x9908 + +#define AR5K_PHY_BIN_MASK_CTL 0x990c +#define AR5K_PHY_BIN_MASK_CTL_MASK_4 0x00003fff +#define AR5K_PHY_BIN_MASK_CTL_MASK_4_S 0 +#define AR5K_PHY_BIN_MASK_CTL_RATE 0xff000000 +#define AR5K_PHY_BIN_MASK_CTL_RATE_S 24 + +/* * PHY Antenna control register */ #define AR5K_PHY_ANT_CTL 0x9910 /* Register Address */ @@ -2164,6 +2210,7 @@ #define AR5K_PHY_OFDM_SELFCORR 0x9924 /* Register Address */ #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN 0x00000001 /* Enable cyclic RSSI thr 1 */ #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1 0x000000fe /* Mask for Cyclic RSSI threshold 1 */ +#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S 0 #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3 0x00000100 /* Cyclic RSSI threshold 3 (field) (?) */ #define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN 0x00008000 /* Enable 1A RSSI threshold (?) */ #define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR 0x00010000 /* 1A RSSI threshold (field) (?) */ @@ -2210,7 +2257,6 @@ #define AR5K_PHY_PAPD_PROBE_INI_5111 0x00004883 /* [5212+] */ #define AR5K_PHY_PAPD_PROBE_INI_5112 0x00004882 /* [5212+] */ - /* * PHY TX rate power registers [5112+] */ @@ -2232,6 +2278,8 @@ #define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038 /* Mask for tx clip (?) */ #define AR5K_PHY_FRAME_CTL_TX_CLIP_S 3 #define AR5K_PHY_FRAME_CTL_PREP_CHINFO 0x00010000 /* Prepend chan info */ +#define AR5K_PHY_FRAME_CTL_EMU 0x80000000 +#define AR5K_PHY_FRAME_CTL_EMU_S 31 /*---[5110/5111]---*/ #define AR5K_PHY_FRAME_CTL_TIMING_ERR 0x01000000 /* PHY timing error */ #define AR5K_PHY_FRAME_CTL_PARITY_ERR 0x02000000 /* Parity error */ @@ -2250,48 +2298,36 @@ * PHY radar detection register [5111+] */ #define AR5K_PHY_RADAR 0x9954 - -/* Radar enable ........ ........ ........ .......1 */ #define AR5K_PHY_RADAR_ENABLE 0x00000001 -#define AR5K_PHY_RADAR_DISABLE 0x00000000 -#define AR5K_PHY_RADAR_ENABLE_S 0 - -/* This is the value found on the card .1.111.1 .1.1.... 111....1 1...1... -at power on. */ -#define AR5K_PHY_RADAR_PWONDEF_AR5213 0x5d50e188 - -/* This is the value found on the card .1.1.111 ..11...1 .1...1.1 1...11.1 -after DFS is enabled */ -#define AR5K_PHY_RADAR_ENABLED_AR5213 0x5731458d - -/* Finite Impulse Response (FIR) filter .1111111 ........ ........ ........ - * power out threshold. - * 7-bits, standard power range {0..127} in 1/2 dBm units. */ -#define AR5K_PHY_RADAR_FIRPWROUTTHR 0x7f000000 -#define AR5K_PHY_RADAR_FIRPWROUTTHR_S 24 - -/* Radar RSSI/SNR threshold. ........ 111111.. ........ ........ - * 6-bits, dBm range {0..63} in dBm units. */ -#define AR5K_PHY_RADAR_RADARRSSITHR 0x00fc0000 -#define AR5K_PHY_RADAR_RADARRSSITHR_S 18 - -/* Pulse height threshold ........ ......11 1111.... ........ - * 6-bits, dBm range {0..63} in dBm units. */ -#define AR5K_PHY_RADAR_PULSEHEIGHTTHR 0x0003f000 -#define AR5K_PHY_RADAR_PULSEHEIGHTTHR_S 12 - -/* Pulse RSSI/SNR threshold ........ ........ ....1111 11...... - * 6-bits, dBm range {0..63} in dBm units. */ -#define AR5K_PHY_RADAR_PULSERSSITHR 0x00000fc0 -#define AR5K_PHY_RADAR_PULSERSSITHR_S 6 - -/* Inband threshold ........ ........ ........ ..11111. - * 5-bits, units unknown {0..31} (? MHz ?) */ -#define AR5K_PHY_RADAR_INBANDTHR 0x0000003e +#define AR5K_PHY_RADAR_DISABLE 0x00000000 +#define AR5K_PHY_RADAR_INBANDTHR 0x0000003e /* Inband threshold + 5-bits, units unknown {0..31} + (? MHz ?) */ #define AR5K_PHY_RADAR_INBANDTHR_S 1 +#define AR5K_PHY_RADAR_PRSSI_THR 0x00000fc0 /* Pulse RSSI/SNR threshold + 6-bits, dBm range {0..63} + in dBm units. */ +#define AR5K_PHY_RADAR_PRSSI_THR_S 6 + +#define AR5K_PHY_RADAR_PHEIGHT_THR 0x0003f000 /* Pulse height threshold + 6-bits, dBm range {0..63} + in dBm units. */ +#define AR5K_PHY_RADAR_PHEIGHT_THR_S 12 + +#define AR5K_PHY_RADAR_RSSI_THR 0x00fc0000 /* Radar RSSI/SNR threshold. + 6-bits, dBm range {0..63} + in dBm units. */ +#define AR5K_PHY_RADAR_RSSI_THR_S 18 + +#define AR5K_PHY_RADAR_FIRPWR_THR 0x7f000000 /* Finite Impulse Response + filter power out threshold. + 7-bits, standard power range + {0..127} in 1/2 dBm units. */ +#define AR5K_PHY_RADAR_FIRPWR_THRS 24 + /* - * PHY antenna switch table registers [5110] + * PHY antenna switch table registers */ #define AR5K_PHY_ANT_SWITCH_TABLE_0 0x9960 #define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964 @@ -2302,25 +2338,65 @@ after DFS is enabled */ #define AR5K_PHY_NFTHRES 0x9968 /* - * PHY clock sleep registers [5112+] + * Sigma Delta register (?) [5213] */ -#define AR5K_PHY_SCLOCK 0x99f0 -#define AR5K_PHY_SCLOCK_32MHZ 0x0000000c -#define AR5K_PHY_SDELAY 0x99f4 -#define AR5K_PHY_SDELAY_32MHZ 0x000000ff -#define AR5K_PHY_SPENDING 0x99f8 -#define AR5K_PHY_SPENDING_14 0x00000014 -#define AR5K_PHY_SPENDING_18 0x00000018 -#define AR5K_PHY_SPENDING_RF5111 0x00000018 -#define AR5K_PHY_SPENDING_RF5112 0x00000014 -/* #define AR5K_PHY_SPENDING_RF5112A 0x0000000e */ -/* #define AR5K_PHY_SPENDING_RF5424 0x00000012 */ -#define AR5K_PHY_SPENDING_RF5413 0x00000014 -#define AR5K_PHY_SPENDING_RF2413 0x00000014 -#define AR5K_PHY_SPENDING_RF2425 0x00000018 +#define AR5K_PHY_SIGMA_DELTA 0x996C +#define AR5K_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 +#define AR5K_PHY_SIGMA_DELTA_ADC_SEL_S 0 +#define AR5K_PHY_SIGMA_DELTA_FILT2 0x000000f8 +#define AR5K_PHY_SIGMA_DELTA_FILT2_S 3 +#define AR5K_PHY_SIGMA_DELTA_FILT1 0x00001f00 +#define AR5K_PHY_SIGMA_DELTA_FILT1_S 8 +#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP 0x01ff3000 +#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S 13 + +/* + * RF restart register [5112+] (?) + */ +#define AR5K_PHY_RESTART 0x9970 /* restart */ +#define AR5K_PHY_RESTART_DIV_GC 0x001c0000 /* Fast diversity gc_limit (?) */ +#define AR5K_PHY_RESTART_DIV_GC_S 18 + +/* + * RF Bus access request register (for synth-oly channel switching) + */ +#define AR5K_PHY_RFBUS_REQ 0x997C +#define AR5K_PHY_RFBUS_REQ_REQUEST 0x00000001 + +/* + * Spur mitigation masks (?) + */ +#define AR5K_PHY_TIMING_7 0x9980 +#define AR5K_PHY_TIMING_8 0x9984 +#define AR5K_PHY_TIMING_8_PILOT_MASK_2 0x000fffff +#define AR5K_PHY_TIMING_8_PILOT_MASK_2_S 0 + +#define AR5K_PHY_BIN_MASK2_1 0x9988 +#define AR5K_PHY_BIN_MASK2_2 0x998c +#define AR5K_PHY_BIN_MASK2_3 0x9990 + +#define AR5K_PHY_BIN_MASK2_4 0x9994 +#define AR5K_PHY_BIN_MASK2_4_MASK_4 0x00003fff +#define AR5K_PHY_BIN_MASK2_4_MASK_4_S 0 + +#define AR_PHY_TIMING_9 0x9998 +#define AR_PHY_TIMING_10 0x999c +#define AR_PHY_TIMING_10_PILOT_MASK_2 0x000fffff +#define AR_PHY_TIMING_10_PILOT_MASK_2_S 0 + +/* + * Spur mitigation control + */ +#define AR_PHY_TIMING_11 0x99a0 /* Register address */ +#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE 0x000fffff /* Spur delta phase */ +#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE_S 0 +#define AR_PHY_TIMING_11_SPUR_FREQ_SD 0x3ff00000 /* Freq sigma delta */ +#define AR_PHY_TIMING_11_SPUR_FREQ_SD_S 20 +#define AR_PHY_TIMING_11_USE_SPUR_IN_AGC 0x40000000 /* Spur filter in AGC detector */ +#define AR_PHY_TIMING_11_USE_SPUR_IN_SELFCOR 0x80000000 /* Spur filter in OFDM self correlator */ /* - * Misc PHY/radio registers [5110 - 5111] + * Gain tables */ #define AR5K_BB_GAIN_BASE 0x9b00 /* BaseBand Amplifier Gain table base address */ #define AR5K_BB_GAIN(_n) (AR5K_BB_GAIN_BASE + ((_n) << 2)) @@ -2340,9 +2416,10 @@ after DFS is enabled */ #define AR5K_PHY_CURRENT_RSSI 0x9c1c /* - * PHY RF Bus grant register (?) + * PHY RF Bus grant register */ #define AR5K_PHY_RFBUS_GRANT 0x9c20 +#define AR5K_PHY_RFBUS_GRANT_OK 0x00000001 /* * PHY ADC test register @@ -2386,6 +2463,31 @@ after DFS is enabled */ #define AR5K_PHY_CHAN_STATUS_RX_CLR_PAP 0x00000008 /* + * Heavy clip enable register + */ +#define AR5K_PHY_HEAVY_CLIP_ENABLE 0x99e0 + +/* + * PHY clock sleep registers [5112+] + */ +#define AR5K_PHY_SCLOCK 0x99f0 +#define AR5K_PHY_SCLOCK_32MHZ 0x0000000c +#define AR5K_PHY_SDELAY 0x99f4 +#define AR5K_PHY_SDELAY_32MHZ 0x000000ff +#define AR5K_PHY_SPENDING 0x99f8 +#define AR5K_PHY_SPENDING_14 0x00000014 +#define AR5K_PHY_SPENDING_18 0x00000018 +#define AR5K_PHY_SPENDING_RF5111 0x00000018 +#define AR5K_PHY_SPENDING_RF5112 0x00000014 +/* #define AR5K_PHY_SPENDING_RF5112A 0x0000000e */ +/* #define AR5K_PHY_SPENDING_RF5424 0x00000012 */ +#define AR5K_PHY_SPENDING_RF5413 0x00000018 +#define AR5K_PHY_SPENDING_RF2413 0x00000018 +#define AR5K_PHY_SPENDING_RF2316 0x00000018 +#define AR5K_PHY_SPENDING_RF2317 0x00000018 +#define AR5K_PHY_SPENDING_RF2425 0x00000014 + +/* * PHY PAPD I (power?) table (?) * (92! entries) */ @@ -2436,10 +2538,47 @@ after DFS is enabled */ #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000000f #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S 0 +/* Same address is used for antenna diversity activation */ +#define AR5K_PHY_FAST_ANT_DIV 0xa208 +#define AR5K_PHY_FAST_ANT_DIV_EN 0x00002000 + /* * PHY 2GHz gain register [5111+] */ -#define AR5K_PHY_GAIN_2GHZ 0xa20c -#define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX 0x00fc0000 +#define AR5K_PHY_GAIN_2GHZ 0xa20c +#define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX 0x00fc0000 #define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S 18 -#define AR5K_PHY_GAIN_2GHZ_INI_5111 0x6480416c +#define AR5K_PHY_GAIN_2GHZ_INI_5111 0x6480416c + +#define AR5K_PHY_CCK_RX_CTL_4 0xa21c +#define AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT 0x01f80000 +#define AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT_S 19 + +#define AR5K_PHY_DAG_CCK_CTL 0xa228 +#define AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR 0x00000200 +#define AR5K_PHY_DAG_CCK_CTL_RSSI_THR 0x0001fc00 +#define AR5K_PHY_DAG_CCK_CTL_RSSI_THR_S 10 + +#define AR5K_PHY_FAST_ADC 0xa24c + +#define AR5K_PHY_BLUETOOTH 0xa254 + +/* + * Transmit Power Control register + * [2413+] + */ +#define AR5K_PHY_TPC_RG1 0xa258 +#define AR5K_PHY_TPC_RG1_NUM_PD_GAIN 0x0000c000 +#define AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S 14 + +#define AR5K_PHY_TPC_RG5 0xa26C +#define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP 0x0000000F +#define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP_S 0 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1 0x000003F0 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1_S 4 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2 0x0000FC00 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2_S 10 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3 0x003F0000 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S 16 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4 0x0FC00000 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S 22 diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c new file mode 100644 index 00000000000..8f1886834e6 --- /dev/null +++ b/drivers/net/wireless/ath5k/reset.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu> + * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org> + * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> + * + * Permission to use, copy, modify, and 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. + * + */ + +#define _ATH5K_RESET + +/*****************************\ + Reset functions and helpers +\*****************************/ + +#include <linux/pci.h> +#include "ath5k.h" +#include "reg.h" +#include "base.h" +#include "debug.h" + +/** + * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 + * + * @ah: the &struct ath5k_hw + * @channel: the currently set channel upon reset + * + * Write the OFDM timings for the AR5212 upon reset. This is a helper for + * ath5k_hw_reset(). This seems to tune the PLL a specified frequency + * depending on the bandwidth of the channel. + * + */ +static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + /* Get exponent and mantissa and set it */ + u32 coef_scaled, coef_exp, coef_man, + ds_coef_exp, ds_coef_man, clock; + + if (!(ah->ah_version == AR5K_AR5212) || + !(channel->hw_value & CHANNEL_OFDM)) + BUG(); + + /* Seems there are two PLLs, one for baseband sampling and one + * for tuning. Tuning basebands are 40 MHz or 80MHz when in + * turbo. */ + clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40; + coef_scaled = ((5 * (clock << 24)) / 2) / + channel->center_freq; + + for (coef_exp = 31; coef_exp > 0; coef_exp--) + if ((coef_scaled >> coef_exp) & 0x1) + break; + + if (!coef_exp) + return -EINVAL; + + coef_exp = 14 - (coef_exp - 24); + coef_man = coef_scaled + + (1 << (24 - coef_exp - 1)); + ds_coef_man = coef_man >> (24 - coef_exp); + ds_coef_exp = coef_exp - 16; + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, + AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, + AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp); + + return 0; +} + + +/* + * index into rates for control rates, we can set it up like this because + * this is only used for AR5212 and we know it supports G mode + */ +static int control_rates[] = + { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 }; + +/** + * ath5k_hw_write_rate_duration - set rate duration during hw resets + * + * @ah: the &struct ath5k_hw + * @mode: one of enum ath5k_driver_mode + * + * Write the rate duration table upon hw reset. This is a helper for + * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout for + * the hardware for the current mode for each rate. The rates which are capable + * of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have another + * register for the short preamble ACK timeout calculation. + */ +static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, + unsigned int mode) +{ + struct ath5k_softc *sc = ah->ah_sc; + struct ieee80211_rate *rate; + unsigned int i; + + /* Write rate duration table */ + for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) { + u32 reg; + u16 tx_time; + + rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]]; + + /* Set ACK timeout */ + reg = AR5K_RATE_DUR(rate->hw_value); + + /* An ACK frame consists of 10 bytes. If you add the FCS, + * which ieee80211_generic_frame_duration() adds, + * its 14 bytes. Note we use the control rate and not the + * actual rate for this rate. See mac80211 tx.c + * ieee80211_duration() for a brief description of + * what rate we should choose to TX ACKs. */ + tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, + sc->vif, 10, rate)); + + ath5k_hw_reg_write(ah, tx_time, reg); + + if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) + continue; + + /* + * We're not distinguishing short preamble here, + * This is true, all we'll get is a longer value here + * which is not necessarilly bad. We could use + * export ieee80211_frame_duration() but that needs to be + * fixed first to be properly used by mac802111 drivers: + * + * - remove erp stuff and let the routine figure ofdm + * erp rates + * - remove passing argument ieee80211_local as + * drivers don't have access to it + * - move drivers using ieee80211_generic_frame_duration() + * to this + */ + ath5k_hw_reg_write(ah, tx_time, + reg + (AR5K_SET_SHORT_PREAMBLE << 2)); + } +} + +/* + * Reset chipset + */ +static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) +{ + int ret; + u32 mask = val ? val : ~0U; + + ATH5K_TRACE(ah->ah_sc); + + /* Read-and-clear RX Descriptor Pointer*/ + ath5k_hw_reg_read(ah, AR5K_RXDP); + + /* + * Reset the device and wait until success + */ + ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); + + /* Wait at least 128 PCI clocks */ + udelay(15); + + if (ah->ah_version == AR5K_AR5210) { + val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA + | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY; + mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA + | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY; + } else { + val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; + mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; + } + + ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false); + + /* + * Reset configuration register (for hw byte-swap). Note that this + * is only set for big endian. We do the necessary magic in + * AR5K_INIT_CFG. + */ + if ((val & AR5K_RESET_CTL_PCU) == 0) + ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG); + + return ret; +} + +/* + * Sleep control + */ +int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, + bool set_chip, u16 sleep_duration) +{ + unsigned int i; + u32 staid, data; + + ATH5K_TRACE(ah->ah_sc); + staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); + + switch (mode) { + case AR5K_PM_AUTO: + staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; + /* fallthrough */ + case AR5K_PM_NETWORK_SLEEP: + if (set_chip) + ath5k_hw_reg_write(ah, + AR5K_SLEEP_CTL_SLE_ALLOW | + sleep_duration, + AR5K_SLEEP_CTL); + + staid |= AR5K_STA_ID1_PWR_SV; + break; + + case AR5K_PM_FULL_SLEEP: + if (set_chip) + ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP, + AR5K_SLEEP_CTL); + + staid |= AR5K_STA_ID1_PWR_SV; + break; + + case AR5K_PM_AWAKE: + + staid &= ~AR5K_STA_ID1_PWR_SV; + + if (!set_chip) + goto commit; + + /* Preserve sleep duration */ + data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); + if (data & 0xffc00000) + data = 0; + else + data = data & 0xfffcffff; + + ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); + udelay(15); + + for (i = 50; i > 0; i--) { + /* Check if the chip did wake up */ + if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & + AR5K_PCICFG_SPWR_DN) == 0) + break; + + /* Wait a bit and retry */ + udelay(200); + ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); + } + + /* Fail if the chip didn't wake up */ + if (i <= 0) + return -EIO; + + break; + + default: + return -EINVAL; + } + +commit: + ah->ah_power_mode = mode; + ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1); + + return 0; +} + +/* + * Bring up MAC + PHY Chips + */ +int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) +{ + struct pci_dev *pdev = ah->ah_sc->pdev; + u32 turbo, mode, clock, bus_flags; + int ret; + + turbo = 0; + mode = 0; + clock = 0; + + ATH5K_TRACE(ah->ah_sc); + + /* Wakeup the device */ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n"); + return ret; + } + + if (ah->ah_version != AR5K_AR5210) { + /* + * Get channel mode flags + */ + + if (ah->ah_radio >= AR5K_RF5112) { + mode = AR5K_PHY_MODE_RAD_RF5112; + clock = AR5K_PHY_PLL_RF5112; + } else { + mode = AR5K_PHY_MODE_RAD_RF5111; /*Zero*/ + clock = AR5K_PHY_PLL_RF5111; /*Zero*/ + } + + if (flags & CHANNEL_2GHZ) { + mode |= AR5K_PHY_MODE_FREQ_2GHZ; + clock |= AR5K_PHY_PLL_44MHZ; + + if (flags & CHANNEL_CCK) { + mode |= AR5K_PHY_MODE_MOD_CCK; + } else if (flags & CHANNEL_OFDM) { + /* XXX Dynamic OFDM/CCK is not supported by the + * AR5211 so we set MOD_OFDM for plain g (no + * CCK headers) operation. We need to test + * this, 5211 might support ofdm-only g after + * all, there are also initial register values + * in the code for g mode (see initvals.c). */ + if (ah->ah_version == AR5K_AR5211) + mode |= AR5K_PHY_MODE_MOD_OFDM; + else + mode |= AR5K_PHY_MODE_MOD_DYN; + } else { + ATH5K_ERR(ah->ah_sc, + "invalid radio modulation mode\n"); + return -EINVAL; + } + } else if (flags & CHANNEL_5GHZ) { + mode |= AR5K_PHY_MODE_FREQ_5GHZ; + clock |= AR5K_PHY_PLL_40MHZ; + + if (flags & CHANNEL_OFDM) + mode |= AR5K_PHY_MODE_MOD_OFDM; + else { + ATH5K_ERR(ah->ah_sc, + "invalid radio modulation mode\n"); + return -EINVAL; + } + } else { + ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n"); + return -EINVAL; + } + + if (flags & CHANNEL_TURBO) + turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT; + } else { /* Reset the device */ + + /* ...enable Atheros turbo mode if requested */ + if (flags & CHANNEL_TURBO) + ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE, + AR5K_PHY_TURBO); + } + + /* reseting PCI on PCI-E cards results card to hang + * and always return 0xffff... so we ingore that flag + * for PCI-E cards */ + bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; + + /* Reset chipset */ + if (ah->ah_version == AR5K_AR5210) { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | + AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); + mdelay(2); + } else { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_BASEBAND | bus_flags); + } + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); + return -EIO; + } + + /* ...wakeup again!*/ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); + return ret; + } + + /* ...final warm reset */ + if (ath5k_hw_nic_reset(ah, 0)) { + ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); + return -EIO; + } + + if (ah->ah_version != AR5K_AR5210) { + /* ...set the PHY operating mode */ + ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); + udelay(300); + + ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE); + ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO); + } + + return 0; +} + +/* + * Main reset function + */ +int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, + struct ieee80211_channel *channel, bool change_channel) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct pci_dev *pdev = ah->ah_sc->pdev; + u32 data, s_seq, s_ant, s_led[3], dma_size; + unsigned int i, mode, freq, ee_mode, ant[2]; + int ret; + + ATH5K_TRACE(ah->ah_sc); + + s_seq = 0; + s_ant = 0; + ee_mode = 0; + freq = 0; + mode = 0; + + /* + * Save some registers before a reset + */ + /*DCU/Antenna selection not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + if (change_channel) { + /* Seq number for queue 0 -do this for all queues ? */ + s_seq = ath5k_hw_reg_read(ah, + AR5K_QUEUE_DFS_SEQNUM(0)); + /*Default antenna*/ + s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); + } + } + + /*GPIOs*/ + s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE; + s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); + s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); + + if (change_channel && ah->ah_rf_banks != NULL) + ath5k_hw_get_rf_gain(ah); + + + /*Wakeup the device*/ + ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); + if (ret) + return ret; + + /* + * Initialize operating mode + */ + ah->ah_op_mode = op_mode; + + /* + * 5111/5112 Settings + * 5210 only comes with RF5110 + */ + if (ah->ah_version != AR5K_AR5210) { + if (ah->ah_radio != AR5K_RF5111 && + ah->ah_radio != AR5K_RF5112 && + ah->ah_radio != AR5K_RF5413 && + ah->ah_radio != AR5K_RF2413 && + ah->ah_radio != AR5K_RF2425) { + ATH5K_ERR(ah->ah_sc, + "invalid phy radio: %u\n", ah->ah_radio); + return -EINVAL; + } + + switch (channel->hw_value & CHANNEL_MODES) { + case CHANNEL_A: + mode = AR5K_MODE_11A; + freq = AR5K_INI_RFGAIN_5GHZ; + ee_mode = AR5K_EEPROM_MODE_11A; + break; + case CHANNEL_G: + mode = AR5K_MODE_11G; + freq = AR5K_INI_RFGAIN_2GHZ; + ee_mode = AR5K_EEPROM_MODE_11G; + break; + case CHANNEL_B: + mode = AR5K_MODE_11B; + freq = AR5K_INI_RFGAIN_2GHZ; + ee_mode = AR5K_EEPROM_MODE_11B; + break; + case CHANNEL_T: + mode = AR5K_MODE_11A_TURBO; + freq = AR5K_INI_RFGAIN_5GHZ; + ee_mode = AR5K_EEPROM_MODE_11A; + break; + /*Is this ok on 5211 too ?*/ + case CHANNEL_TG: + mode = AR5K_MODE_11G_TURBO; + freq = AR5K_INI_RFGAIN_2GHZ; + ee_mode = AR5K_EEPROM_MODE_11G; + break; + case CHANNEL_XR: + if (ah->ah_version == AR5K_AR5211) { + ATH5K_ERR(ah->ah_sc, + "XR mode not available on 5211"); + return -EINVAL; + } + mode = AR5K_MODE_XR; + freq = AR5K_INI_RFGAIN_5GHZ; + ee_mode = AR5K_EEPROM_MODE_11A; + break; + default: + ATH5K_ERR(ah->ah_sc, + "invalid channel: %d\n", channel->center_freq); + return -EINVAL; + } + + /* PHY access enable */ + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); + + } + + ret = ath5k_hw_write_initvals(ah, mode, change_channel); + if (ret) + return ret; + + /* + * 5211/5212 Specific + */ + if (ah->ah_version != AR5K_AR5210) { + /* + * Write initial RF gain settings + * This should work for both 5111/5112 + */ + ret = ath5k_hw_rfgain(ah, freq); + if (ret) + return ret; + + mdelay(1); + + /* + * Write some more initial register settings + */ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0x0002a002, 0x982c); + + if (channel->hw_value == CHANNEL_G) + if (ah->ah_mac_srev < AR5K_SREV_AR2413) + ath5k_hw_reg_write(ah, 0x00f80d80, + 0x994c); + else if (ah->ah_mac_srev < AR5K_SREV_AR5424) + ath5k_hw_reg_write(ah, 0x00380140, + 0x994c); + else if (ah->ah_mac_srev < AR5K_SREV_AR2425) + ath5k_hw_reg_write(ah, 0x00fc0ec0, + 0x994c); + else /* 2425 */ + ath5k_hw_reg_write(ah, 0x00fc0fc0, + 0x994c); + else + ath5k_hw_reg_write(ah, 0x00000000, 0x994c); + + /* Some bits are disabled here, we know nothing about + * register 0xa228 yet, most of the times this ends up + * with a value 0x9b5 -haven't seen any dump with + * a different value- */ + /* Got this from decompiling binary HAL */ + data = ath5k_hw_reg_read(ah, 0xa228); + data &= 0xfffffdff; + ath5k_hw_reg_write(ah, data, 0xa228); + + data = ath5k_hw_reg_read(ah, 0xa228); + data &= 0xfffe03ff; + ath5k_hw_reg_write(ah, data, 0xa228); + data = 0; + + /* Just write 0x9b5 ? */ + /* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */ + ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK); + ath5k_hw_reg_write(ah, 0x00000000, 0xa254); + ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL); + } + + /* Fix for first revision of the RF5112 RF chipset */ + if (ah->ah_radio >= AR5K_RF5112 && + ah->ah_radio_5ghz_revision < + AR5K_SREV_RAD_5112A) { + ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, + AR5K_PHY_CCKTXCTL); + if (channel->hw_value & CHANNEL_5GHZ) + data = 0xffb81020; + else + data = 0xffb80d20; + ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL); + data = 0; + } + + /* + * Set TX power (FIXME) + */ + ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER); + if (ret) + return ret; + + /* Write rate duration table only on AR5212 and if + * virtual interface has already been brought up + * XXX: rethink this after new mode changes to + * mac80211 are integrated */ + if (ah->ah_version == AR5K_AR5212 && + ah->ah_sc->vif != NULL) + ath5k_hw_write_rate_duration(ah, mode); + + /* + * Write RF registers + */ + ret = ath5k_hw_rfregs(ah, channel, mode); + if (ret) + return ret; + + /* + * Configure additional registers + */ + + /* Write OFDM timings on 5212*/ + if (ah->ah_version == AR5K_AR5212 && + channel->hw_value & CHANNEL_OFDM) { + ret = ath5k_hw_write_ofdm_timings(ah, channel); + if (ret) + return ret; + } + + /*Enable/disable 802.11b mode on 5111 + (enable 2111 frequency converter + CCK)*/ + if (ah->ah_radio == AR5K_RF5111) { + if (mode == AR5K_MODE_11B) + AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_B_MODE); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_B_MODE); + } + + /* + * Set channel and calibrate the PHY + */ + ret = ath5k_hw_channel(ah, channel); + if (ret) + return ret; + + /* Set antenna mode */ + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL, + ah->ah_antenna[ee_mode][0], 0xfffffc06); + + /* + * In case a fixed antenna was set as default + * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE + * registers. + */ + if (s_ant != 0) { + if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */ + ant[0] = ant[1] = AR5K_ANT_FIXED_A; + else /* 2 - Aux */ + ant[0] = ant[1] = AR5K_ANT_FIXED_B; + } else { + ant[0] = AR5K_ANT_FIXED_A; + ant[1] = AR5K_ANT_FIXED_B; + } + + ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]], + AR5K_PHY_ANT_SWITCH_TABLE_0); + ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]], + AR5K_PHY_ANT_SWITCH_TABLE_1); + + /* Commit values from EEPROM */ + if (ah->ah_radio == AR5K_RF5111) + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, + AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip); + + ath5k_hw_reg_write(ah, + AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), + AR5K_PHY_NFTHRES); + + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING, + (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, + 0xffffc07f); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN, + (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, + 0xfffc0fff); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, + (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | + ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00), + 0xffff0000); + + ath5k_hw_reg_write(ah, + (ee->ee_tx_end2xpa_disable[ee_mode] << 24) | + (ee->ee_tx_end2xpa_disable[ee_mode] << 16) | + (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) | + (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4); + + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3, + ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF, + (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01); + + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_CORR_ENABLE | + (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) | + ee->ee_q_cal[ee_mode]); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ, + AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX, + ee->ee_margin_tx_rx[ee_mode]); + + } else { + mdelay(1); + /* Disable phy and wait */ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); + mdelay(1); + } + + /* + * Restore saved values + */ + /*DCU/Antenna selection not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0)); + ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); + } + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]); + ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR); + ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); + + /* + * Misc + */ + /* XXX: add ah->aid once mac80211 gives this to us */ + ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + + ath5k_hw_set_opmode(ah); + /*PISR/SISR Not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); + /* If we later allow tuning for this, store into sc structure */ + data = AR5K_TUNE_RSSI_THRES | + AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S; + ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR); + } + + /* + * Set Rx/Tx DMA Configuration + * + * Set maximum DMA size (512) except for PCI-E cards since + * it causes rx overruns and tx errors (tested on 5424 but since + * rx overruns also occur on 5416/5418 with madwifi we set 128 + * for all PCI-E cards to be safe). + * + * In dumps this is 128 for allchips. + * + * XXX: need to check 5210 for this + * TODO: Check out tx triger level, it's always 64 on dumps but I + * guess we can tweak it and see how it goes ;-) + */ + dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B; + if (ah->ah_version != AR5K_AR5210) { + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_SDMAMR, dma_size); + AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, + AR5K_RXCFG_SDMAMW, dma_size); + } + + /* + * Enable the PHY and wait until completion + */ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); + + /* + * On 5211+ read activation -> rx delay + * and use it. + */ + if (ah->ah_version != AR5K_AR5210) { + data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & + AR5K_PHY_RX_DELAY_M; + data = (channel->hw_value & CHANNEL_CCK) ? + ((data << 2) / 22) : (data / 10); + + udelay(100 + (2 * data)); + data = 0; + } else { + mdelay(1); + } + + /* + * Perform ADC test (?) + */ + data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); + ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); + for (i = 0; i <= 20; i++) { + if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) + break; + udelay(200); + } + ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1); + data = 0; + + /* + * Start automatic gain calibration + * + * During AGC calibration RX path is re-routed to + * a signal detector so we don't receive anything. + * + * This method is used to calibrate some static offsets + * used together with on-the fly I/Q calibration (the + * one performed via ath5k_hw_phy_calibrate), that doesn't + * interrupt rx path. + * + * If we are in a noisy environment AGC calibration may time + * out. + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL); + + /* At the same time start I/Q calibration for QAM constellation + * -no need for CCK- */ + ah->ah_calibration = false; + if (!(mode == AR5K_MODE_11B)) { + ah->ah_calibration = true; + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_RUN); + } + + /* Wait for gain calibration to finish (we check for I/Q calibration + * during ath5k_phy_calibrate) */ + if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL, 0, false)) { + ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n", + channel->center_freq); + return -EAGAIN; + } + + /* + * Start noise floor calibration + * + * If we run NF calibration before AGC, it always times out. + * Binary HAL starts NF and AGC calibration at the same time + * and only waits for AGC to finish. I believe that's wrong because + * during NF calibration, rx path is also routed to a detector, so if + * it doesn't finish we won't have RX. + * + * XXX: Find an interval that's OK for all cards... + */ + ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + if (ret) + return ret; + + /* + * Reset queues and start beacon timers at the end of the reset routine + */ + for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) { + /*No QCU on 5210*/ + if (ah->ah_version != AR5K_AR5210) + AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i); + + ret = ath5k_hw_reset_tx_queue(ah, i); + if (ret) { + ATH5K_ERR(ah->ah_sc, + "failed to reset TX queue #%d\n", i); + return ret; + } + } + + /* Pre-enable interrupts on 5211/5212*/ + if (ah->ah_version != AR5K_AR5210) + ath5k_hw_set_imr(ah, AR5K_INT_RX | AR5K_INT_TX | + AR5K_INT_FATAL); + + /* + * Set RF kill flags if supported by the device (read from the EEPROM) + * Disable gpio_intr for now since it results system hang. + * TODO: Handle this in ath5k_intr + */ +#if 0 + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + ath5k_hw_set_gpio_input(ah, 0); + ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); + if (ah->ah_gpio[0] == 0) + ath5k_hw_set_gpio_intr(ah, 0, 1); + else + ath5k_hw_set_gpio_intr(ah, 0, 0); + } +#endif + + /* + * Set the 32MHz reference clock on 5212 phy clock sleep register + * + * TODO: Find out how to switch to external 32Khz clock to save power + */ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); + ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT); + ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); + ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); + ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); + ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING); + + data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ; + data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ? + 0x00000f80 : 0x00001380 ; + ath5k_hw_reg_write(ah, data, AR5K_USEC_5211); + data = 0; + } + + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0x000100aa, 0x8118); + ath5k_hw_reg_write(ah, 0x00003210, 0x811c); + ath5k_hw_reg_write(ah, 0x00000052, 0x8108); + if (ah->ah_mac_srev >= AR5K_SREV_AR2413) + ath5k_hw_reg_write(ah, 0x00000004, 0x8120); + } + + /* + * Disable beacons and reset the register + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE | + AR5K_BEACON_RESET_TSF); + + return 0; +} + +#undef _ATH5K_RESET diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig index 9e19dcceb3a..80a69243041 100644 --- a/drivers/net/wireless/ath9k/Kconfig +++ b/drivers/net/wireless/ath9k/Kconfig @@ -1,6 +1,9 @@ config ATH9K tristate "Atheros 802.11n wireless cards support" depends on PCI && MAC80211 && WLAN_80211 + select MAC80211_LEDS + select LEDS_CLASS + select NEW_LEDS ---help--- This module adds support for wireless adapters based on Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets. diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index d1b0fbae5a3..accace5f7ef 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -144,6 +144,7 @@ struct ath_desc { #define ATH9K_TXDESC_EXT_AND_CTL 0x0080 #define ATH9K_TXDESC_VMF 0x0100 #define ATH9K_TXDESC_FRAG_IS_ON 0x0200 +#define ATH9K_TXDESC_CAB 0x0400 #define ATH9K_RXDESC_INTREQ 0x0020 @@ -564,8 +565,6 @@ enum ath9k_cipher { #define CTL_5GHT40 8 #define AR_EEPROM_MAC(i) (0x1d+(i)) -#define EEP_SCALE 100 -#define EEP_DELTA 10 #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c #define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 @@ -606,9 +605,6 @@ struct ath9k_country_entry { #define REG_CLR_BIT(_a, _r, _f) \ REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f) -#define ATH9K_COMP_BUF_MAX_SIZE 9216 -#define ATH9K_COMP_BUF_ALIGN_SIZE 512 - #define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001 #define INIT_AIFS 2 @@ -632,12 +628,6 @@ struct ath9k_country_entry { (IEEE80211_WEP_IVLEN + \ IEEE80211_WEP_KIDLEN + \ IEEE80211_WEP_CRCLEN)) -#define IEEE80211_MAX_LEN (2300 + FCS_LEN + \ - (IEEE80211_WEP_IVLEN + \ - IEEE80211_WEP_KIDLEN + \ - IEEE80211_WEP_CRCLEN)) - -#define MAX_REG_ADD_COUNT 129 #define MAX_RATE_POWER 63 enum ath9k_power_mode { @@ -707,13 +697,6 @@ enum phytype { }; #define PHY_CCK PHY_DS -enum start_adhoc_option { - START_ADHOC_NO_11A, - START_ADHOC_PER_11D, - START_ADHOC_IN_11A, - START_ADHOC_IN_11B, -}; - enum ath9k_tp_scale { ATH9K_TP_SCALE_MAX = 0, ATH9K_TP_SCALE_50, @@ -769,14 +752,11 @@ struct ath9k_node_stats { #define ATH9K_RSSI_EP_MULTIPLIER (1<<7) -enum ath9k_gpio_output_mux_type { - ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT, - ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, - ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, - ATH9K_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, - ATH9K_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, - ATH9K_GPIO_OUTPUT_MUX_NUM_ENTRIES -}; +#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 enum { ATH9K_RESET_POWER_ON, @@ -790,19 +770,20 @@ struct ath_hal { u32 ah_magic; u16 ah_devid; u16 ah_subvendorid; - struct ath_softc *ah_sc; - void __iomem *ah_sh; - u16 ah_countryCode; u32 ah_macVersion; u16 ah_macRev; u16 ah_phyRev; u16 ah_analog5GhzRev; u16 ah_analog2GhzRev; - u8 ah_decompMask[ATH9K_DECOMP_MASK_SIZE]; - u32 ah_flags; + + void __iomem *ah_sh; + struct ath_softc *ah_sc; enum ath9k_opmode ah_opmode; struct ath9k_ops_config ah_config; struct ath9k_hw_capabilities ah_caps; + + u16 ah_countryCode; + u32 ah_flags; int16_t ah_powerLimit; u16 ah_maxPowerLevel; u32 ah_tpScale; @@ -812,15 +793,17 @@ struct ath_hal { u16 ah_currentRD5G; u16 ah_currentRD2G; char ah_iso[4]; - enum start_adhoc_option ah_adHocMode; - bool ah_commonMode; + struct ath9k_channel ah_channels[150]; - u32 ah_nchan; struct ath9k_channel *ah_curchan; - u16 ah_rfsilent; - bool ah_rfkillEnabled; + u32 ah_nchan; + bool ah_isPciExpress; u16 ah_txTrigLevel; + u16 ah_rfsilent; + u32 ah_rfkill_gpio; + u32 ah_rfkill_polarity; + #ifndef ATH_NF_PER_CHAN struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; #endif @@ -853,7 +836,7 @@ bool ath9k_regd_init_channels(struct ath_hal *ah, u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints); -bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, @@ -871,7 +854,7 @@ bool ath9k_hw_calibrate(struct ath_hal *ah, u8 rxchainmask, bool longcal, bool *isCalDone); -int16_t ath9k_hw_getchan_noise(struct ath_hal *ah, +s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan); void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId); @@ -1018,4 +1001,9 @@ void ath9k_hw_get_channel_centers(struct ath_hal *ah, bool ath9k_get_channel_edges(struct ath_hal *ah, u16 flags, u16 *low, u16 *high); +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type); +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value); +u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio); +void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio); #endif diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index caf569401a3..9e15c30bbc0 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -16,7 +16,6 @@ /* Implementation of beacon processing. */ -#include <asm/unaligned.h> #include "core.h" /* @@ -26,14 +25,13 @@ * the operating mode of the station (AP or AdHoc). Parameters are AIFS * settings and channel width min/max */ - static int ath_beaconq_config(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; struct ath9k_tx_queue_info qi; ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi); - if (sc->sc_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; qi.tqi_cwmin = 0; @@ -63,19 +61,18 @@ static int ath_beaconq_config(struct ath_softc *sc) * up all required antenna switch parameters, 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_vap *avp, struct ath_buf *bf) + struct ath_vap *avp, struct ath_buf *bf) { struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; struct ath_hal *ah = sc->sc_ah; struct ath_desc *ds; - int flags, antenna; + struct ath9k_11n_rate_series series[4]; const struct ath9k_rate_table *rt; + int flags, antenna; u8 rix, rate; int ctsrate = 0; int ctsduration = 0; - struct ath9k_11n_rate_series series[4]; DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n", __func__, skb, skb->len); @@ -85,7 +82,7 @@ static void ath_beacon_setup(struct ath_softc *sc, flags = ATH9K_TXDESC_NOACK; - if (sc->sc_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { ds->ds_link = bf->bf_daddr; /* self-linked */ flags |= ATH9K_TXDESC_VEOL; @@ -111,27 +108,28 @@ static void ath_beacon_setup(struct ath_softc *sc, rix = 0; rt = sc->sc_currates; rate = rt->info[rix].rateCode; - if (sc->sc_flags & ATH_PREAMBLE_SHORT) + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) rate |= rt->info[rix].shortPreamble; - ath9k_hw_set11n_txdesc(ah, ds - , skb->len + FCS_LEN /* frame length */ - , ATH9K_PKT_TYPE_BEACON /* Atheros packet type */ - , avp->av_btxctl.txpower /* txpower XXX */ - , ATH9K_TXKEYIX_INVALID /* no encryption */ - , ATH9K_KEY_TYPE_CLEAR /* no encryption */ - , flags /* no ack, veol for beacons */ + ath9k_hw_set11n_txdesc(ah, ds, + skb->len + FCS_LEN, /* frame length */ + ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ + avp->av_btxctl.txpower, /* txpower XXX */ + ATH9K_TXKEYIX_INVALID, /* no encryption */ + ATH9K_KEY_TYPE_CLEAR, /* no encryption */ + flags /* no ack, + veol for beacons */ ); /* NB: beacon's BufLen must be a multiple of 4 bytes */ - ath9k_hw_filltxdesc(ah, ds - , roundup(skb->len, 4) /* buffer length */ - , true /* first segment */ - , true /* last segment */ - , ds /* first descriptor */ + ath9k_hw_filltxdesc(ah, ds, + roundup(skb->len, 4), /* buffer length */ + true, /* first segment */ + true, /* last segment */ + ds /* first descriptor */ ); - memzero(series, sizeof(struct ath9k_11n_rate_series) * 4); + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); series[0].Tries = 1; series[0].Rate = rate; series[0].ChSel = sc->sc_tx_chainmask; @@ -140,55 +138,6 @@ static void ath_beacon_setup(struct ath_softc *sc, ctsrate, ctsduration, series, 4, 0); } -/* Move everything from the vap's mcast queue to the hardware cab queue. - * Caller must hold mcasq lock and cabq lock - * XXX MORE_DATA bit? - */ -static void empty_mcastq_into_cabq(struct ath_hal *ah, - struct ath_txq *mcastq, struct ath_txq *cabq) -{ - struct ath_buf *bfmcast; - - BUG_ON(list_empty(&mcastq->axq_q)); - - bfmcast = list_first_entry(&mcastq->axq_q, struct ath_buf, list); - - /* link the descriptors */ - if (!cabq->axq_link) - ath9k_hw_puttxbuf(ah, cabq->axq_qnum, bfmcast->bf_daddr); - else - *cabq->axq_link = bfmcast->bf_daddr; - - /* append the private vap mcast list to the cabq */ - - cabq->axq_depth += mcastq->axq_depth; - cabq->axq_totalqueued += mcastq->axq_totalqueued; - cabq->axq_linkbuf = mcastq->axq_linkbuf; - cabq->axq_link = mcastq->axq_link; - list_splice_tail_init(&mcastq->axq_q, &cabq->axq_q); - mcastq->axq_depth = 0; - mcastq->axq_totalqueued = 0; - mcastq->axq_linkbuf = NULL; - mcastq->axq_link = NULL; -} - -/* This is only run at DTIM. We move everything from the vap's mcast queue - * to the hardware cab queue. Caller must hold the mcastq lock. */ -static void trigger_mcastq(struct ath_hal *ah, - struct ath_txq *mcastq, struct ath_txq *cabq) -{ - spin_lock_bh(&cabq->axq_lock); - - if (!list_empty(&mcastq->axq_q)) - empty_mcastq_into_cabq(ah, mcastq, cabq); - - /* cabq is gated by beacon so it is safe to start here */ - if (!list_empty(&cabq->axq_q)) - ath9k_hw_txstart(ah, cabq->axq_qnum); - - spin_unlock_bh(&cabq->axq_lock); -} - /* * Generate beacon frame and queue cab data for a vap. * @@ -199,57 +148,56 @@ static void trigger_mcastq(struct ath_hal *ah, */ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) { - struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; struct ath_vap *avp; struct sk_buff *skb; - int cabq_depth; - int mcastq_depth; - int is_beacon_dtim = 0; - unsigned int curlen; struct ath_txq *cabq; - struct ath_txq *mcastq; + struct ieee80211_tx_info *info; + int cabq_depth; + avp = sc->sc_vaps[if_id]; + ASSERT(avp); - mcastq = &avp->av_mcastq; cabq = sc->sc_cabq; - ASSERT(avp); - if (avp->av_bcbuf == NULL) { DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", __func__, avp, avp->av_bcbuf); return NULL; } + bf = avp->av_bcbuf; - skb = (struct sk_buff *) bf->bf_mpdu; + skb = (struct sk_buff *)bf->bf_mpdu; + if (skb) { + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); + } - /* - * Update dynamic beacon contents. If this returns - * non-zero then we need to remap the memory because - * the beacon frame changed size (probably because - * of the TIM bitmap). - */ - curlen = skb->len; - - /* XXX: spin_lock_bh should not be used here, but sparse bitches - * otherwise. We should fix sparse :) */ - spin_lock_bh(&mcastq->axq_lock); - mcastq_depth = avp->av_mcastq.axq_depth; - - if (ath_update_beacon(sc, if_id, &avp->av_boff, skb, mcastq_depth) == - 1) { - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); - bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); - } else { - pci_dma_sync_single_for_cpu(sc->pdev, - bf->bf_buf_addr, - skb_tailroom(skb), - PCI_DMA_TODEVICE); + skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); + bf->bf_mpdu = skb; + if (skb == NULL) + return NULL; + + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + /* + * TODO: make sure the seq# gets assigned properly (vs. other + * TX frames) + */ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); } + bf->bf_buf_addr = bf->bf_dmacontext = + pci_map_single(sc->pdev, skb->data, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); + + skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + /* * if the CABQ traffic from previous DTIM is pending and the current * beacon is also a DTIM. @@ -262,9 +210,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) cabq_depth = cabq->axq_depth; spin_unlock_bh(&cabq->axq_lock); - is_beacon_dtim = avp->av_boff.bo_tim[4] & 1; - - if (mcastq_depth && is_beacon_dtim && cabq_depth) { + if (skb && cabq_depth) { /* * Unlock the cabq lock as ath_tx_draintxq acquires * the lock again which is a common function and that @@ -284,10 +230,11 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) * Enable the CAB queue before the beacon queue to * insure cab frames are triggered by this beacon. */ - if (is_beacon_dtim) - trigger_mcastq(ah, mcastq, cabq); + while (skb) { + ath_tx_cabq(sc, skb); + skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + } - spin_unlock_bh(&mcastq->axq_lock); return bf; } @@ -295,7 +242,6 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) * Startup beacon transmission for adhoc mode when they are sent entirely * by the hardware using the self-linked descriptor + veol trick. */ - static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) { struct ath_hal *ah = sc->sc_ah; @@ -332,12 +278,11 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) * min/max, and enable aifs). The info structure does not need to be * persistant. */ - int ath_beaconq_setup(struct ath_hal *ah) { struct ath9k_tx_queue_info qi; - memzero(&qi, sizeof(qi)); + memset(&qi, 0, sizeof(qi)); qi.tqi_aifs = 1; qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; @@ -353,29 +298,27 @@ int ath_beaconq_setup(struct ath_hal *ah) * the ATH interface. This routine also calculates the beacon "slot" for * staggared beacons in the mBSSID case. */ - int ath_beacon_alloc(struct ath_softc *sc, int if_id) { struct ath_vap *avp; - struct ieee80211_hdr *wh; + struct ieee80211_hdr *hdr; struct ath_buf *bf; struct sk_buff *skb; + __le64 tstamp; avp = sc->sc_vaps[if_id]; ASSERT(avp); /* Allocate a beacon descriptor if we haven't done so. */ if (!avp->av_bcbuf) { - /* - * Allocate beacon state for hostap/ibss. We know - * a buffer is available. - */ + /* Allocate beacon state for hostap/ibss. We know + * a buffer is available. */ avp->av_bcbuf = list_first_entry(&sc->sc_bbuf, - struct ath_buf, list); + struct ath_buf, list); list_del(&avp->av_bcbuf->list); - if (sc->sc_opmode == ATH9K_M_HOSTAP || + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { int slot; /* @@ -408,17 +351,16 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { skb = (struct sk_buff *)bf->bf_mpdu; - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } /* - * NB: the beacon data buffer must be 32-bit aligned; - * we assume the wbuf routines will return us something - * with this alignment (perhaps should assert). - * FIXME: Fill avp->av_boff.bo_tim,avp->av_btxctl.txpower and + * NB: the beacon data buffer must be 32-bit aligned. + * FIXME: Fill avp->av_btxctl.txpower and * avp->av_btxctl.shortPreamble */ skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); @@ -428,6 +370,9 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) return -ENOMEM; } + tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; + sc->bc_tstamp = le64_to_cpu(tstamp); + /* * Calculate a TSF adjustment factor required for * staggered beacons. Note that we assume the format @@ -439,9 +384,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) __le64 val; int intval; - /* FIXME: Use default value for now: Sujith */ - - intval = ATH_DEFAULT_BINTVAL; + intval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; /* * The beacon interval is in TU's; the TSF in usecs. @@ -462,12 +406,14 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) __func__, "stagger", avp->av_bslot, intval, (unsigned long long)tsfadjust); - wh = (struct ieee80211_hdr *)skb->data; - memcpy(&wh[1], &val, sizeof(val)); + hdr = (struct ieee80211_hdr *)skb->data; + memcpy(&hdr[1], &val, sizeof(val)); } - bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + bf->bf_buf_addr = bf->bf_dmacontext = + pci_map_single(sc->pdev, skb->data, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); bf->bf_mpdu = skb; return 0; @@ -477,9 +423,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) * Reclaim beacon resources and return buffer to the pool. * * Checks the VAP to put the beacon frame buffer back to the ATH object - * queue, and de-allocates any wbuf frames that were sent as CAB traffic. + * queue, and de-allocates any skbs that were sent as CAB traffic. */ - void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) { if (avp->av_bcbuf != NULL) { @@ -493,8 +438,9 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } @@ -505,44 +451,14 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) } /* - * Reclaim beacon resources and return buffer to the pool. - * - * This function will free any wbuf frames that are still attached to the - * beacon buffers in the ATH object. Note that this does not de-allocate - * any wbuf objects that are in the transmit queue and have not yet returned - * to the ATH object. -*/ - -void ath_beacon_free(struct ath_softc *sc) -{ - struct ath_buf *bf; - - list_for_each_entry(bf, &sc->sc_bbuf, list) { - if (bf->bf_mpdu != NULL) { - struct sk_buff *skb = (struct sk_buff *) bf->bf_mpdu; - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - } - } -} - -/* * Tasklet for Sending Beacons * * Transmit one or more beacon frames at SWBA. Dynamic updates to the frame * contents are done as needed and the slot time is also adjusted based on * current state. - * - * This tasklet is not scheduled, it's called in ISR context. */ - void ath9k_beacon_tasklet(unsigned long data) { -#define TSF_TO_TU(_h,_l) \ - ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) - struct ath_softc *sc = (struct ath_softc *)data; struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf = NULL; @@ -555,7 +471,7 @@ void ath9k_beacon_tasklet(unsigned long data) u32 tsftu; u16 intval; - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { show_cycles = ath9k_hw_GetMibCycleCountsPct(ah, &rx_clear, &rx_frame, @@ -568,6 +484,8 @@ void ath9k_beacon_tasklet(unsigned long data) * and wait for the next. Missed beacons indicate * a problem and should not occur. If we miss too * many consecutive beacons reset the device. + * + * FIXME: Clean up this mess !! */ if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) { sc->sc_bmisscount++; @@ -577,25 +495,22 @@ void ath9k_beacon_tasklet(unsigned long data) * (in that layer). */ if (sc->sc_bmisscount < BSTUCK_THRESH) { - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, "%s: missed %u consecutive beacons\n", __func__, sc->sc_bmisscount); if (show_cycles) { /* - * Display cycle counter stats - * from HW to aide in debug of - * stickiness. + * Display cycle counter stats from HW + * to aide in debug of stickiness. */ - DPRINTF(sc, - ATH_DBG_BEACON, + DPRINTF(sc, ATH_DBG_BEACON, "%s: busy times: rx_clear=%d, " "rx_frame=%d, tx_frame=%d\n", __func__, rx_clear, rx_frame, tx_frame); } else { - DPRINTF(sc, - ATH_DBG_BEACON, + DPRINTF(sc, ATH_DBG_BEACON, "%s: unable to obtain " "busy times\n", __func__); } @@ -605,10 +520,9 @@ void ath9k_beacon_tasklet(unsigned long data) __func__, sc->sc_bmisscount); } } else if (sc->sc_bmisscount >= BSTUCK_THRESH) { - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { if (sc->sc_bmisscount == BSTUCK_THRESH) { - DPRINTF(sc, - ATH_DBG_BEACON, + DPRINTF(sc, ATH_DBG_BEACON, "%s: beacon is officially " "stuck\n", __func__); ath9k_hw_dmaRegDump(ah); @@ -620,13 +534,12 @@ void ath9k_beacon_tasklet(unsigned long data) ath_bstuck_process(sc); } } - return; } + if (sc->sc_bmisscount != 0) { - if (sc->sc_noreset) { - DPRINTF(sc, - ATH_DBG_BEACON, + if (sc->sc_flags & SC_OP_NO_RESET) { + DPRINTF(sc, ATH_DBG_BEACON, "%s: resume beacon xmit after %u misses\n", __func__, sc->sc_bmisscount); } else { @@ -643,17 +556,19 @@ void ath9k_beacon_tasklet(unsigned long data) * on the tsf to safeguard against missing an swba. */ - /* FIXME: Use default value for now - Sujith */ - intval = ATH_DEFAULT_BINTVAL; + intval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf); slot = ((tsftu % intval) * ATH_BCBUF) / intval; if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF]; + DPRINTF(sc, ATH_DBG_BEACON, - "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", - __func__, slot, (unsigned long long) tsf, tsftu, - intval, if_id); + "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", + __func__, slot, (unsigned long long)tsf, tsftu, + intval, if_id); + bfaddr = 0; if (if_id != ATH_IF_ID_ANY) { bf = ath_beacon_generate(sc, if_id); @@ -704,22 +619,20 @@ void ath9k_beacon_tasklet(unsigned long data) sc->ast_be_xmit += bc; /* XXX per-vap? */ } -#undef TSF_TO_TU } /* * Tasklet for Beacon Stuck processing * * Processing for Beacon Stuck. - * Basically calls the ath_internal_reset function to reset the chip. + * Basically resets the chip. */ - void ath_bstuck_process(struct ath_softc *sc) { DPRINTF(sc, ATH_DBG_BEACON, "%s: stuck beacon; resetting (bmiss count %u)\n", __func__, sc->sc_bmisscount); - ath_internal_reset(sc); + ath_reset(sc, false); } /* @@ -737,40 +650,32 @@ void ath_bstuck_process(struct ath_softc *sc) * interrupt when we stop seeing beacons from the AP * we've associated with. */ - void ath_beacon_config(struct ath_softc *sc, int if_id) { -#define TSF_TO_TU(_h,_l) \ - ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) struct ath_hal *ah = sc->sc_ah; - u32 nexttbtt, intval; struct ath_beacon_config conf; enum ath9k_opmode av_opmode; + u32 nexttbtt, intval; if (if_id != ATH_IF_ID_ANY) av_opmode = sc->sc_vaps[if_id]->av_opmode; else - av_opmode = sc->sc_opmode; + av_opmode = sc->sc_ah->ah_opmode; - memzero(&conf, sizeof(struct ath_beacon_config)); + memset(&conf, 0, sizeof(struct ath_beacon_config)); - /* FIXME: Use default values for now - Sujith */ - /* Query beacon configuration first */ - /* - * Protocol stack doesn't support dynamic beacon configuration, - * use default configurations. - */ - conf.beacon_interval = ATH_DEFAULT_BINTVAL; + conf.beacon_interval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; conf.listen_interval = 1; conf.dtim_period = conf.beacon_interval; conf.dtim_count = 1; conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; /* extract tstamp from last beacon and convert to TU */ - nexttbtt = TSF_TO_TU(get_unaligned_le32(conf.u.last_tstamp + 4), - get_unaligned_le32(conf.u.last_tstamp)); + nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp); + /* XXX conditionalize multi-bss support? */ - if (sc->sc_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* * For multi-bss ap support beacons are either staggered * evenly over N slots or burst together. For the former @@ -784,14 +689,16 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; } - if (nexttbtt == 0) /* e.g. for ap mode */ + if (nexttbtt == 0) /* e.g. for ap mode */ nexttbtt = intval; - else if (intval) /* NB: can be 0 for monitor mode */ + else if (intval) /* NB: can be 0 for monitor mode */ nexttbtt = roundup(nexttbtt, intval); + DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", __func__, nexttbtt, intval, conf.beacon_interval); + /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ - if (sc->sc_opmode == ATH9K_M_STA) { + if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { struct ath9k_beacon_state bs; u64 tsf; u32 tsftu; @@ -803,19 +710,19 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * last beacon we received (which may be none). */ dtimperiod = conf.dtim_period; - if (dtimperiod <= 0) /* NB: 0 if not known */ + if (dtimperiod <= 0) /* NB: 0 if not known */ dtimperiod = 1; dtimcount = conf.dtim_count; - if (dtimcount >= dtimperiod) /* NB: sanity check */ - dtimcount = 0; /* XXX? */ - cfpperiod = 1; /* NB: no PCF support yet */ + if (dtimcount >= dtimperiod) /* NB: sanity check */ + dtimcount = 0; + cfpperiod = 1; /* NB: no PCF support yet */ cfpcount = 0; sleepduration = conf.listen_interval * intval; if (sleepduration <= 0) sleepduration = intval; -#define FUDGE 2 +#define FUDGE 2 /* * Pull nexttbtt forward to reflect the current * TSF and calculate dtim+cfp state for the result. @@ -831,7 +738,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) } } while (nexttbtt < tsftu); #undef FUDGE - memzero(&bs, sizeof(bs)); + memset(&bs, 0, sizeof(bs)); bs.bs_intval = intval; bs.bs_nexttbtt = nexttbtt; bs.bs_dtimperiod = dtimperiod*intval; @@ -839,6 +746,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; bs.bs_cfpmaxduration = 0; + /* * Calculate the number of consecutive beacons to miss * before taking a BMISS interrupt. The configuration @@ -847,9 +755,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * result to at most 15 beacons. */ if (sleepduration > intval) { - bs.bs_bmissthreshold = - conf.listen_interval * - ATH_DEFAULT_BMISS_LIMIT / 2; + bs.bs_bmissthreshold = conf.listen_interval * + ATH_DEFAULT_BMISS_LIMIT / 2; } else { bs.bs_bmissthreshold = DIV_ROUND_UP(conf.bmiss_timeout, intval); @@ -869,8 +776,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * XXX fixed at 100ms */ - bs.bs_sleepduration = - roundup(IEEE80211_MS_TO_TU(100), sleepduration); + bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), + sleepduration); if (bs.bs_sleepduration > bs.bs_dtimperiod) bs.bs_sleepduration = bs.bs_dtimperiod; @@ -886,19 +793,19 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) "cfp:period %u " "maxdur %u " "next %u " - "timoffset %u\n" - , __func__ - , (unsigned long long)tsf, tsftu - , bs.bs_intval - , bs.bs_nexttbtt - , bs.bs_dtimperiod - , bs.bs_nextdtim - , bs.bs_bmissthreshold - , bs.bs_sleepduration - , bs.bs_cfpperiod - , bs.bs_cfpmaxduration - , bs.bs_cfpnext - , bs.bs_timoffset + "timoffset %u\n", + __func__, + (unsigned long long)tsf, tsftu, + bs.bs_intval, + bs.bs_nexttbtt, + bs.bs_dtimperiod, + bs.bs_nextdtim, + bs.bs_bmissthreshold, + bs.bs_sleepduration, + bs.bs_cfpperiod, + bs.bs_cfpmaxduration, + bs.bs_cfpnext, + bs.bs_timoffset ); ath9k_hw_set_interrupts(ah, 0); @@ -911,12 +818,12 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ath9k_hw_set_interrupts(ah, 0); if (nexttbtt == intval) intval |= ATH9K_BEACON_RESET_TSF; - if (sc->sc_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { /* * Pull nexttbtt forward to reflect the current - * TSF . + * TSF */ -#define FUDGE 2 +#define FUDGE 2 if (!(intval & ATH9K_BEACON_RESET_TSF)) { tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU((u32)(tsf>>32), @@ -943,7 +850,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) sc->sc_imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); - } else if (sc->sc_opmode == ATH9K_M_HOSTAP) { + } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* * In AP mode we enable the beacon timers and * SWBA interrupts to prepare beacon frames. @@ -959,11 +866,10 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * When using a self-linked beacon descriptor in * ibss mode load it once here. */ - if (sc->sc_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) ath_beacon_start_adhoc(sc, 0); } -#undef TSF_TO_TU } /* Function to collect beacon rssi data and resync beacon if necessary */ @@ -975,5 +881,5 @@ void ath_beacon_sync(struct ath_softc *sc, int if_id) * beacon frame we just received. */ ath_beacon_config(sc, if_id); - sc->sc_beacons = 1; + sc->sc_flags |= SC_OP_BEACONS; } diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index f6c45288d0e..c5033f6f42a 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -21,9 +21,6 @@ static int ath_outdoor; /* enable outdoor use */ -static const u8 ath_bcast_mac[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - static u32 ath_chainmask_sel_up_rssi_thres = ATH_CHAINMASK_SEL_UP_RSSI_THRES; static u32 ath_chainmask_sel_down_rssi_thres = @@ -54,10 +51,8 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz) * Set current operating mode * * This function initializes and fills the rate table in the ATH object based - * on the operating mode. The blink rates are also set up here, although - * they have been superceeded by the ath_led module. + * on the operating mode. */ - static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) { const struct ath9k_rate_table *rt; @@ -70,7 +65,7 @@ static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) for (i = 0; i < rt->rateCount; i++) sc->sc_rixmap[rt->info[i].rateCode] = (u8) i; - memzero(sc->sc_hwmap, sizeof(sc->sc_hwmap)); + memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); for (i = 0; i < 256; i++) { u8 ix = rt->rateCodeToIndex[i]; @@ -235,7 +230,7 @@ static int ath_setup_channels(struct ath_softc *sc) * Determine mode from channel flags * * This routine will provide the enumerated WIRELESSS_MODE value based - * on the settings of the channel flags. If ho valid set of flags + * on the settings of the channel flags. If no valid set of flags * exist, the lowest mode (11b) is selected. */ @@ -260,7 +255,8 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) else if (chan->chanmode == CHANNEL_G_HT40MINUS) return ATH9K_MODE_11NG_HT40MINUS; - /* NB: should not get here */ + WARN_ON(1); /* should not get here */ + return ATH9K_MODE_11B; } @@ -275,14 +271,12 @@ static int ath_stop(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %u\n", - __func__, sc->sc_invalid); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n", + __func__, sc->sc_flags & SC_OP_INVALID); /* * Shutdown the hardware and driver: * stop output from above - * reset 802.11 state machine - * (sends station deassoc/deauth frames) * turn off timers * disable interrupts * clear transmit machinery @@ -294,10 +288,8 @@ static int ath_stop(struct ath_softc *sc) * hardware is gone (invalid). */ - if (!sc->sc_invalid) - ath9k_hw_set_interrupts(ah, 0); ath_draintxq(sc, false); - if (!sc->sc_invalid) { + if (!(sc->sc_flags & SC_OP_INVALID)) { ath_stoprecv(sc); ath9k_hw_phy_disable(ah); } else @@ -307,56 +299,6 @@ static int ath_stop(struct ath_softc *sc) } /* - * Start Scan - * - * This function is called when starting a channel scan. It will perform - * power save wakeup processing, set the filter for the scan, and get the - * chip ready to send broadcast packets out during the scan. -*/ - -void ath_scan_start(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - u32 rfilt; - u32 now = (u32) jiffies_to_msecs(get_timestamp()); - - sc->sc_scanning = 1; - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); - ath9k_hw_write_associd(ah, ath_bcast_mac, 0); - - /* Restore previous power management state. */ - - DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0\n", - now / 1000, now % 1000, __func__, rfilt); -} - -/* - * Scan End - * - * This routine is called by the upper layer when the scan is completed. This - * will set the filters back to normal operating mode, set the BSSID to the - * correct value, and restore the power save state. -*/ - -void ath_scan_end(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - u32 rfilt; - u32 now = (u32) jiffies_to_msecs(get_timestamp()); - - sc->sc_scanning = 0; - /* Request for a full reset due to rx packet filter changes */ - sc->sc_full_reset = 1; - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); - ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid); - - DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0x%x\n", - now / 1000, now % 1000, __func__, rfilt, sc->sc_curaid); -} - -/* * Set the current channel * * Set/change channels. If the channel is really being changed, it's done @@ -367,25 +309,23 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) { struct ath_hal *ah = sc->sc_ah; bool fastcc = true, stopped; - enum ath9k_ht_macmode ht_macmode; - if (sc->sc_invalid) /* if the device is invalid or removed */ + if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */ return -EIO; DPRINTF(sc, ATH_DBG_CONFIG, "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n", __func__, - ath9k_hw_mhz2ieee(ah, sc->sc_curchan.channel, - sc->sc_curchan.channelFlags), - sc->sc_curchan.channel, + ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel, + sc->sc_ah->ah_curchan->channelFlags), + sc->sc_ah->ah_curchan->channel, ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags), hchan->channel, hchan->channelFlags); - ht_macmode = ath_cwm_macmode(sc); - - if (hchan->channel != sc->sc_curchan.channel || - hchan->channelFlags != sc->sc_curchan.channelFlags || - sc->sc_update_chainmask || sc->sc_full_reset) { + if (hchan->channel != sc->sc_ah->ah_curchan->channel || + hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || + (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || + (sc->sc_flags & SC_OP_FULL_RESET)) { int status; /* * This is only performed if the channel settings have @@ -404,15 +344,16 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) * to flush data frames already in queue because of * changing channel. */ - if (!stopped || sc->sc_full_reset) + if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) fastcc = false; spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, hchan, - ht_macmode, sc->sc_tx_chainmask, - sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, - fastcc, &status)) { + if (!ath9k_hw_reset(ah, hchan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, + sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, + fastcc, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset channel %u (%uMhz) " "flags 0x%x hal status %u\n", __func__, @@ -424,9 +365,8 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) } spin_unlock_bh(&sc->sc_resetlock); - sc->sc_curchan = *hchan; - sc->sc_update_chainmask = 0; - sc->sc_full_reset = 0; + sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; + sc->sc_flags &= ~SC_OP_FULL_RESET; /* Re-enable rx framework */ if (ath_startrecv(sc) != 0) { @@ -477,7 +417,7 @@ static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an) { struct ath_chainmask_sel *cm = &an->an_chainmask_sel; - memzero(cm, sizeof(struct ath_chainmask_sel)); + memset(cm, 0, sizeof(struct ath_chainmask_sel)); cm->cur_tx_mask = sc->sc_tx_chainmask; cm->cur_rx_mask = sc->sc_rx_chainmask; @@ -537,7 +477,7 @@ int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an) void ath_update_chainmask(struct ath_softc *sc, int is_ht) { - sc->sc_update_chainmask = 1; + sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; if (is_ht) { sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; @@ -550,66 +490,126 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask); } -/******************/ -/* VAP management */ -/******************/ +/*******/ +/* ANI */ +/*******/ /* - * VAP in Listen mode - * - * This routine brings the VAP out of the down state into a "listen" state - * where it waits for association requests. This is used in AP and AdHoc - * modes. -*/ + * This routine performs the periodic noise floor calibration function + * that is used to adjust and optimize the chip performance. This + * takes environmental changes (location, temperature) into account. + * When the task is complete, it reschedules itself depending on the + * appropriate interval that was calculated. + */ -int ath_vap_listen(struct ath_softc *sc, int if_id) +static void ath_ani_calibrate(unsigned long data) { - struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; - u32 rfilt = 0; - DECLARE_MAC_BUF(mac); + struct ath_softc *sc; + struct ath_hal *ah; + bool longcal = false; + bool shortcal = false; + bool aniflag = false; + unsigned int timestamp = jiffies_to_msecs(jiffies); + u32 cal_interval; - avp = sc->sc_vaps[if_id]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n", - __func__, if_id); - return -EINVAL; - } + sc = (struct ath_softc *)data; + ah = sc->sc_ah; -#ifdef CONFIG_SLOW_ANT_DIV - ath_slow_ant_div_stop(&sc->sc_antdiv); -#endif + /* + * don't calibrate when we're scanning. + * we are most likely not on our home channel. + */ + if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC) + return; - /* update ratectrl about the new state */ - ath_rate_newstate(sc, avp); + /* Long calibration runs independently of short calibration. */ + if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { + longcal = true; + DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n", + __func__, jiffies); + sc->sc_ani.sc_longcal_timer = timestamp; + } - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); + /* Short calibration applies only while sc_caldone is false */ + if (!sc->sc_ani.sc_caldone) { + if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= + ATH_SHORT_CALINTERVAL) { + shortcal = true; + DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n", + __func__, jiffies); + sc->sc_ani.sc_shortcal_timer = timestamp; + sc->sc_ani.sc_resetcal_timer = timestamp; + } + } else { + if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= + ATH_RESTART_CALINTERVAL) { + ath9k_hw_reset_calvalid(ah, ah->ah_curchan, + &sc->sc_ani.sc_caldone); + if (sc->sc_ani.sc_caldone) + sc->sc_ani.sc_resetcal_timer = timestamp; + } + } - if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS) { - memcpy(sc->sc_curbssid, ath_bcast_mac, ETH_ALEN); - ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid); - } else - sc->sc_curaid = 0; + /* Verify whether we must check ANI */ + if ((timestamp - sc->sc_ani.sc_checkani_timer) >= + ATH_ANI_POLLINTERVAL) { + aniflag = true; + sc->sc_ani.sc_checkani_timer = timestamp; + } - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: RX filter 0x%x bssid %s aid 0x%x\n", - __func__, rfilt, print_mac(mac, - sc->sc_curbssid), sc->sc_curaid); + /* Skip all processing if there's nothing to do. */ + if (longcal || shortcal || aniflag) { + /* Call ANI routine if necessary */ + if (aniflag) + ath9k_hw_ani_monitor(ah, &sc->sc_halstats, + ah->ah_curchan); + + /* Perform calibration if necessary */ + if (longcal || shortcal) { + bool iscaldone = false; + + if (ath9k_hw_calibrate(ah, ah->ah_curchan, + sc->sc_rx_chainmask, longcal, + &iscaldone)) { + if (longcal) + sc->sc_ani.sc_noise_floor = + ath9k_hw_getchan_noise(ah, + ah->ah_curchan); + + DPRINTF(sc, ATH_DBG_ANI, + "%s: calibrate chan %u/%x nf: %d\n", + __func__, + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags, + sc->sc_ani.sc_noise_floor); + } else { + DPRINTF(sc, ATH_DBG_ANY, + "%s: calibrate chan %u/%x failed\n", + __func__, + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags); + } + sc->sc_ani.sc_caldone = iscaldone; + } + } /* - * XXXX - * Disable BMISS interrupt when we're not associated - */ - ath9k_hw_set_interrupts(ah, - sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - /* need to reconfigure the beacons when it moves to RUN */ - sc->sc_beacons = 0; + * Set timer interval based on previous results. + * The interval must be the shortest necessary to satisfy ANI, + * short calibration and long calibration. + */ - return 0; + cal_interval = ATH_ANI_POLLINTERVAL; + if (!sc->sc_ani.sc_caldone) + cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); + + mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); } +/******************/ +/* VAP management */ +/******************/ + int ath_vap_attach(struct ath_softc *sc, int if_id, struct ieee80211_vif *if_data, @@ -642,21 +642,19 @@ int ath_vap_attach(struct ath_softc *sc, if (avp == NULL) return -ENOMEM; - memzero(avp, sizeof(struct ath_vap)); + memset(avp, 0, sizeof(struct ath_vap)); avp->av_if_data = if_data; /* Set the VAP opmode */ avp->av_opmode = opmode; avp->av_bslot = -1; - INIT_LIST_HEAD(&avp->av_mcastq.axq_q); - INIT_LIST_HEAD(&avp->av_mcastq.axq_acq); - spin_lock_init(&avp->av_mcastq.axq_lock); - ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + if (opmode == ATH9K_M_HOSTAP) + ath9k_hw_set_tsfadjust(sc->sc_ah, 1); sc->sc_vaps[if_id] = avp; sc->sc_nvaps++; /* Set the device opmode */ - sc->sc_opmode = opmode; + sc->sc_ah->ah_opmode = opmode; /* default VAP configuration */ avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE; @@ -689,9 +687,6 @@ int ath_vap_detach(struct ath_softc *sc, int if_id) ath_stoprecv(sc); /* stop recv side */ ath_flushrecv(sc); /* flush recv queue */ - /* Reclaim any pending mcast bufs on the vap. */ - ath_tx_draintxq(sc, &avp->av_mcastq, false); - kfree(avp); sc->sc_vaps[if_id] = NULL; sc->sc_nvaps--; @@ -728,9 +723,9 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) struct ath_hal *ah = sc->sc_ah; int status; int error = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", __func__, sc->sc_opmode); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", + __func__, sc->sc_ah->ah_opmode); /* * Stop anything previously setup. This is safe @@ -752,16 +747,16 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ - sc->sc_curchan = *initial_chan; spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { + if (!ath9k_hw_reset(ah, initial_chan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u " "(freq %u flags 0x%x)\n", __func__, status, - sc->sc_curchan.channel, sc->sc_curchan.channelFlags); + initial_chan->channel, initial_chan->channelFlags); error = -EIO; spin_unlock_bh(&sc->sc_resetlock); goto done; @@ -802,7 +797,8 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) * Note we only do this (at the moment) for station mode. */ if (ath9k_hw_phycounters(ah) && - ((sc->sc_opmode == ATH9K_M_STA) || (sc->sc_opmode == ATH9K_M_IBSS))) + ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || + (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))) sc->sc_imask |= ATH9K_INT_MIB; /* * Some hardware processes the TIM IE and fires an @@ -811,7 +807,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) * enable the TIM interrupt when operating as station. */ if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (sc->sc_opmode == ATH9K_M_STA) && + (sc->sc_ah->ah_opmode == ATH9K_M_STA) && !sc->sc_config.swBeaconProcess) sc->sc_imask |= ATH9K_INT_TIM; /* @@ -823,34 +819,34 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) /* XXX: we must make sure h/w is ready and clear invalid flag * before turning on interrupt. */ - sc->sc_invalid = 0; + sc->sc_flags &= ~SC_OP_INVALID; done: return error; } -/* - * Reset the hardware w/o losing operational state. This is - * basically a more efficient way of doing ath_stop, ath_init, - * followed by state transitions to the current 802.11 - * operational state. Used to recover from errors rx overrun - * and to reset the hardware when rf gain settings must be reset. - */ - -static int ath_reset_start(struct ath_softc *sc, u32 flag) +int ath_reset(struct ath_softc *sc, bool retry_tx) { struct ath_hal *ah = sc->sc_ah; + int status; + int error = 0; ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, flag & RESET_RETRY_TXQ); /* stop xmit side */ - ath_stoprecv(sc); /* stop recv side */ - ath_flushrecv(sc); /* flush recv queue */ + ath_draintxq(sc, retry_tx); /* stop xmit */ + ath_stoprecv(sc); /* stop recv */ + ath_flushrecv(sc); /* flush recv queue */ - return 0; -} - -static int ath_reset_end(struct ath_softc *sc, u32 flag) -{ - struct ath_hal *ah = sc->sc_ah; + /* Reset chip */ + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to reset hardware; hal status %u\n", + __func__, status); + error = -EIO; + } + spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) /* restart recv */ DPRINTF(sc, ATH_DBG_FATAL, @@ -861,16 +857,17 @@ static int ath_reset_end(struct ath_softc *sc, u32 flag) * that changes the channel so update any state that * might change as a result. */ - ath_setcurmode(sc, ath_chan2mode(&sc->sc_curchan)); + ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); - ath_update_txpow(sc); /* update tx power state */ + ath_update_txpow(sc); - if (sc->sc_beacons) + if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ + ath9k_hw_set_interrupts(ah, sc->sc_imask); /* Restart the txq */ - if (flag & RESET_RETRY_TXQ) { + if (retry_tx) { int i; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { @@ -880,28 +877,6 @@ static int ath_reset_end(struct ath_softc *sc, u32 flag) } } } - return 0; -} - -int ath_reset(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); - - /* NB: indicate channel change so we do a full reset */ - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, - ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u\n", - __func__, status); - error = -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); return error; } @@ -911,7 +886,7 @@ int ath_suspend(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; /* No I/O if device has been surprise removed */ - if (sc->sc_invalid) + if (sc->sc_flags & SC_OP_INVALID) return -EIO; /* Shut off the interrupt before setting sc->sc_invalid to '1' */ @@ -919,7 +894,7 @@ int ath_suspend(struct ath_softc *sc) /* XXX: we must make sure h/w will not generate any interrupt * before setting the invalid flag. */ - sc->sc_invalid = 1; + sc->sc_flags |= SC_OP_INVALID; /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); @@ -940,7 +915,7 @@ irqreturn_t ath_isr(int irq, void *dev) bool sched = false; do { - if (sc->sc_invalid) { + if (sc->sc_flags & SC_OP_INVALID) { /* * The hardware is not ready/present, don't * touch anything. Note this can happen early @@ -1050,7 +1025,7 @@ static void ath9k_tasklet(unsigned long data) if (status & ATH9K_INT_FATAL) { /* need a chip reset */ - ath_internal_reset(sc); + ath_reset(sc, false); return; } else { @@ -1093,10 +1068,9 @@ int ath_init(u16 devid, struct ath_softc *sc) int status; int error = 0, i; int csz = 0; - u32 rd; /* XXX: hardware will not be ready until ath_open() being called */ - sc->sc_invalid = 1; + sc->sc_flags |= SC_OP_INVALID; sc->sc_debug = DBG_DEFAULT; DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid); @@ -1126,8 +1100,9 @@ int ath_init(u16 devid, struct ath_softc *sc) } sc->sc_ah = ah; - /* Get the chipset-specific aggr limit. */ - sc->sc_rtsaggrlimit = ah->ah_caps.rts_aggr_limit; + /* Initializes the noise floor to a reasonable default value. + * Later on this will be updated during ANI processing. */ + sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; /* Get the hardware key cache size. */ sc->sc_keymax = ah->ah_caps.keycache_size; @@ -1162,14 +1137,12 @@ int ath_init(u16 devid, struct ath_softc *sc) * is resposible for filtering this list based on settings * like the phy mode. */ - rd = ah->ah_currentRD; - error = ath_setup_channels(sc); if (error) goto bad; /* default to STA mode */ - sc->sc_opmode = ATH9K_M_MONITOR; + sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; /* Setup rate tables */ @@ -1238,9 +1211,11 @@ int ath_init(u16 devid, struct ath_softc *sc) goto bad2; } + setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); + sc->sc_rc = ath_rate_attach(ah); if (sc->sc_rc == NULL) { - error = EIO; + error = -EIO; goto bad2; } @@ -1280,20 +1255,13 @@ int ath_init(u16 devid, struct ath_softc *sc) /* 11n Capabilities */ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_txaggr = 1; - sc->sc_rxaggr = 1; + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; } sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; - /* Configuration for rx chain detection */ - sc->sc_rxchaindetect_ref = 0; - sc->sc_rxchaindetect_thresh5GHz = 35; - sc->sc_rxchaindetect_thresh2GHz = 35; - sc->sc_rxchaindetect_delta5GHz = 30; - sc->sc_rxchaindetect_delta2GHz = 30; - ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); sc->sc_defant = ath9k_hw_getdefantenna(ah); @@ -1336,8 +1304,10 @@ void ath_deinit(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__); + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); ath_stop(sc); - if (!sc->sc_invalid) + if (!(sc->sc_flags & SC_OP_INVALID)) ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); ath_rate_detach(sc->sc_rc); /* cleanup tx queues */ @@ -1364,7 +1334,7 @@ struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id) an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC); if (an == NULL) return NULL; - memzero(an, sizeof(*an)); + memset(an, 0, sizeof(*an)); an->an_sc = sc; memcpy(an->an_addr, addr, ETH_ALEN); @@ -1464,9 +1434,9 @@ void ath_newassoc(struct ath_softc *sc, /* if station reassociates, tear down the aggregation state. */ if (!isnew) { for (tidno = 0; tidno < WME_NUM_TID; tidno++) { - if (sc->sc_txaggr) + if (sc->sc_flags & SC_OP_TXAGGR) ath_tx_aggr_teardown(sc, an, tidno); - if (sc->sc_rxaggr) + if (sc->sc_flags & SC_OP_RXAGGR) ath_rx_aggr_teardown(sc, an, tidno); } } @@ -1751,7 +1721,7 @@ int ath_descdma_setup(struct ath_softc *sc, error = -ENOMEM; goto fail2; } - memzero(bf, bsize); + memset(bf, 0, bsize); dd->dd_bufptr = bf; INIT_LIST_HEAD(head); @@ -1783,7 +1753,7 @@ fail2: pci_free_consistent(sc->pdev, dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); fail: - memzero(dd, sizeof(*dd)); + memset(dd, 0, sizeof(*dd)); return error; #undef ATH_DESC_4KB_BOUND_CHECK #undef ATH_DESC_4KB_BOUND_NUM_SKIPPED @@ -1808,20 +1778,13 @@ void ath_descdma_cleanup(struct ath_softc *sc, INIT_LIST_HEAD(head); kfree(dd->dd_bufptr); - memzero(dd, sizeof(*dd)); + memset(dd, 0, sizeof(*dd)); } /*************/ /* Utilities */ /*************/ -void ath_internal_reset(struct ath_softc *sc) -{ - ath_reset_start(sc, 0); - ath_reset(sc); - ath_reset_end(sc, 0); -} - int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) { int qnum; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 673b3d81133..cb3e61e57c4 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -39,6 +39,8 @@ #include <linux/scatterlist.h> #include <asm/page.h> #include <net/mac80211.h> +#include <linux/leds.h> +#include <linux/rfkill.h> #include "ath9k.h" #include "rc.h" @@ -79,11 +81,8 @@ struct ath_node; } \ } while (0) -/* XXX: remove */ -#define memzero(_buf, _len) memset(_buf, 0, _len) - -#define get_dma_mem_context(var, field) (&((var)->field)) -#define copy_dma_mem_context(dst, src) (*dst = *src) +#define TSF_TO_TU(_h,_l) \ + ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) #define ATH9K_BH_STATUS_INTACT 0 #define ATH9K_BH_STATUS_CHANGE 1 @@ -95,6 +94,8 @@ static inline unsigned long get_timestamp(void) return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ); } +static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + /*************/ /* Debugging */ /*************/ @@ -175,42 +176,38 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht); /* Descriptor Management */ /*************************/ -/* Number of descriptors per buffer. The only case where we see skbuff -chains is due to FF aggregation in the driver. */ -#define ATH_TXDESC 1 -/* if there's more fragment for this MSDU */ -#define ATH_BF_MORE_MPDU 1 #define ATH_TXBUF_RESET(_bf) do { \ (_bf)->bf_status = 0; \ (_bf)->bf_lastbf = NULL; \ (_bf)->bf_lastfrm = NULL; \ (_bf)->bf_next = NULL; \ - memzero(&((_bf)->bf_state), \ + memset(&((_bf)->bf_state), 0, \ sizeof(struct ath_buf_state)); \ } while (0) +enum buffer_type { + BUF_DATA = BIT(0), + BUF_AGGR = BIT(1), + BUF_AMPDU = BIT(2), + BUF_HT = BIT(3), + BUF_RETRY = BIT(4), + BUF_XRETRY = BIT(5), + BUF_SHORT_PREAMBLE = BIT(6), + BUF_BAR = BIT(7), + BUF_PSPOLL = BIT(8), + BUF_AGGR_BURST = BIT(9), + BUF_CALC_AIRTIME = BIT(10), +}; + struct ath_buf_state { - int bfs_nframes; /* # frames in aggregate */ - u16 bfs_al; /* length of aggregate */ - u16 bfs_frmlen; /* length of frame */ - int bfs_seqno; /* sequence number */ - int bfs_tidno; /* tid of this frame */ - int bfs_retries; /* current retries */ + int bfs_nframes; /* # frames in aggregate */ + u16 bfs_al; /* length of aggregate */ + u16 bfs_frmlen; /* length of frame */ + int bfs_seqno; /* sequence number */ + int bfs_tidno; /* tid of this frame */ + int bfs_retries; /* current retries */ struct ath_rc_series bfs_rcs[4]; /* rate series */ - u8 bfs_isdata:1; /* is a data frame/aggregate */ - u8 bfs_isaggr:1; /* is an aggregate */ - u8 bfs_isampdu:1; /* is an a-mpdu, aggregate or not */ - u8 bfs_ht:1; /* is an HT frame */ - u8 bfs_isretried:1; /* is retried */ - u8 bfs_isxretried:1; /* is excessive retried */ - u8 bfs_shpreamble:1; /* is short preamble */ - u8 bfs_isbar:1; /* is a BAR */ - u8 bfs_ispspoll:1; /* is a PS-Poll */ - u8 bfs_aggrburst:1; /* is a aggr burst */ - u8 bfs_calcairtime:1; /* requests airtime be calculated - when set for tx frame */ - int bfs_rifsburst_elem; /* RIFS burst/bar */ - int bfs_nrifsubframes; /* # of elements in burst */ + u32 bf_type; /* BUF_* (enum buffer_type) */ /* key type use to encrypt this frame */ enum ath9k_key_type bfs_keytype; }; @@ -222,26 +219,22 @@ struct ath_buf_state { #define bf_seqno bf_state.bfs_seqno #define bf_tidno bf_state.bfs_tidno #define bf_rcs bf_state.bfs_rcs -#define bf_isdata bf_state.bfs_isdata -#define bf_isaggr bf_state.bfs_isaggr -#define bf_isampdu bf_state.bfs_isampdu -#define bf_ht bf_state.bfs_ht -#define bf_isretried bf_state.bfs_isretried -#define bf_isxretried bf_state.bfs_isxretried -#define bf_shpreamble bf_state.bfs_shpreamble -#define bf_rifsburst_elem bf_state.bfs_rifsburst_elem -#define bf_nrifsubframes bf_state.bfs_nrifsubframes #define bf_keytype bf_state.bfs_keytype -#define bf_isbar bf_state.bfs_isbar -#define bf_ispspoll bf_state.bfs_ispspoll -#define bf_aggrburst bf_state.bfs_aggrburst -#define bf_calcairtime bf_state.bfs_calcairtime +#define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA) +#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) +#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) +#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) +#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) +#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) +#define bf_isshpreamble(bf) (bf->bf_state.bf_type & BUF_SHORT_PREAMBLE) +#define bf_isbar(bf) (bf->bf_state.bf_type & BUF_BAR) +#define bf_ispspoll(bf) (bf->bf_state.bf_type & BUF_PSPOLL) +#define bf_isaggrburst(bf) (bf->bf_state.bf_type & BUF_AGGR_BURST) /* * Abstraction of a contiguous buffer to transmit/receive. There is only * a single hw descriptor encapsulated here. */ - struct ath_buf { struct list_head list; struct list_head *last; @@ -316,7 +309,7 @@ void ath_descdma_cleanup(struct ath_softc *sc, #define ATH_RX_TIMEOUT 40 /* 40 milliseconds */ #define WME_NUM_TID 16 #define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */ -#define IEEE80211_BAR_CTL_TID_S 2 /* tid shift */ +#define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */ enum ATH_RX_TYPE { ATH_RX_NON_CONSUMED = 0, @@ -391,10 +384,10 @@ int ath_rx_input(struct ath_softc *sc, struct sk_buff *skb, struct ath_recv_status *rx_status, enum ATH_RX_TYPE *status); -int ath__rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix); +int _ath_rx_indicate(struct ath_softc *sc, + struct sk_buff *skb, + struct ath_recv_status *status, + u16 keyix); int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, struct ath_recv_status *status); @@ -402,8 +395,7 @@ int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, /* TX */ /******/ -#define ATH_FRAG_PER_MSDU 1 -#define ATH_TXBUF (512/ATH_FRAG_PER_MSDU) +#define ATH_TXBUF 512 /* max number of transmit attempts (tries) */ #define ATH_TXMAXTRY 13 /* max number of 11n transmit attempts (tries) */ @@ -522,7 +514,6 @@ struct ath_tx_control { u32 keyix; int min_rate; int mcast_rate; - u16 nextfraglen; struct ath_softc *dev; dma_addr_t dmacontext; }; @@ -557,10 +548,10 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_setup(struct ath_softc *sc, int haltype); void ath_draintxq(struct ath_softc *sc, bool retry_tx); void ath_tx_draintxq(struct ath_softc *sc, - struct ath_txq *txq, bool retry_tx); + struct ath_txq *txq, bool retry_tx); void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); void ath_tx_node_cleanup(struct ath_softc *sc, - struct ath_node *an, bool bh_flag); + struct ath_node *an, bool bh_flag); void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_init(struct ath_softc *sc, int nbufs); @@ -575,6 +566,7 @@ u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum); void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth); void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ath_xmit_status *tx_status, struct ath_node *an); +void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); /**********************/ /* Node / Aggregation */ @@ -585,7 +577,6 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, /* indicates the node is 80211 power save */ #define ATH_NODE_PWRSAVE 0x2 -#define ADDBA_TIMEOUT 200 /* 200 milliseconds */ #define ADDBA_EXCHANGE_ATTEMPTS 10 #define ATH_AGGR_DELIM_SZ 4 /* delimiter size */ #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ @@ -705,9 +696,6 @@ struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr); #define ATH_BCBUF 4 /* number of beacon buffers */ #define ATH_DEFAULT_BINTVAL 100 /* default beacon interval in TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define ATH_BEACON_AIFS_DEFAULT 0 /* Default aifs for ap beacon q */ -#define ATH_BEACON_CWMIN_DEFAULT 0 /* Default cwmin for ap beacon q */ -#define ATH_BEACON_CWMAX_DEFAULT 0 /* Default cwmax for ap beacon q */ #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) /* beacon configuration */ @@ -724,30 +712,16 @@ struct ath_beacon_config { } u; /* last received beacon/probe response timestamp of this BSS. */ }; -/* offsets in a beacon frame for - * quick acess of beacon content by low-level driver */ -struct ath_beacon_offset { - u8 *bo_tim; /* start of atim/dtim */ -}; - void ath9k_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, int if_id); int ath_beaconq_setup(struct ath_hal *ah); int ath_beacon_alloc(struct ath_softc *sc, int if_id); void ath_bstuck_process(struct ath_softc *sc); -void ath_beacon_tasklet(struct ath_softc *sc, int *needmark); -void ath_beacon_free(struct ath_softc *sc); void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp); void ath_beacon_sync(struct ath_softc *sc, int if_id); -void ath_update_beacon_info(struct ath_softc *sc, int avgbrssi); void ath_get_beaconconfig(struct ath_softc *sc, int if_id, struct ath_beacon_config *conf); -int ath_update_beacon(struct ath_softc *sc, - int if_id, - struct ath_beacon_offset *bo, - struct sk_buff *skb, - int mcast); /********/ /* VAPs */ /********/ @@ -774,10 +748,8 @@ struct ath_vap { struct ieee80211_vif *av_if_data; enum ath9k_opmode av_opmode; /* VAP operational mode */ struct ath_buf *av_bcbuf; /* beacon buffer */ - struct ath_beacon_offset av_boff; /* dynamic update state */ struct ath_tx_control av_btxctl; /* txctl information for beacon */ int av_bslot; /* beacon slot index */ - struct ath_txq av_mcastq; /* multicast transmit queue */ struct ath_vap_config av_config;/* vap configuration parameters*/ struct ath_rate_node *rc_node; }; @@ -788,8 +760,7 @@ int ath_vap_attach(struct ath_softc *sc, enum ath9k_opmode opmode); int ath_vap_detach(struct ath_softc *sc, int if_id); int ath_vap_config(struct ath_softc *sc, - int if_id, struct ath_vap_config *if_config); -int ath_vap_listen(struct ath_softc *sc, int if_id); + int if_id, struct ath_vap_config *if_config); /*********************/ /* Antenna diversity */ @@ -829,6 +800,58 @@ void ath_slow_ant_div(struct ath_antdiv *antdiv, struct ath_rx_status *rx_stats); void ath_setdefantenna(void *sc, u32 antenna); +/*******/ +/* ANI */ +/*******/ + +/* ANI values for STA only. + FIXME: Add appropriate values for AP later */ + +#define ATH_ANI_POLLINTERVAL 100 /* 100 milliseconds between ANI poll */ +#define ATH_SHORT_CALINTERVAL 1000 /* 1 second between calibrations */ +#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds between calibrations */ +#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */ + +struct ath_ani { + bool sc_caldone; + int16_t sc_noise_floor; + unsigned int sc_longcal_timer; + unsigned int sc_shortcal_timer; + unsigned int sc_resetcal_timer; + unsigned int sc_checkani_timer; + struct timer_list timer; +}; + +/********************/ +/* LED Control */ +/********************/ + +#define ATH_LED_PIN 1 + +enum ath_led_type { + ATH_LED_RADIO, + ATH_LED_ASSOC, + ATH_LED_TX, + ATH_LED_RX +}; + +struct ath_led { + struct ath_softc *sc; + struct led_classdev led_cdev; + enum ath_led_type led_type; + char name[32]; + bool registered; +}; + +/* Rfkill */ +#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */ + +struct ath_rfkill { + struct rfkill *rfkill; + struct delayed_work rfkill_poll; + char rfkill_name[32]; +}; + /********************/ /* Main driver core */ /********************/ @@ -841,11 +864,7 @@ void ath_setdefantenna(void *sc, u32 antenna); #define ATH_DEFAULT_NOISE_FLOOR -95 #define ATH_REGCLASSIDS_MAX 10 #define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ -#define ATH_PREAMBLE_SHORT (1<<0) -#define ATH_PROTECT_ENABLE (1<<1) #define ATH_MAX_SW_RETRIES 10 -/* Num farmes difference in tx to flip default recv */ -#define ATH_ANTENNA_DIFF 2 #define ATH_CHAN_MAX 255 #define IEEE80211_WEP_NKID 4 /* number of key ids */ #define IEEE80211_RATE_VAL 0x7f @@ -859,9 +878,7 @@ void ath_setdefantenna(void *sc, u32 antenna); */ #define ATH_KEYMAX 128 /* max key cache size we handle */ -#define RESET_RETRY_TXQ 0x00000001 #define ATH_IF_ID_ANY 0xff - #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define RSSI_LPF_THRESHOLD -20 @@ -907,60 +924,64 @@ struct ath_ht_info { u8 ext_chan_offset; }; +#define SC_OP_INVALID BIT(0) +#define SC_OP_BEACONS BIT(1) +#define SC_OP_RXAGGR BIT(2) +#define SC_OP_TXAGGR BIT(3) +#define SC_OP_CHAINMASK_UPDATE BIT(4) +#define SC_OP_FULL_RESET BIT(5) +#define SC_OP_NO_RESET BIT(6) +#define SC_OP_PREAMBLE_SHORT BIT(7) +#define SC_OP_PROTECT_ENABLE BIT(8) +#define SC_OP_RXFLUSH BIT(9) +#define SC_OP_LED_ASSOCIATED BIT(10) +#define SC_OP_RFKILL_REGISTERED BIT(11) +#define SC_OP_RFKILL_SW_BLOCKED BIT(12) +#define SC_OP_RFKILL_HW_BLOCKED BIT(13) + struct ath_softc { struct ieee80211_hw *hw; struct pci_dev *pdev; - void __iomem *mem; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; - struct ath_config sc_config; /* load-time parameters */ - int sc_debug; + struct ath_config sc_config; struct ath_hal *sc_ah; - struct ath_rate_softc *sc_rc; /* tx rate control support */ + struct ath_rate_softc *sc_rc; + void __iomem *mem; + + u8 sc_curbssid[ETH_ALEN]; + u8 sc_myaddr[ETH_ALEN]; + u8 sc_bssidmask[ETH_ALEN]; + + int sc_debug; u32 sc_intrstatus; - enum ath9k_opmode sc_opmode; /* current operating mode */ - - u8 sc_invalid; /* being detached */ - u8 sc_beacons; /* beacons running */ - u8 sc_scanning; /* scanning active */ - u8 sc_txaggr; /* enable 11n tx aggregation */ - u8 sc_rxaggr; /* enable 11n rx aggregation */ - u8 sc_update_chainmask; /* change chain mask */ - u8 sc_full_reset; /* force full reset */ - enum wireless_mode sc_curmode; /* current phy mode */ + u32 sc_flags; /* SC_OP_* */ + unsigned int rx_filter; u16 sc_curtxpow; u16 sc_curaid; - u8 sc_curbssid[ETH_ALEN]; - u8 sc_myaddr[ETH_ALEN]; + u16 sc_cachelsz; + int sc_slotupdate; /* slot to next advance fsm */ + int sc_slottime; + int sc_bslot[ATH_BCBUF]; + u8 sc_tx_chainmask; + u8 sc_rx_chainmask; + enum ath9k_int sc_imask; + enum wireless_mode sc_curmode; /* current phy mode */ enum PROT_MODE sc_protmode; - u8 sc_mcastantenna; - u8 sc_txantenna; /* data tx antenna (fixed or auto) */ + u8 sc_nbcnvaps; /* # of vaps sending beacons */ u16 sc_nvaps; /* # of active virtual ap's */ struct ath_vap *sc_vaps[ATH_BCBUF]; - enum ath9k_int sc_imask; - u8 sc_bssidmask[ETH_ALEN]; + + u8 sc_mcastantenna; u8 sc_defant; /* current default antenna */ u8 sc_rxotherant; /* rx's on non-default antenna */ - u16 sc_cachelsz; - int sc_slotupdate; /* slot to next advance fsm */ - int sc_slottime; - u8 sc_noreset; - int sc_bslot[ATH_BCBUF]; + struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */ struct list_head node_list; struct ath_ht_info sc_ht_info; - int16_t sc_noise_floor; /* signal noise floor in dBm */ enum ath9k_ht_extprotspacing sc_ht_extprotspacing; - u8 sc_tx_chainmask; - u8 sc_rx_chainmask; - u8 sc_rxchaindetect_ref; - u8 sc_rxchaindetect_thresh5GHz; - u8 sc_rxchaindetect_thresh2GHz; - u8 sc_rxchaindetect_delta5GHz; - u8 sc_rxchaindetect_delta2GHz; - u32 sc_rtsaggrlimit; /* Chipset specific aggr limit */ - u32 sc_flags; + #ifdef CONFIG_SLOW_ANT_DIV struct ath_antdiv sc_antdiv; #endif @@ -974,15 +995,12 @@ struct ath_softc { u32 sc_keymax; /* size of key cache */ DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); /* key use bit map */ u8 sc_splitmic; /* split TKIP MIC keys */ - int sc_keytype; /* RX */ struct list_head sc_rxbuf; struct ath_descdma sc_rxdma; int sc_rxbufsize; /* rx size based on mtu */ u32 *sc_rxlink; /* link ptr in last RX desc */ - u32 sc_rxflush; /* rx flush in progress */ - u64 sc_lastrx; /* tsf of last rx'd frame */ /* TX */ struct list_head sc_txbuf; @@ -991,7 +1009,7 @@ struct ath_softc { u32 sc_txqsetup; u32 sc_txintrperiod; /* tx interrupt batching */ int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */ - u32 sc_ant_tx[8]; /* recent tx frames/antenna */ + u16 seq_no; /* TX sequence number */ /* Beacon */ struct ath9k_tx_queue_info sc_beacon_qi; @@ -1001,6 +1019,7 @@ struct ath_softc { u32 sc_bhalq; u32 sc_bmisscount; u32 ast_be_xmit; /* beacons transmitted */ + u64 bc_tstamp; /* Rate */ struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; @@ -1015,7 +1034,6 @@ struct ath_softc { /* Channel, Band */ struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - struct ath9k_channel sc_curchan; /* Locks */ spinlock_t sc_rxflushlock; @@ -1023,6 +1041,18 @@ struct ath_softc { spinlock_t sc_txbuflock; spinlock_t sc_resetlock; spinlock_t node_lock; + + /* LEDs */ + struct ath_led radio_led; + struct ath_led assoc_led; + struct ath_led tx_led; + struct ath_led rx_led; + + /* Rfkill */ + struct ath_rfkill rf_kill; + + /* ANI */ + struct ath_ani sc_ani; }; int ath_init(u16 devid, struct ath_softc *sc); @@ -1030,14 +1060,8 @@ void ath_deinit(struct ath_softc *sc); int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); int ath_suspend(struct ath_softc *sc); irqreturn_t ath_isr(int irq, void *dev); -int ath_reset(struct ath_softc *sc); -void ath_scan_start(struct ath_softc *sc); -void ath_scan_end(struct ath_softc *sc); +int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); -void ath_setup_rate(struct ath_softc *sc, - enum wireless_mode wMode, - enum RATE_TYPE type, - const struct ath9k_rate_table *rt); /*********************/ /* Utility Functions */ @@ -1056,17 +1080,5 @@ int ath_cabq_update(struct ath_softc *); void ath_get_currentCountry(struct ath_softc *sc, struct ath9k_country_entry *ctry); u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); -void ath_internal_reset(struct ath_softc *sc); -u32 ath_chan2flags(struct ieee80211_channel *chan, struct ath_softc *sc); -dma_addr_t ath_skb_map_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa); -void ath_skb_unmap_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa); -void ath_mcast_merge(struct ath_softc *sc, u32 mfilt[2]); -enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 6dbfed0b414..98bc25c9b3c 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -85,29 +85,6 @@ static const struct hal_percal_data adc_init_dc_cal = { ath9k_hw_adc_dccal_calibrate }; -static const struct ath_hal ar5416hal = { - AR5416_MAGIC, - 0, - 0, - NULL, - NULL, - CTRY_DEFAULT, - 0, - 0, - 0, - 0, - 0, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }, -}; - static struct ath9k_rate_table ar5416_11a_table = { 8, {0}, @@ -352,7 +329,7 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah) ah->ah_config.ofdm_trig_high = 500; ah->ah_config.cck_trig_high = 200; ah->ah_config.cck_trig_low = 100; - ah->ah_config.enable_ani = 0; + ah->ah_config.enable_ani = 1; ah->ah_config.noise_immunity_level = 4; ah->ah_config.ofdm_weaksignal_det = 1; ah->ah_config.cck_weaksignal_thr = 0; @@ -371,7 +348,7 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah) ah->ah_config.intr_mitigation = 0; } -static inline void ath9k_hw_override_ini(struct ath_hal *ah, +static void ath9k_hw_override_ini(struct ath_hal *ah, struct ath9k_channel *chan) { if (!AR_SREV_5416_V20_OR_LATER(ah) @@ -381,8 +358,8 @@ static inline void ath9k_hw_override_ini(struct ath_hal *ah, REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); } -static inline void ath9k_hw_init_bb(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_bb(struct ath_hal *ah, + struct ath9k_channel *chan) { u32 synthDelay; @@ -397,8 +374,8 @@ static inline void ath9k_hw_init_bb(struct ath_hal *ah, udelay(synthDelay + BASE_ACTIVATE_DELAY); } -static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, - enum ath9k_opmode opmode) +static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, + enum ath9k_opmode opmode) { struct ath_hal_5416 *ahp = AH5416(ah); @@ -428,7 +405,7 @@ static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, } } -static inline void ath9k_hw_init_qos(struct ath_hal *ah) +static void ath9k_hw_init_qos(struct ath_hal *ah) { REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); @@ -523,7 +500,7 @@ static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, return ath9k_hw_eeprom_read(ah, off, data); } -static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416_eeprom *eep = &ahp->ah_eeprom; @@ -790,7 +767,7 @@ ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, return true; } -static inline int ath9k_hw_check_eeprom(struct ath_hal *ah) +static int ath9k_hw_check_eeprom(struct ath_hal *ah) { u32 sum = 0, el; u16 *eepdata; @@ -1196,11 +1173,12 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, ah = &ahp->ah; - memcpy(&ahp->ah, &ar5416hal, sizeof(struct ath_hal)); - ah->ah_sc = sc; ah->ah_sh = mem; + ah->ah_magic = AR5416_MAGIC; + ah->ah_countryCode = CTRY_DEFAULT; + ah->ah_devid = devid; ah->ah_subvendorid = 0; @@ -1294,7 +1272,7 @@ u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, } } -static inline int ath9k_hw_get_radiorev(struct ath_hal *ah) +static int ath9k_hw_get_radiorev(struct ath_hal *ah) { u32 val; int i; @@ -1307,7 +1285,7 @@ static inline int ath9k_hw_get_radiorev(struct ath_hal *ah) return ath9k_hw_reverse_bits(val, 8); } -static inline int ath9k_hw_init_macaddr(struct ath_hal *ah) +static int ath9k_hw_init_macaddr(struct ath_hal *ah) { u32 sum; int i; @@ -1389,7 +1367,7 @@ static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, return spur_val; } -static inline int ath9k_hw_rfattach(struct ath_hal *ah) +static int ath9k_hw_rfattach(struct ath_hal *ah) { bool rfStatus = false; int ecode = 0; @@ -1434,8 +1412,8 @@ static int ath9k_hw_rf_claim(struct ath_hal *ah) return 0; } -static inline void ath9k_hw_init_pll(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_pll(struct ath_hal *ah, + struct ath9k_channel *chan) { u32 pll; @@ -1553,7 +1531,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) } } -static inline void +static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) { u32 rfMode = 0; @@ -1623,7 +1601,7 @@ static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) return true; } -static inline bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) +static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) { REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); @@ -1664,7 +1642,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, } } -static inline +static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, struct ath9k_channel *chan) { @@ -2098,7 +2076,7 @@ static void ath9k_hw_ani_attach(struct ath_hal *ah) ahp->ah_procPhyErr |= HAL_PROCESS_ANI; } -static inline void ath9k_hw_ani_setup(struct ath_hal *ah) +static void ath9k_hw_ani_setup(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); int i; @@ -2548,6 +2526,11 @@ static void ath9k_ani_reset(struct ath_hal *ah) } } +/* + * Process a MIB interrupt. We may potentially be invoked because + * any of the MIB counters overflow/trigger so don't assume we're + * here because a PHY error counter triggered. + */ void ath9k_hw_procmibevent(struct ath_hal *ah, const struct ath9k_node_stats *stats) { @@ -2555,18 +2538,20 @@ void ath9k_hw_procmibevent(struct ath_hal *ah, u32 phyCnt1, phyCnt2; DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n"); - + /* Reset these counters regardless */ REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); + /* Clear the mib counters and save them in the stats */ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); ahp->ah_stats.ast_nodestats = *stats; if (!DO_ANI(ah)) return; + /* NB: these are not reset-on-read */ phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || @@ -2574,6 +2559,7 @@ void ath9k_hw_procmibevent(struct ath_hal *ah, struct ar5416AniState *aniState = ahp->ah_curani; u32 ofdmPhyErrCnt, cckPhyErrCnt; + /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; ahp->ah_stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; @@ -2584,11 +2570,17 @@ void ath9k_hw_procmibevent(struct ath_hal *ah, cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; + /* + * NB: figure out which counter triggered. If both + * trigger we'll only deal with one as the processing + * clobbers the error counter so the trigger threshold + * check will never be true. + */ if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) ath9k_hw_ani_ofdm_err_trigger(ah); if (aniState->cckPhyErrCount > aniState->cckTrigHigh) ath9k_hw_ani_cck_err_trigger(ah); - + /* NB: always restart to insure the h/w counters are reset */ ath9k_ani_restart(ah); } } @@ -2822,32 +2814,11 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, } } -static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, - enum ath9k_gpio_output_mux_type - halSignalType) +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type) { - u32 ah_signal_type; u32 gpio_shift; - static u32 MuxSignalConversionTable[] = { - - AR_GPIO_OUTPUT_MUX_AS_OUTPUT, - - AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, - - AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, - - AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, - - AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, - }; - - if ((halSignalType >= 0) - && (halSignalType < ARRAY_SIZE(MuxSignalConversionTable))) - ah_signal_type = MuxSignalConversionTable[halSignalType]; - else - return false; - ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); gpio_shift = 2 * gpio; @@ -2856,19 +2827,46 @@ static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, AR_GPIO_OE_OUT, (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), (AR_GPIO_OE_OUT_DRV << gpio_shift)); - - return true; } -static bool ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, - u32 val) +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) { REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), AR_GPIO_BIT(gpio)); - return true; } -static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) +/* + * Configure GPIO Input lines + */ +void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) +{ + u32 gpio_shift; + + ASSERT(gpio < ah->ah_caps.num_gpio_pins); + + gpio_shift = gpio << 1; + + REG_RMW(ah, + AR_GPIO_OE_OUT, + (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); +} + +#ifdef CONFIG_RFKILL +static void ath9k_enable_rfkill(struct ath_hal *ah) +{ + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); + + REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, + AR_GPIO_INPUT_MUX2_RFSILENT); + + ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio); + REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); +} +#endif + +u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) { if (gpio >= ah->ah_caps.num_gpio_pins) return 0xffffffff; @@ -2883,7 +2881,7 @@ static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) } } -static inline int ath9k_hw_post_attach(struct ath_hal *ah) +static int ath9k_hw_post_attach(struct ath_hal *ah) { int ecode; @@ -3081,17 +3079,17 @@ static bool ath9k_hw_fill_cap_info(struct ath_hal *ah) pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; +#ifdef CONFIG_RFKILL ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT); if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { - ahp->ah_gpioSelect = + ah->ah_rfkill_gpio = MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); - ahp->ah_polarity = + ah->ah_rfkill_polarity = MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); - ath9k_hw_setcapability(ah, ATH9K_CAP_RFSILENT, 1, true, - NULL); pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; } +#endif if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) || (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) || @@ -3595,7 +3593,7 @@ static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, return true; } -static inline void +static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, struct ath9k_channel *chan, struct cal_data_per_freq *pRawDataSet, @@ -3777,7 +3775,7 @@ ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, return; } -static inline bool +static bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, struct ar5416_eeprom *pEepData, struct ath9k_channel *chan, @@ -3980,7 +3978,7 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) } } -static inline void +static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, struct ath9k_channel *chan, struct cal_target_power_leg *powInfo, @@ -4046,7 +4044,7 @@ ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, } } -static inline void +static void ath9k_hw_get_target_powers(struct ath_hal *ah, struct ath9k_channel *chan, struct cal_target_power_ht *powInfo, @@ -4113,7 +4111,7 @@ ath9k_hw_get_target_powers(struct ath_hal *ah, } } -static inline u16 +static u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, bool is2GHz) @@ -4143,7 +4141,7 @@ ath9k_hw_get_max_edge_power(u16 freq, return twiceMaxEdgePower; } -static inline bool +static bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, struct ar5416_eeprom *pEepData, struct ath9k_channel *chan, @@ -5122,7 +5120,7 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -static inline void ath9k_hw_init_chain_masks(struct ath_hal *ah) +static void ath9k_hw_init_chain_masks(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); int rx_chainmask, tx_chainmask; @@ -5326,7 +5324,7 @@ bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) } } -static inline void ath9k_hw_init_user_settings(struct ath_hal *ah) +static void ath9k_hw_init_user_settings(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); @@ -5345,7 +5343,7 @@ static inline void ath9k_hw_init_user_settings(struct ath_hal *ah) ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); } -static inline int +static int ath9k_hw_process_ini(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) @@ -5476,7 +5474,7 @@ ath9k_hw_process_ini(struct ath_hal *ah, return 0; } -static inline void ath9k_hw_setup_calibration(struct ath_hal *ah, +static void ath9k_hw_setup_calibration(struct ath_hal *ah, struct hal_cal_list *currCal) { REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), @@ -5512,8 +5510,8 @@ static inline void ath9k_hw_setup_calibration(struct ath_hal *ah, AR_PHY_TIMING_CTRL4_DO_CAL); } -static inline void ath9k_hw_reset_calibration(struct ath_hal *ah, - struct hal_cal_list *currCal) +static void ath9k_hw_reset_calibration(struct ath_hal *ah, + struct hal_cal_list *currCal) { struct ath_hal_5416 *ahp = AH5416(ah); int i; @@ -5532,7 +5530,7 @@ static inline void ath9k_hw_reset_calibration(struct ath_hal *ah, ahp->ah_CalSamples = 0; } -static inline void +static void ath9k_hw_per_calibration(struct ath_hal *ah, struct ath9k_channel *ichan, u8 rxchainmask, @@ -5622,7 +5620,7 @@ static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah, return true; } -static inline bool +static bool ath9k_hw_channel_change(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) @@ -5799,8 +5797,8 @@ static bool ath9k_hw_iscal_supported(struct ath_hal *ah, return retval; } -static inline bool ath9k_hw_init_cal(struct ath_hal *ah, - struct ath9k_channel *chan) +static bool ath9k_hw_init_cal(struct ath_hal *ah, + struct ath9k_channel *chan) { struct ath_hal_5416 *ahp = AH5416(ah); struct ath9k_channel *ichan = @@ -5861,7 +5859,7 @@ static inline bool ath9k_hw_init_cal(struct ath_hal *ah, } -bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, @@ -5869,7 +5867,6 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, bool bChannelChange, int *status) { -#define FAIL(_code) do { ecode = _code; goto bad; } while (0) u32 saveLedState; struct ath_hal_5416 *ahp = AH5416(ah); struct ath9k_channel *curchan = ah->ah_curchan; @@ -5891,11 +5888,14 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->channel, chan->channelFlags); - FAIL(-EINVAL); + ecode = -EINVAL; + goto bad; } - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { + ecode = -EIO; + goto bad; + } if (curchan) ath9k_hw_getnf(ah, curchan); @@ -5932,7 +5932,8 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, if (!ath9k_hw_chip_reset(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n", __func__); - FAIL(-EIO); + ecode = -EINVAL; + goto bad; } if (AR_SREV_9280(ah)) { @@ -5945,12 +5946,14 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, else ath9k_hw_set_gpio(ah, 9, 1); } - ath9k_hw_cfg_output(ah, 9, ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); } ecode = ath9k_hw_process_ini(ah, chan, macmode); - if (ecode != 0) + if (ecode != 0) { + ecode = -EINVAL; goto bad; + } if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) ath9k_hw_set_delta_slope(ah, chan); @@ -5963,7 +5966,8 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, if (!ath9k_hw_eeprom_set_board_values(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: error setting board options\n", __func__); - FAIL(-EIO); + ecode = -EIO; + goto bad; } ath9k_hw_decrease_chain_power(ah, chan); @@ -5975,7 +5979,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, | (ah->ah_config. ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0) | ahp->ah_staId1Defaults); - ath9k_hw_set_operating_mode(ah, opmode); + ath9k_hw_set_operating_mode(ah, ah->ah_opmode); REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); @@ -5991,11 +5995,15 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); if (AR_SREV_9280_10_OR_LATER(ah)) { - if (!(ath9k_hw_ar9280_set_channel(ah, chan))) - FAIL(-EIO); + if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { + ecode = -EIO; + goto bad; + } } else { - if (!(ath9k_hw_set_channel(ah, chan))) - FAIL(-EIO); + if (!(ath9k_hw_set_channel(ah, chan))) { + ecode = -EIO; + goto bad; + } } for (i = 0; i < AR_NUM_DCU; i++) @@ -6005,13 +6013,15 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, for (i = 0; i < ah->ah_caps.total_queues; i++) ath9k_hw_resettxqueue(ah, i); - ath9k_hw_init_interrupt_masks(ah, opmode); + ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode); ath9k_hw_init_qos(ah); +#ifdef CONFIG_RFKILL + if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + ath9k_enable_rfkill(ah); +#endif ath9k_hw_init_user_settings(ah); - ah->ah_opmode = opmode; - REG_WRITE(ah, AR_STA_ID1, REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); @@ -6027,8 +6037,10 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, ath9k_hw_init_bb(ah, chan); - if (!ath9k_hw_init_cal(ah, chan)) - FAIL(-ENODEV); + if (!ath9k_hw_init_cal(ah, chan)){ + ecode = -EIO;; + goto bad; + } rx_chainmask = ahp->ah_rxchainmask; if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { @@ -6064,7 +6076,6 @@ bad: if (status) *status = ecode; return false; -#undef FAIL } bool ath9k_hw_phy_disable(struct ath_hal *ah) @@ -6539,31 +6550,6 @@ ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) return true; } -#ifdef CONFIG_ATH9K_RFKILL -static void ath9k_enable_rfkill(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); - - REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, - AR_GPIO_INPUT_MUX2_RFSILENT); - - ath9k_hw_cfg_gpio_input(ah, ahp->ah_gpioSelect); - REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); - - if (ahp->ah_gpioBit == ath9k_hw_gpio_get(ah, ahp->ah_gpioSelect)) { - - ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect, - !ahp->ah_gpioBit); - } else { - ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect, - ahp->ah_gpioBit); - } -} -#endif - void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId) @@ -7678,8 +7664,7 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) REG_WRITE(ah, AR_DRETRY_LIMIT(q), SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) - | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH) - ); + | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); REG_WRITE(ah, AR_DMISC(q), @@ -8324,15 +8309,7 @@ struct ath_hal *ath9k_hw_attach(u16 devid, *error = -ENXIO; break; } - if (ah != NULL) { - ah->ah_devid = ah->ah_devid; - ah->ah_subvendorid = ah->ah_subvendorid; - ah->ah_macVersion = ah->ah_macVersion; - ah->ah_macRev = ah->ah_macRev; - ah->ah_phyRev = ah->ah_phyRev; - ah->ah_analog5GhzRev = ah->ah_analog5GhzRev; - ah->ah_analog2GhzRev = ah->ah_analog2GhzRev; - } + return ah; } @@ -8439,23 +8416,48 @@ u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) } } -int16_t +/* We can tune this as we go by monitoring really low values */ +#define ATH9K_NF_TOO_LOW -60 + +/* AR5416 may return very high value (like -31 dBm), in those cases the nf + * is incorrect and we should use the static NF value. Later we can try to + * find out why they are reporting these values */ +static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) +{ + if (nf > ATH9K_NF_TOO_LOW) { + DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + "%s: noise floor value detected (%d) is " + "lower than what we think is a " + "reasonable value (%d)\n", + __func__, nf, ATH9K_NF_TOO_LOW); + return false; + } + return true; +} + +s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) { struct ath9k_channel *ichan; + s16 nf; ichan = ath9k_regd_check_channel(ah, chan); if (ichan == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->channel, chan->channelFlags); - return 0; + return ATH_DEFAULT_NOISE_FLOOR; } if (ichan->rawNoiseFloor == 0) { enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); - return NOISE_FLOOR[mode]; + nf = NOISE_FLOOR[mode]; } else - return ichan->rawNoiseFloor; + nf = ichan->rawNoiseFloor; + + if (!ath9k_hw_nf_in_range(ah, nf)) + nf = ATH_DEFAULT_NOISE_FLOOR; + + return nf; } bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index ae680f21ba7..2113818ee93 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -314,14 +314,11 @@ struct ar5416_desc { #define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \ MS(ads->ds_rxstatus0, AR_RxRate) : \ (ads->ds_rxstatus3 >> 2) & 0xFF) -#define RXSTATUS_DUPLICATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \ - MS(ads->ds_rxstatus3, AR_Parallel40) : \ - (ads->ds_rxstatus3 >> 10) & 0x1) -#define set11nTries(_series, _index) \ +#define set11nTries(_series, _index) \ (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) -#define set11nRate(_series, _index) \ +#define set11nRate(_series, _index) \ (SM((_series)[_index].Rate, AR_XmitRate##_index)) #define set11nPktDurRTSCTS(_series, _index) \ @@ -330,11 +327,11 @@ struct ar5416_desc { AR_RTSCTSQual##_index : 0)) #define set11nRateFlags(_series, _index) \ - (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \ - AR_2040_##_index : 0) \ - |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ - AR_GI##_index : 0) \ - |SM((_series)[_index].ChSel, AR_ChainSel##_index)) + (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \ + AR_2040_##_index : 0) \ + |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ + AR_GI##_index : 0) \ + |SM((_series)[_index].ChSel, AR_ChainSel##_index)) #define AR_SREV_9100(ah) ((ah->ah_macVersion) == AR_SREV_VERSION_9100) @@ -346,9 +343,6 @@ struct ar5416_desc { #define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1) #define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD -#define NUM_CORNER_FIX_BITS_2133 7 -#define CCK_OFDM_GAIN_DELTA 15 - struct ar5416AniState { struct ath9k_channel c; u8 noiseImmunityLevel; @@ -377,11 +371,8 @@ struct ar5416AniState { }; #define HAL_PROCESS_ANI 0x00000001 -#define HAL_RADAR_EN 0x80000000 -#define HAL_AR_EN 0x40000000 - #define DO_ANI(ah) \ - ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI)) + ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI)) struct ar5416Stats { u32 ast_ani_niup; @@ -425,7 +416,6 @@ struct ar5416Stats { #define AR5416_EEP_MINOR_VER_7 0x7 #define AR5416_EEP_MINOR_VER_9 0x9 -#define AR5416_EEP_START_LOC 256 #define AR5416_NUM_5G_CAL_PIERS 8 #define AR5416_NUM_2G_CAL_PIERS 4 #define AR5416_NUM_5G_20_TARGET_POWERS 8 @@ -441,25 +431,10 @@ struct ar5416Stats { #define AR5416_EEPROM_MODAL_SPURS 5 #define AR5416_MAX_RATE_POWER 63 #define AR5416_NUM_PDADC_VALUES 128 -#define AR5416_NUM_RATES 16 #define AR5416_BCHAN_UNUSED 0xFF #define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 -#define AR5416_EEPMISC_BIG_ENDIAN 0x01 #define AR5416_MAX_CHAINS 3 -#define AR5416_ANT_16S 25 - -#define AR5416_NUM_ANT_CHAIN_FIELDS 7 -#define AR5416_NUM_ANT_COMMON_FIELDS 4 -#define AR5416_SIZE_ANT_CHAIN_FIELD 3 -#define AR5416_SIZE_ANT_COMMON_FIELD 4 -#define AR5416_ANT_CHAIN_MASK 0x7 -#define AR5416_ANT_COMMON_MASK 0xf -#define AR5416_CHAIN_0_IDX 0 -#define AR5416_CHAIN_1_IDX 1 -#define AR5416_CHAIN_2_IDX 2 - #define AR5416_PWR_TABLE_OFFSET -5 -#define AR5416_LEGACY_CHAINMASK 1 enum eeprom_param { EEP_NFTHRESH_5, @@ -633,7 +608,7 @@ struct ar5416IniArray { }; #define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ - (iniarray)->ia_array = (u32 *)(array); \ + (iniarray)->ia_array = (u32 *)(array); \ (iniarray)->ia_rows = (rows); \ (iniarray)->ia_columns = (columns); \ } while (0) @@ -641,16 +616,16 @@ struct ar5416IniArray { #define INI_RA(iniarray, row, column) \ (((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)]) -#define INIT_CAL(_perCal) do { \ - (_perCal)->calState = CAL_WAITING; \ - (_perCal)->calNext = NULL; \ +#define INIT_CAL(_perCal) do { \ + (_perCal)->calState = CAL_WAITING; \ + (_perCal)->calNext = NULL; \ } while (0) #define INSERT_CAL(_ahp, _perCal) \ do { \ if ((_ahp)->ah_cal_list_last == NULL) { \ - (_ahp)->ah_cal_list = \ - (_ahp)->ah_cal_list_last = (_perCal); \ + (_ahp)->ah_cal_list = \ + (_ahp)->ah_cal_list_last = (_perCal); \ ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \ } else { \ ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \ @@ -696,25 +671,29 @@ struct hal_cal_list { struct ath_hal_5416 { struct ath_hal ah; struct ar5416_eeprom ah_eeprom; + struct ar5416Stats ah_stats; + struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; + void __iomem *ah_cal_mem; + u8 ah_macaddr[ETH_ALEN]; u8 ah_bssid[ETH_ALEN]; u8 ah_bssidmask[ETH_ALEN]; u16 ah_assocId; + int16_t ah_curchanRadIndex; u32 ah_maskReg; - struct ar5416Stats ah_stats; - u32 ah_txDescMask; u32 ah_txOkInterruptMask; u32 ah_txErrInterruptMask; u32 ah_txDescInterruptMask; u32 ah_txEolInterruptMask; u32 ah_txUrnInterruptMask; - struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; - enum ath9k_power_mode ah_powerMode; bool ah_chipFullSleep; u32 ah_atimWindow; - enum ath9k_ant_setting ah_diversityControl; u16 ah_antennaSwitchSwap; + enum ath9k_power_mode ah_powerMode; + enum ath9k_ant_setting ah_diversityControl; + + /* Calibration */ enum hal_cal_types ah_suppCals; struct hal_cal_list ah_iqCalData; struct hal_cal_list ah_adcGainCalData; @@ -751,16 +730,16 @@ struct ath_hal_5416 { int32_t sign[AR5416_MAX_CHAINS]; } ah_Meas3; u16 ah_CalSamples; - u32 ah_tx6PowerInHalfDbm; + u32 ah_staId1Defaults; u32 ah_miscMode; - bool ah_tpcEnabled; - u32 ah_beaconInterval; enum { AUTO_32KHZ, USE_32KHZ, DONT_USE_32KHZ, } ah_enable32kHzClock; + + /* RF */ u32 *ah_analogBank0Data; u32 *ah_analogBank1Data; u32 *ah_analogBank2Data; @@ -770,8 +749,9 @@ struct ath_hal_5416 { u32 *ah_analogBank7Data; u32 *ah_addac5416_21; u32 *ah_bank6Temp; - u32 ah_ofdmTxPower; + int16_t ah_txPowerIndexOffset; + u32 ah_beaconInterval; u32 ah_slottime; u32 ah_acktimeout; u32 ah_ctstimeout; @@ -780,7 +760,8 @@ struct ath_hal_5416 { u32 ah_gpioSelect; u32 ah_polarity; u32 ah_gpioBit; - bool ah_eepEnabled; + + /* ANI */ u32 ah_procPhyErr; bool ah_hasHwPhyCounters; u32 ah_aniPeriod; @@ -790,18 +771,14 @@ struct ath_hal_5416 { int ah_coarseHigh[5]; int ah_coarseLow[5]; int ah_firpwr[5]; - u16 ah_ratesArray[16]; + enum ath9k_ani_cmd ah_ani_function; + u32 ah_intrTxqs; bool ah_intrMitigation; - u32 ah_cycleCount; - u32 ah_ctlBusy; - u32 ah_extBusy; enum ath9k_ht_extprotspacing ah_extprotspacing; u8 ah_txchainmask; u8 ah_rxchainmask; - int ah_hwp; - void __iomem *ah_cal_mem; - enum ath9k_ani_cmd ah_ani_function; + struct ar5416IniArray ah_iniModes; struct ar5416IniArray ah_iniCommon; struct ar5416IniArray ah_iniBank0; @@ -820,10 +797,6 @@ struct ath_hal_5416 { #define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) -#define IS_5416_EMU(ah) \ - ((ah->ah_devid == AR5416_DEVID_EMU) || \ - (ah->ah_devid == AR5416_DEVID_EMU_PCIE)) - #define ar5416RfDetach(ah) do { \ if (AH5416(ah)->ah_rfHal.rfDetach != NULL) \ AH5416(ah)->ah_rfHal.rfDetach(ah); \ @@ -841,8 +814,8 @@ struct ath_hal_5416 { #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))); \ + REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ + INI_RA((iniarray), r, (column))); \ DO_DELAY(regWr); \ } \ } while (0) @@ -852,30 +825,21 @@ struct ath_hal_5416 { #define COEF_SCALE_S 24 #define HT40_CHANNEL_CENTER_SHIFT 10 -#define ar5416CheckOpMode(_opmode) \ - ((_opmode == ATH9K_M_STA) || (_opmode == ATH9K_M_IBSS) || \ - (_opmode == ATH9K_M_HOSTAP) || (_opmode == ATH9K_M_MONITOR)) - #define AR5416_EEPROM_MAGIC_OFFSET 0x0 #define AR5416_EEPROM_S 2 #define AR5416_EEPROM_OFFSET 0x2000 -#define AR5416_EEPROM_START_ADDR \ +#define AR5416_EEPROM_START_ADDR \ (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 #define AR5416_EEPROM_MAX 0xae0 -#define ar5416_get_eep_ver(_ahp) \ +#define ar5416_get_eep_ver(_ahp) \ (((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF) -#define ar5416_get_eep_rev(_ahp) \ +#define ar5416_get_eep_rev(_ahp) \ (((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF) -#define ar5416_get_ntxchains(_txchainmask) \ +#define ar5416_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) -#define IS_EEP_MINOR_V3(_ahp) \ - (ath9k_hw_get_eeprom((_ahp), EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_3) - -#define FIXED_CCA_THRESHOLD 15 - #ifdef __BIG_ENDIAN #define AR5416_EEPROM_MAGIC 0x5aa5 #else @@ -910,8 +874,6 @@ struct ath_hal_5416 { #define AR_GPIOD_MASK 0x00001FFF #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) -#define MAX_ANALOG_START 319 - #define HAL_EP_RND(x, mul) \ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) #define BEACON_RSSI(ahp) \ @@ -923,8 +885,6 @@ struct ath_hal_5416 { #define AH_TIMEOUT 100000 #define AH_TIME_QUANTUM 10 -#define IS(_c, _f) (((_c)->channelFlags & _f) || 0) - #define AR_KEYTABLE_SIZE 128 #define POWER_UP_TIME 200000 @@ -964,6 +924,6 @@ struct ath_hal_5416 { #define OFDM_SYMBOL_TIME_QUARTER 16 u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, - enum eeprom_param param); + enum eeprom_param param); #endif diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index c5107f269f2..f05f584ab7b 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -22,8 +22,6 @@ #define ATH_PCI_VERSION "0.1" #define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 -#define IEEE80211_ACTION_CAT_HT 7 -#define IEEE80211_ACTION_HT_TXCHWIDTH 0 static char *dev_info = "ath9k"; @@ -142,7 +140,7 @@ static int ath_key_config(struct ath_softc *sc, struct ath9k_keyval hk; const u8 *mac = NULL; int ret = 0; - enum ieee80211_if_types opmode; + enum nl80211_iftype opmode; memset(&hk, 0, sizeof(hk)); @@ -181,14 +179,14 @@ static int ath_key_config(struct ath_softc *sc, */ if (is_broadcast_ether_addr(addr)) { switch (opmode) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: /* default key: could be group WPA key * or could be static WEP key */ mac = NULL; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: break; - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: break; default: ASSERT(0); @@ -206,37 +204,30 @@ static int ath_key_config(struct ath_softc *sc, if (!ret) return -EIO; - if (mac) - sc->sc_keytype = hk.kv_type; return 0; } static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) { -#define ATH_MAX_NUM_KEYS 4 int freeslot; - freeslot = (key->keyidx >= ATH_MAX_NUM_KEYS) ? 1 : 0; + freeslot = (key->keyidx >= 4) ? 1 : 0; ath_key_reset(sc, key->keyidx, freeslot); -#undef ATH_MAX_NUM_KEYS } static void setup_ht_cap(struct ieee80211_ht_info *ht_info) { -/* Until mac80211 includes these fields */ - -#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 -#define IEEE80211_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ -#define IEEE80211_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ +#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ +#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ ht_info->ht_supported = 1; ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH - |(u16)IEEE80211_HT_CAP_MIMO_PS + |(u16)IEEE80211_HT_CAP_SM_PS |(u16)IEEE80211_HT_CAP_SGI_40 |(u16)IEEE80211_HT_CAP_DSSSCCK40; - ht_info->ampdu_factor = IEEE80211_HT_CAP_MAXRXAMPDU_65536; - ht_info->ampdu_density = IEEE80211_HT_CAP_MPDUDENSITY_8; + ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; + ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; /* setup supported mcs set */ memset(ht_info->supp_mcs_set, 0, 16); ht_info->supp_mcs_set[0] = 0xff; @@ -283,10 +274,12 @@ static void ath9k_rx_prepare(struct ath_softc *sc, rx_status->mactime = status->tsf; rx_status->band = curchan->band; rx_status->freq = curchan->center_freq; - rx_status->noise = ATH_DEFAULT_NOISE_FLOOR; + rx_status->noise = sc->sc_ani.sc_noise_floor; rx_status->signal = rx_status->noise + status->rssi; rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100)); rx_status->antenna = status->antenna; + + /* XXX Fix me, 64 cannot be the max rssi value, rigure it out */ rx_status->qual = status->rssi * 100 / 64; if (status->flags & ATH_RX_MIC_ERROR) @@ -332,6 +325,698 @@ static u8 parse_mpdudensity(u8 mpdudensity) } } +static void ath9k_ht_conf(struct ath_softc *sc, + struct ieee80211_bss_conf *bss_conf) +{ +#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) + struct ath_ht_info *ht_info = &sc->sc_ht_info; + + if (bss_conf->assoc_ht) { + ht_info->ext_chan_offset = + bss_conf->ht_bss_conf->bss_cap & + IEEE80211_HT_IE_CHA_SEC_OFFSET; + + if (!(bss_conf->ht_conf->cap & + IEEE80211_HT_CAP_40MHZ_INTOLERANT) && + (bss_conf->ht_bss_conf->bss_cap & + IEEE80211_HT_IE_CHA_WIDTH)) + ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; + else + ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; + + ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); + ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + bss_conf->ht_conf->ampdu_factor); + ht_info->mpdudensity = + parse_mpdudensity(bss_conf->ht_conf->ampdu_density); + + } + +#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT +} + +static void ath9k_bss_assoc_info(struct ath_softc *sc, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_channel *curchan = hw->conf.channel; + struct ath_vap *avp; + int pos; + DECLARE_MAC_BUF(mac); + + if (bss_conf->assoc) { + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", + __func__, + bss_conf->aid); + + avp = sc->sc_vaps[0]; + if (avp == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", + __func__); + return; + } + + /* New association, store aid */ + if (avp->av_opmode == ATH9K_M_STA) { + sc->sc_curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, + sc->sc_curaid); + } + + /* Configure the beacon */ + ath_beacon_config(sc, 0); + sc->sc_flags |= SC_OP_BEACONS; + + /* Reset rssi stats */ + sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + + /* Update chainmask */ + ath_update_chainmask(sc, bss_conf->assoc_ht); + + DPRINTF(sc, ATH_DBG_CONFIG, + "%s: bssid %s aid 0x%x\n", + __func__, + print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", + __func__, + curchan->center_freq); + + pos = ath_get_channel(sc, curchan); + if (pos == -1) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Invalid channel\n", __func__); + return; + } + + if (hw->conf.ht_conf.ht_supported) + sc->sc_ah->ah_channels[pos].chanmode = + ath_get_extchanmode(sc, curchan); + else + sc->sc_ah->ah_channels[pos].chanmode = + (curchan->band == IEEE80211_BAND_2GHZ) ? + CHANNEL_G : CHANNEL_A; + + /* set h/w channel */ + if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to set channel\n", + __func__); + + ath_rate_newstate(sc, avp); + /* Update ratectrl about the new state */ + ath_rc_node_update(hw, avp->rc_node); + + /* Start ANI */ + mod_timer(&sc->sc_ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + + } else { + DPRINTF(sc, ATH_DBG_CONFIG, + "%s: Bss Info DISSOC\n", __func__); + sc->sc_curaid = 0; + } +} + +void ath_get_beaconconfig(struct ath_softc *sc, + int if_id, + struct ath_beacon_config *conf) +{ + struct ieee80211_hw *hw = sc->hw; + + /* fill in beacon config data */ + + conf->beacon_interval = hw->conf.beacon_int; + conf->listen_interval = 100; + conf->dtim_count = 1; + conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; +} + +void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, + struct ath_xmit_status *tx_status, struct ath_node *an) +{ + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + + DPRINTF(sc, ATH_DBG_XMIT, + "%s: TX complete: skb: %p\n", __func__, skb); + + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || + tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + /* free driver's private data area of tx_info */ + if (tx_info->driver_data[0] != NULL) + kfree(tx_info->driver_data[0]); + tx_info->driver_data[0] = NULL; + } + + if (tx_status->flags & ATH_TX_BAR) { + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + tx_status->flags &= ~ATH_TX_BAR; + } + + if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { + /* Frame was not ACKed, but an ACK was expected */ + tx_info->status.excessive_retries = 1; + } + } else { + /* Frame was ACKed */ + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } + + tx_info->status.retry_count = tx_status->retries; + + ieee80211_tx_status(hw, skb); + if (an) + ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); +} + +int _ath_rx_indicate(struct ath_softc *sc, + struct sk_buff *skb, + struct ath_recv_status *status, + u16 keyix) +{ + struct ieee80211_hw *hw = sc->hw; + struct ath_node *an = NULL; + struct ieee80211_rx_status rx_status; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + int hdrlen = ieee80211_get_hdrlen_from_skb(skb); + int padsize; + enum ATH_RX_TYPE st; + + /* see if any padding is done by the hw and remove it */ + if (hdrlen & 3) { + padsize = hdrlen % 4; + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); + } + + /* Prepare rx status */ + ath9k_rx_prepare(sc, skb, status, &rx_status); + + if (!(keyix == ATH9K_RXKEYIX_INVALID) && + !(status->flags & ATH_RX_DECRYPT_ERROR)) { + rx_status.flag |= RX_FLAG_DECRYPTED; + } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) + && !(status->flags & ATH_RX_DECRYPT_ERROR) + && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, sc->sc_keymap)) + rx_status.flag |= RX_FLAG_DECRYPTED; + } + + spin_lock_bh(&sc->node_lock); + an = ath_node_find(sc, hdr->addr2); + spin_unlock_bh(&sc->node_lock); + + if (an) { + ath_rx_input(sc, an, + hw->conf.ht_conf.ht_supported, + skb, status, &st); + } + if (!an || (st != ATH_RX_CONSUMED)) + __ieee80211_rx(hw, skb, &rx_status); + + return 0; +} + +int ath_rx_subframe(struct ath_node *an, + struct sk_buff *skb, + struct ath_recv_status *status) +{ + struct ath_softc *sc = an->an_sc; + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_rx_status rx_status; + + /* Prepare rx status */ + ath9k_rx_prepare(sc, skb, status, &rx_status); + if (!(status->flags & ATH_RX_DECRYPT_ERROR)) + rx_status.flag |= RX_FLAG_DECRYPTED; + + __ieee80211_rx(hw, skb, &rx_status); + + return 0; +} + +/********************************/ +/* LED functions */ +/********************************/ + +static void ath_led_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); + struct ath_softc *sc = led->sc; + + switch (brightness) { + case LED_OFF: + if (led->led_type == ATH_LED_ASSOC || + led->led_type == ATH_LED_RADIO) + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + (led->led_type == ATH_LED_RADIO) ? 1 : + !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); + break; + case LED_FULL: + if (led->led_type == ATH_LED_ASSOC) + sc->sc_flags |= SC_OP_LED_ASSOCIATED; + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + break; + default: + break; + } +} + +static int ath_register_led(struct ath_softc *sc, struct ath_led *led, + char *trigger) +{ + int ret; + + led->sc = sc; + led->led_cdev.name = led->name; + led->led_cdev.default_trigger = trigger; + led->led_cdev.brightness_set = ath_led_brightness; + + ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); + if (ret) + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to register led:%s", led->name); + else + led->registered = 1; + return ret; +} + +static void ath_unregister_led(struct ath_led *led) +{ + if (led->registered) { + led_classdev_unregister(&led->led_cdev); + led->registered = 0; + } +} + +static void ath_deinit_leds(struct ath_softc *sc) +{ + ath_unregister_led(&sc->assoc_led); + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath_unregister_led(&sc->tx_led); + ath_unregister_led(&sc->rx_led); + ath_unregister_led(&sc->radio_led); + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); +} + +static void ath_init_leds(struct ath_softc *sc) +{ + char *trigger; + int ret; + + /* Configure gpio 1 for output */ + ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + /* LED off, active low */ + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + + trigger = ieee80211_get_radio_led_name(sc->hw); + snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), + "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->radio_led, trigger); + sc->radio_led.led_type = ATH_LED_RADIO; + if (ret) + goto fail; + + trigger = ieee80211_get_assoc_led_name(sc->hw); + snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), + "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->assoc_led, trigger); + sc->assoc_led.led_type = ATH_LED_ASSOC; + if (ret) + goto fail; + + trigger = ieee80211_get_tx_led_name(sc->hw); + snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), + "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->tx_led, trigger); + sc->tx_led.led_type = ATH_LED_TX; + if (ret) + goto fail; + + trigger = ieee80211_get_rx_led_name(sc->hw); + snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), + "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->rx_led, trigger); + sc->rx_led.led_type = ATH_LED_RX; + if (ret) + goto fail; + + return; + +fail: + ath_deinit_leds(sc); +} + +#ifdef CONFIG_RFKILL +/*******************/ +/* Rfkill */ +/*******************/ + +static void ath_radio_enable(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + int status; + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, ah->ah_curchan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, + sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, + false, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", __func__, + ath9k_hw_mhz2ieee(ah, + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags), + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags, status); + } + spin_unlock_bh(&sc->sc_resetlock); + + ath_update_txpow(sc); + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to restart recv logic\n", __func__); + return; + } + + if (sc->sc_flags & SC_OP_BEACONS) + ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ + + /* Re-Enable interrupts */ + ath9k_hw_set_interrupts(ah, sc->sc_imask); + + /* Enable LED */ + ath9k_hw_cfg_output(ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); + + ieee80211_wake_queues(sc->hw); +} + +static void ath_radio_disable(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + int status; + + + ieee80211_stop_queues(sc->hw); + + /* Disable LED */ + ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1); + ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN); + + /* Disable interrupts */ + ath9k_hw_set_interrupts(ah, 0); + + ath_draintxq(sc, false); /* clear pending tx frames */ + ath_stoprecv(sc); /* turn off frame recv */ + ath_flushrecv(sc); /* flush recv queue */ + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, ah->ah_curchan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, + sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, + false, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", __func__, + ath9k_hw_mhz2ieee(ah, + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags), + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags, status); + } + spin_unlock_bh(&sc->sc_resetlock); + + ath9k_hw_phy_disable(ah); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); +} + +static bool ath_is_rfkill_set(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + + return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) == + ah->ah_rfkill_polarity; +} + +/* h/w rfkill poll function */ +static void ath_rfkill_poll(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + rf_kill.rfkill_poll.work); + bool radio_on; + + if (sc->sc_flags & SC_OP_INVALID) + return; + + radio_on = !ath_is_rfkill_set(sc); + + /* + * enable/disable radio only when there is a + * state change in RF switch + */ + if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) { + enum rfkill_state state; + + if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) { + state = radio_on ? RFKILL_STATE_SOFT_BLOCKED + : RFKILL_STATE_HARD_BLOCKED; + } else if (radio_on) { + ath_radio_enable(sc); + state = RFKILL_STATE_UNBLOCKED; + } else { + ath_radio_disable(sc); + state = RFKILL_STATE_HARD_BLOCKED; + } + + if (state == RFKILL_STATE_HARD_BLOCKED) + sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED; + else + sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED; + + rfkill_force_state(sc->rf_kill.rfkill, state); + } + + queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, + msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); +} + +/* s/w rfkill handler */ +static int ath_sw_toggle_radio(void *data, enum rfkill_state state) +{ + struct ath_softc *sc = data; + + switch (state) { + case RFKILL_STATE_SOFT_BLOCKED: + if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | + SC_OP_RFKILL_SW_BLOCKED))) + ath_radio_disable(sc); + sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED; + return 0; + case RFKILL_STATE_UNBLOCKED: + if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) { + sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; + if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { + DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" + "radio as it is disabled by h/w \n"); + return -EPERM; + } + ath_radio_enable(sc); + } + return 0; + default: + return -EINVAL; + } +} + +/* Init s/w rfkill */ +static int ath_init_sw_rfkill(struct ath_softc *sc) +{ + sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), + RFKILL_TYPE_WLAN); + if (!sc->rf_kill.rfkill) { + DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); + return -ENOMEM; + } + + snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), + "ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy)); + sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; + sc->rf_kill.rfkill->data = sc; + sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; + sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED; + sc->rf_kill.rfkill->user_claim_unsupported = 1; + + return 0; +} + +/* Deinitialize rfkill */ +static void ath_deinit_rfkill(struct ath_softc *sc) +{ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); + + if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { + rfkill_unregister(sc->rf_kill.rfkill); + sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; + sc->rf_kill.rfkill = NULL; + } +} +#endif /* CONFIG_RFKILL */ + +static int ath_detach(struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); + + /* Deinit LED control */ + ath_deinit_leds(sc); + +#ifdef CONFIG_RFKILL + /* deinit rfkill */ + ath_deinit_rfkill(sc); +#endif + + /* Unregister hw */ + + ieee80211_unregister_hw(hw); + + /* unregister Rate control */ + ath_rate_control_unregister(); + + /* tx/rx cleanup */ + + ath_rx_cleanup(sc); + ath_tx_cleanup(sc); + + /* Deinit */ + + ath_deinit(sc); + + return 0; +} + +static int ath_attach(u16 devid, + struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + int error = 0; + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); + + error = ath_init(devid, sc); + if (error != 0) + return error; + + /* Init nodes */ + + INIT_LIST_HEAD(&sc->node_list); + spin_lock_init(&sc->node_lock); + + /* get mac address from hardware and set in mac80211 */ + + SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); + + /* setup channels and rates */ + + sc->sbands[IEEE80211_BAND_2GHZ].channels = + sc->channels[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = + sc->rates[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) + /* Setup HT capabilities for 2.4Ghz*/ + setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info); + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &sc->sbands[IEEE80211_BAND_2GHZ]; + + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_5GHZ].channels = + sc->channels[IEEE80211_BAND_5GHZ]; + sc->sbands[IEEE80211_BAND_5GHZ].bitrates = + sc->rates[IEEE80211_BAND_5GHZ]; + sc->sbands[IEEE80211_BAND_5GHZ].band = + IEEE80211_BAND_5GHZ; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) + /* Setup HT capabilities for 5Ghz*/ + setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info); + + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &sc->sbands[IEEE80211_BAND_5GHZ]; + } + + /* FIXME: Have to figure out proper hw init values later */ + + hw->queues = 4; + hw->ampdu_queues = 1; + + /* Register rate control */ + hw->rate_control_algorithm = "ath9k_rate_control"; + error = ath_rate_control_register(); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to register rate control " + "algorithm:%d\n", __func__, error); + ath_rate_control_unregister(); + goto bad; + } + + error = ieee80211_register_hw(hw); + if (error != 0) { + ath_rate_control_unregister(); + goto bad; + } + + /* Initialize LED control */ + ath_init_leds(sc); + +#ifdef CONFIG_RFKILL + /* Initialze h/w Rfkill */ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); + + /* Initialize s/w rfkill */ + if (ath_init_sw_rfkill(sc)) + goto detach; +#endif + + /* initialize tx/rx engine */ + + error = ath_tx_init(sc, ATH_TXBUF); + if (error != 0) + goto detach; + + error = ath_rx_init(sc, ATH_RXBUF); + if (error != 0) + goto detach; + + return 0; +detach: + ath_detach(sc); +bad: + return error; +} + static int ath9k_start(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; @@ -360,6 +1045,33 @@ static int ath9k_start(struct ieee80211_hw *hw) return error; } +#ifdef CONFIG_RFKILL + /* Start rfkill polling */ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + queue_delayed_work(sc->hw->workqueue, + &sc->rf_kill.rfkill_poll, 0); + + if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { + if (rfkill_register(sc->rf_kill.rfkill)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to register rfkill\n"); + rfkill_free(sc->rf_kill.rfkill); + + /* Deinitialize the device */ + if (sc->pdev->irq) + free_irq(sc->pdev->irq, sc); + ath_detach(sc); + pci_iounmap(sc->pdev, sc->mem); + pci_release_region(sc->pdev, 0); + pci_disable_device(sc->pdev); + ieee80211_free_hw(hw); + return -EIO; + } else { + sc->sc_flags |= SC_OP_RFKILL_REGISTERED; + } + } +#endif + ieee80211_wake_queues(hw); return 0; } @@ -369,6 +1081,20 @@ static int ath9k_tx(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; int hdrlen, padsize; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + /* + * As a temporary workaround, assign seq# here; this will likely need + * to be cleaned up to work better with Beacon transmission and virtual + * BSSes. + */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + } /* Add the padding after the header if this is not already done */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -407,6 +1133,11 @@ static void ath9k_stop(struct ieee80211_hw *hw) "%s: Device is no longer present\n", __func__); ieee80211_stop_queues(hw); + +#ifdef CONFIG_RFKILL + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); +#endif } static int ath9k_add_interface(struct ieee80211_hw *hw, @@ -421,16 +1152,19 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, return -ENOBUFS; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: ic_opmode = ATH9K_M_STA; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: ic_opmode = ATH9K_M_IBSS; break; + case NL80211_IFTYPE_AP: + ic_opmode = ATH9K_M_HOSTAP; + break; default: DPRINTF(sc, ATH_DBG_FATAL, - "%s: Only STA and IBSS are supported currently\n", - __func__); + "%s: Interface type %d not yet supported\n", + __func__, conf->type); return -EOPNOTSUPP; } @@ -446,6 +1180,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, return error; } + if (conf->type == NL80211_IFTYPE_AP) { + /* TODO: is this a suitable place to start ANI for AP mode? */ + /* Start ANI */ + mod_timer(&sc->sc_ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + } + return 0; } @@ -468,12 +1209,15 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, #ifdef CONFIG_SLOW_ANT_DIV ath_slow_ant_div_stop(&sc->sc_antdiv); #endif + /* Stop ANI */ + del_timer_sync(&sc->sc_ani.timer); /* Update ratectrl */ ath_rate_newstate(sc, avp); /* Reclaim beacon resources */ - if (sc->sc_opmode == ATH9K_M_HOSTAP || sc->sc_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || + sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); ath_beacon_return(sc, avp); } @@ -481,7 +1225,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, /* Set interrupt mask */ sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL); - sc->sc_beacons = 0; + sc->sc_flags &= ~SC_OP_BEACONS; error = ath_vap_detach(sc, 0); if (error) @@ -530,6 +1274,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf) { struct ath_softc *sc = hw->priv; + struct ath_hal *ah = sc->sc_ah; struct ath_vap *avp; u32 rfilt = 0; int error, i; @@ -542,18 +1287,25 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, return -EINVAL; } + /* TODO: Need to decide which hw opmode to use for multi-interface + * cases */ + if (vif->type == NL80211_IFTYPE_AP && + ah->ah_opmode != ATH9K_M_HOSTAP) { + ah->ah_opmode = ATH9K_M_HOSTAP; + ath9k_hw_setopmode(ah); + ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); + /* Request full reset to get hw opmode changed properly */ + sc->sc_flags |= SC_OP_FULL_RESET; + } + if ((conf->changed & IEEE80211_IFCC_BSSID) && !is_zero_ether_addr(conf->bssid)) { switch (vif->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: /* Update ratectrl about the new state */ ath_rate_newstate(sc, avp); - /* Set rx filter */ - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(sc->sc_ah, rfilt); - /* Set BSSID */ memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); sc->sc_curaid = 0; @@ -586,7 +1338,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, print_mac(mac, sc->sc_curbssid), sc->sc_curaid); /* need to reconfigure the beacon */ - sc->sc_beacons = 0; + sc->sc_flags &= ~SC_OP_BEACONS ; break; default: @@ -595,7 +1347,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } if ((conf->changed & IEEE80211_IFCC_BEACON) && - (vif->type == IEEE80211_IF_TYPE_IBSS)) { + ((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_AP))) { /* * Allocate and setup the beacon frame. * @@ -614,7 +1367,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } /* Check for WLAN_CAPABILITY_PRIVACY ? */ - if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) { + if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { for (i = 0; i < IEEE80211_WEP_NKID; i++) if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) ath9k_hw_keysetmac(sc->sc_ah, @@ -623,7 +1376,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } /* Only legacy IBSS for now */ - if (vif->type == IEEE80211_IF_TYPE_IBSS) + if (vif->type == NL80211_IFTYPE_ADHOC) ath_update_chainmask(sc, 0); return 0; @@ -637,8 +1390,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | \ FIF_FCSFAIL) -/* Accept unicast, bcast and mcast frames */ - +/* FIXME: sc->sc_full_reset ? */ static void ath9k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, @@ -646,22 +1398,28 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, struct dev_mc_list *mclist) { struct ath_softc *sc = hw->priv; + u32 rfilt; changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; + sc->rx_filter = *total_flags; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(sc->sc_ah, rfilt); + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - ath_scan_start(sc); - else - ath_scan_end(sc); + ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); } + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n", + __func__, sc->rx_filter); } static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, - const u8 *addr) + struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; struct ath_node *an; @@ -669,19 +1427,18 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, DECLARE_MAC_BUF(mac); spin_lock_irqsave(&sc->node_lock, flags); - an = ath_node_find(sc, (u8 *) addr); + an = ath_node_find(sc, sta->addr); spin_unlock_irqrestore(&sc->node_lock, flags); switch (cmd) { case STA_NOTIFY_ADD: spin_lock_irqsave(&sc->node_lock, flags); if (!an) { - ath_node_attach(sc, (u8 *)addr, 0); + ath_node_attach(sc, sta->addr, 0); DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", - __func__, - print_mac(mac, addr)); + __func__, print_mac(mac, sta->addr)); } else { - ath_node_get(sc, (u8 *)addr); + ath_node_get(sc, sta->addr); } spin_unlock_irqrestore(&sc->node_lock, flags); break; @@ -694,7 +1451,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT); DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n", __func__, - print_mac(mac, addr)); + print_mac(mac, sta->addr)); } break; default: @@ -764,7 +1521,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw, case DISABLE_KEY: ath_key_delete(sc, key); clear_bit(key->keyidx, sc->sc_keymap); - sc->sc_keytype = ATH9K_CIPHER_CLR; break; default: ret = -EINVAL; @@ -773,117 +1529,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return ret; } -static void ath9k_ht_conf(struct ath_softc *sc, - struct ieee80211_bss_conf *bss_conf) -{ -#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) - struct ath_ht_info *ht_info = &sc->sc_ht_info; - - if (bss_conf->assoc_ht) { - ht_info->ext_chan_offset = - bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_SEC_OFFSET; - - if (!(bss_conf->ht_conf->cap & - IEEE80211_HT_CAP_40MHZ_INTOLERANT) && - (bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_WIDTH)) - ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; - else - ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; - - ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); - ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - bss_conf->ht_conf->ampdu_factor); - ht_info->mpdudensity = - parse_mpdudensity(bss_conf->ht_conf->ampdu_density); - - } - -#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT -} - -static void ath9k_bss_assoc_info(struct ath_softc *sc, - struct ieee80211_bss_conf *bss_conf) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_channel *curchan = hw->conf.channel; - struct ath_vap *avp; - int pos; - DECLARE_MAC_BUF(mac); - - if (bss_conf->assoc) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", - __func__, - bss_conf->aid); - - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } - - /* New association, store aid */ - if (avp->av_opmode == ATH9K_M_STA) { - sc->sc_curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, - sc->sc_curaid); - } - - /* Configure the beacon */ - ath_beacon_config(sc, 0); - sc->sc_beacons = 1; - - /* Reset rssi stats */ - sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; - - /* Update chainmask */ - ath_update_chainmask(sc, bss_conf->assoc_ht); - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: bssid %s aid 0x%x\n", - __func__, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); - - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid channel\n", __func__); - return; - } - - if (hw->conf.ht_conf.ht_supported) - sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan); - else - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? - CHANNEL_G : CHANNEL_A; - - /* set h/w channel */ - if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to set channel\n", - __func__); - - ath_rate_newstate(sc, avp); - /* Update ratectrl about the new state */ - ath_rc_node_update(hw, avp->rc_node); - } else { - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Bss Info DISSOC\n", __func__); - sc->sc_curaid = 0; - } -} - static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -896,9 +1541,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, __func__, bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) - sc->sc_flags |= ATH_PREAMBLE_SHORT; + sc->sc_flags |= SC_OP_PREAMBLE_SHORT; else - sc->sc_flags &= ~ATH_PREAMBLE_SHORT; + sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; } if (changed & BSS_CHANGED_ERP_CTS_PROT) { @@ -907,9 +1552,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, bss_conf->use_cts_prot); if (bss_conf->use_cts_prot && hw->conf.channel->band != IEEE80211_BAND_5GHZ) - sc->sc_flags |= ATH_PROTECT_ENABLE; + sc->sc_flags |= SC_OP_PROTECT_ENABLE; else - sc->sc_flags &= ~ATH_PROTECT_ENABLE; + sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } if (changed & BSS_CHANGED_HT) { @@ -948,45 +1593,44 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw) static int ath9k_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, - const u8 *addr, - u16 tid, - u16 *ssn) + struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { struct ath_softc *sc = hw->priv; int ret = 0; switch (action) { case IEEE80211_AMPDU_RX_START: - ret = ath_rx_aggr_start(sc, addr, tid, ssn); + ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to start RX aggregation\n", __func__); break; case IEEE80211_AMPDU_RX_STOP: - ret = ath_rx_aggr_stop(sc, addr, tid); + ret = ath_rx_aggr_stop(sc, sta->addr, tid); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to stop RX aggregation\n", __func__); break; case IEEE80211_AMPDU_TX_START: - ret = ath_tx_aggr_start(sc, addr, tid, ssn); + ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to start TX aggregation\n", __func__); else - ieee80211_start_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, addr, tid); + ret = ath_tx_aggr_stop(sc, sta->addr, tid); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to stop TX aggregation\n", __func__); - ieee80211_stop_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; default: DPRINTF(sc, ATH_DBG_FATAL, @@ -996,6 +1640,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, return ret; } +static int ath9k_no_fragmentation(struct ieee80211_hw *hw, u32 value) +{ + return -EOPNOTSUPP; +} + static struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -1020,263 +1669,10 @@ static struct ieee80211_ops ath9k_ops = { .get_tsf = ath9k_get_tsf, .reset_tsf = ath9k_reset_tsf, .tx_last_beacon = NULL, - .ampdu_action = ath9k_ampdu_action + .ampdu_action = ath9k_ampdu_action, + .set_frag_threshold = ath9k_no_fragmentation, }; -void ath_get_beaconconfig(struct ath_softc *sc, - int if_id, - struct ath_beacon_config *conf) -{ - struct ieee80211_hw *hw = sc->hw; - - /* fill in beacon config data */ - - conf->beacon_interval = hw->conf.beacon_int; - conf->listen_interval = 100; - conf->dtim_count = 1; - conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; -} - -int ath_update_beacon(struct ath_softc *sc, - int if_id, - struct ath_beacon_offset *bo, - struct sk_buff *skb, - int mcast) -{ - return 0; -} - -void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status, struct ath_node *an) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - - DPRINTF(sc, ATH_DBG_XMIT, - "%s: TX complete: skb: %p\n", __func__, skb); - - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || - tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - /* free driver's private data area of tx_info */ - if (tx_info->driver_data[0] != NULL) - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; - } - - if (tx_status->flags & ATH_TX_BAR) { - tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - tx_status->flags &= ~ATH_TX_BAR; - } - - if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { - if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - /* Frame was not ACKed, but an ACK was expected */ - tx_info->status.excessive_retries = 1; - } - } else { - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; - } - - tx_info->status.retry_count = tx_status->retries; - - ieee80211_tx_status(hw, skb); - if (an) - ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); -} - -int ath__rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) -{ - struct ieee80211_hw *hw = sc->hw; - struct ath_node *an = NULL; - struct ieee80211_rx_status rx_status; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - int padsize; - enum ATH_RX_TYPE st; - - /* see if any padding is done by the hw and remove it */ - if (hdrlen & 3) { - padsize = hdrlen % 4; - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } - - /* remove FCS before passing up to protocol stack */ - skb_trim(skb, (skb->len - FCS_LEN)); - - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); - - if (!(keyix == ATH9K_RXKEYIX_INVALID) && - !(status->flags & ATH_RX_DECRYPT_ERROR)) { - rx_status.flag |= RX_FLAG_DECRYPTED; - } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) - && !(status->flags & ATH_RX_DECRYPT_ERROR) - && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - - if (test_bit(keyix, sc->sc_keymap)) - rx_status.flag |= RX_FLAG_DECRYPTED; - } - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr2); - spin_unlock_bh(&sc->node_lock); - - if (an) { - ath_rx_input(sc, an, - hw->conf.ht_conf.ht_supported, - skb, status, &st); - } - if (!an || (st != ATH_RX_CONSUMED)) - __ieee80211_rx(hw, skb, &rx_status); - - return 0; -} - -int ath_rx_subframe(struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *status) -{ - struct ath_softc *sc = an->an_sc; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_rx_status rx_status; - - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); - if (!(status->flags & ATH_RX_DECRYPT_ERROR)) - rx_status.flag |= RX_FLAG_DECRYPTED; - - __ieee80211_rx(hw, skb, &rx_status); - - return 0; -} - -enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc) -{ - return sc->sc_ht_info.tx_chan_width; -} - -static int ath_detach(struct ath_softc *sc) -{ - struct ieee80211_hw *hw = sc->hw; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); - - /* Unregister hw */ - - ieee80211_unregister_hw(hw); - - /* unregister Rate control */ - ath_rate_control_unregister(); - - /* tx/rx cleanup */ - - ath_rx_cleanup(sc); - ath_tx_cleanup(sc); - - /* Deinit */ - - ath_deinit(sc); - - return 0; -} - -static int ath_attach(u16 devid, - struct ath_softc *sc) -{ - struct ieee80211_hw *hw = sc->hw; - int error = 0; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); - - error = ath_init(devid, sc); - if (error != 0) - return error; - - /* Init nodes */ - - INIT_LIST_HEAD(&sc->node_list); - spin_lock_init(&sc->node_lock); - - /* get mac address from hardware and set in mac80211 */ - - SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); - - /* setup channels and rates */ - - sc->sbands[IEEE80211_BAND_2GHZ].channels = - sc->channels[IEEE80211_BAND_2GHZ]; - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = - sc->rates[IEEE80211_BAND_2GHZ]; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - /* Setup HT capabilities for 2.4Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info); - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; - - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = - sc->channels[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - sc->rates[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].band = - IEEE80211_BAND_5GHZ; - - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - /* Setup HT capabilities for 5Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info); - - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; - } - - /* FIXME: Have to figure out proper hw init values later */ - - hw->queues = 4; - hw->ampdu_queues = 1; - - /* Register rate control */ - hw->rate_control_algorithm = "ath9k_rate_control"; - error = ath_rate_control_register(); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to register rate control " - "algorithm:%d\n", __func__, error); - ath_rate_control_unregister(); - goto bad; - } - - error = ieee80211_register_hw(hw); - if (error != 0) { - ath_rate_control_unregister(); - goto bad; - } - - /* initialize tx/rx engine */ - - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto bad1; - - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto bad1; - - return 0; -bad1: - ath_detach(sc); -bad: - return error; -} - static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void __iomem *mem; @@ -1350,9 +1746,16 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bad2; } - hw->flags = IEEE80211_HW_SIGNAL_DBM | + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); @@ -1400,10 +1803,17 @@ static void ath_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; + enum ath9k_int status; - if (pdev->irq) + if (pdev->irq) { + ath9k_hw_set_interrupts(sc->sc_ah, 0); + /* clear the ISR */ + ath9k_hw_getisr(sc->sc_ah, &status); + sc->sc_flags |= SC_OP_INVALID; free_irq(pdev->irq, sc); + } ath_detach(sc); + pci_iounmap(pdev, sc->mem); pci_release_region(pdev, 0); pci_disable_device(pdev); @@ -1414,6 +1824,16 @@ static void ath_pci_remove(struct pci_dev *pdev) static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) { + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; + + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + +#ifdef CONFIG_RFKILL + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); +#endif + pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, 3); @@ -1423,6 +1843,8 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int ath_pci_resume(struct pci_dev *pdev) { + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; u32 val; int err; @@ -1439,6 +1861,21 @@ static int ath_pci_resume(struct pci_dev *pdev) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + /* Enable LED */ + ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + +#ifdef CONFIG_RFKILL + /* + * check the h/w rfkill state on resume + * and start the rfkill poll timer + */ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + queue_delayed_work(sc->hw->workqueue, + &sc->rf_kill.rfkill_poll, 0); +#endif + return 0; } diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 0cd399a5344..14702344448 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h @@ -18,19 +18,19 @@ #define PHY_H bool ath9k_hw_ar9280_set_channel(struct ath_hal *ah, - struct ath9k_channel - *chan); + struct ath9k_channel + *chan); bool ath9k_hw_set_channel(struct ath_hal *ah, - struct ath9k_channel *chan); + struct ath9k_channel *chan); void ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex, u32 freqIndex, int regWrites); bool ath9k_hw_set_rf_regs(struct ath_hal *ah, - struct ath9k_channel *chan, - u16 modesIndex); + struct ath9k_channel *chan, + u16 modesIndex); void ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan); bool ath9k_hw_init_rf(struct ath_hal *ah, - int *status); + int *status); #define AR_PHY_BASE 0x9800 #define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 73c460ad355..cca2fc5b076 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -20,6 +20,7 @@ */ #include "core.h" +/* FIXME: remove this include! */ #include "../net/mac80211/rate.h" static u32 tx_triglevel_max; @@ -653,8 +654,8 @@ ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); for (i = 0; i < rate_table->rate_cnt; i++) { valid = (ath_rc_priv->single_stream ? - rate_table->info[i].valid_single_stream : - rate_table->info[i].valid); + rate_table->info[i].valid_single_stream : + rate_table->info[i].valid); if (valid == TRUE) { u32 phy = rate_table->info[i].phy; u8 valid_rate_count = 0; @@ -740,14 +741,14 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; u32 valid = (ath_rc_priv->single_stream ? - rate_table->info[j].valid_single_stream : - rate_table->info[j].valid); + rate_table->info[j].valid_single_stream : + rate_table->info[j].valid); if (((((struct ath_rateset *) - mcs_set)->rs_rates[i] & 0x7F) != - (rate_table->info[j].dot11rate & 0x7F)) || - !WLAN_RC_PHY_HT(phy) || - !WLAN_RC_PHY_HT_VALID(valid, capflag)) + mcs_set)->rs_rates[i] & 0x7F) != + (rate_table->info[j].dot11rate & 0x7F)) || + !WLAN_RC_PHY_HT(phy) || + !WLAN_RC_PHY_HT_VALID(valid, capflag)) continue; if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) @@ -847,9 +848,9 @@ void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) /* For half and quarter rate channles use different * rate tables */ - if (sc->sc_curchan.channelFlags & CHANNEL_HALF) + if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF) ar5416_sethalf_ratetable(asc); - else if (sc->sc_curchan.channelFlags & CHANNEL_QUARTER) + else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER) ar5416_setquarter_ratetable(asc); else /* full rate */ ar5416_setfull_ratetable(asc); @@ -866,10 +867,10 @@ void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) } static u8 ath_rc_ratefind_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - int probe_allowed, int *is_probing, - int is_retry) + struct ath_rate_node *ath_rc_priv, + const struct ath_rate_table *rate_table, + int probe_allowed, int *is_probing, + int is_retry) { u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; @@ -997,8 +998,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, rate = rate_ctrl->rate_table_size - 1; ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) || - (rate_table->info[rate].valid_single_stream && - ath_rc_priv->single_stream)); + (rate_table->info[rate].valid_single_stream && + ath_rc_priv->single_stream)); return rate; } @@ -1023,10 +1024,10 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table , } static u8 ath_rc_rate_getidx(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - u8 rix, u16 stepdown, - u16 min_rate) + struct ath_rate_node *ath_rc_priv, + const struct ath_rate_table *rate_table, + u8 rix, u16 stepdown, + u16 min_rate) { u32 j; u8 nextindex; @@ -1066,8 +1067,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, rate_table = (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, - (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, - is_probe, is_retry); + (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, + is_probe, is_retry); nrix = rix; if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) { @@ -1099,13 +1100,13 @@ static void ath_rc_ratefind(struct ath_softc *sc, try_num = ((i + 1) == num_rates) ? num_tries - (try_per_rate * i) : try_per_rate ; min_rate = (((i + 1) == num_rates) && - (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0; + (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0; nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1, min_rate); + rate_table, nrix, 1, min_rate); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, - &series[i], try_num, nrix, TRUE); + &series[i], try_num, nrix, TRUE); } /* @@ -1124,13 +1125,13 @@ static void ath_rc_ratefind(struct ath_softc *sc, * above conditions. */ if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { + (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || + (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { u8 dot11rate = rate_table->info[rix].dot11rate; u8 phy = rate_table->info[rix].phy; if (i == 4 && ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || - (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { + (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { series[3].rix = series[2].rix; series[3].flags = series[2].flags; series[3].max_4ms_framelen = series[2].max_4ms_framelen; @@ -1141,18 +1142,19 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* * Return the Tx rate series. */ -void ath_rate_findrate(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - int num_tries, - int num_rates, - unsigned int rcflag, - struct ath_rc_series series[], - int *is_probe, - int is_retry) +static void ath_rate_findrate(struct ath_softc *sc, + struct ath_rate_node *ath_rc_priv, + int num_tries, + int num_rates, + unsigned int rcflag, + struct ath_rc_series series[], + int *is_probe, + int is_retry) { struct ath_vap *avp = ath_rc_priv->avp; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + if (!num_rates || !num_tries) return; @@ -1174,9 +1176,8 @@ void ath_rate_findrate(struct ath_softc *sc, unsigned int mcs; u8 series_rix = 0; - series[idx].tries = - IEEE80211_RATE_IDX_ENTRY( - avp->av_config.av_fixed_retryset, idx); + series[idx].tries = IEEE80211_RATE_IDX_ENTRY( + avp->av_config.av_fixed_retryset, idx); mcs = IEEE80211_RATE_IDX_ENTRY( avp->av_config.av_fixed_rateset, idx); @@ -1228,7 +1229,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, u32 now_msec = jiffies_to_msecs(jiffies); int state_change = FALSE, rate, count; u8 last_per; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; + struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rate_table *rate_table = (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; @@ -1272,14 +1273,14 @@ static void ath_rc_update_ht(struct ath_softc *sc, } else { /* xretries == 2 */ count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + sizeof(nretry_to_per_lookup[0]); if (retries >= count) retries = count - 1; /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ rate_ctrl->state[tx_rate].per = (u8)(rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - ((100) >> 3)); + (rate_ctrl->state[tx_rate].per >> 3) + + ((100) >> 3)); } /* xretries == 1 or 2 */ @@ -1295,8 +1296,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (retries >= count) retries = count - 1; if (info_priv->n_bad_frames) { - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - /* + /* new_PER = 7/8*old_PER + 1/8*(currentPER) * Assuming that n_frames is not 0. The current PER * from the retries is 100 * retries / (retries+1), * since the first retries attempts failed, and the @@ -1386,7 +1386,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, * rssi_ack values. */ if (tx_rate == rate_ctrl->rate_max_phy && - rate_ctrl->hw_maxretry_pktcnt < 255) { + rate_ctrl->hw_maxretry_pktcnt < 255) { rate_ctrl->hw_maxretry_pktcnt++; } @@ -1418,7 +1418,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Now reduce the current * rssi threshold. */ if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { + (rssi_thres > rssi_ack_vmin)) { rate_ctrl->state[tx_rate]. rssi_thres--; } @@ -1436,10 +1436,10 @@ static void ath_rc_update_ht(struct ath_softc *sc, * a while (except if we are probing). */ if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 && - rate_table->info[tx_rate].ratekbps <= - rate_table->info[rate_ctrl->rate_max_phy].ratekbps) { + rate_table->info[tx_rate].ratekbps <= + rate_table->info[rate_ctrl->rate_max_phy].ratekbps) { ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl, - (u8) tx_rate, &rate_ctrl->rate_max_phy); + (u8) tx_rate, &rate_ctrl->rate_max_phy); /* Don't probe for a little while. */ rate_ctrl->probe_time = now_msec; @@ -1460,43 +1460,43 @@ static void ath_rc_update_ht(struct ath_softc *sc, break; if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { + rate_table->info[rate].rssi_ack_deltamin > + rate_ctrl->state[rate+1].rssi_thres) { rate_ctrl->state[rate+1].rssi_thres = rate_ctrl->state[rate]. - rssi_thres + + rssi_thres + rate_table->info[rate]. - rssi_ack_deltamin; + rssi_ack_deltamin; } } /* Make sure the rates below this have lower rssi thresholds. */ for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) + rate_table->info[tx_rate].phy) break; if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { + rate_table->info[rate].rssi_ack_deltamin > + rate_ctrl->state[rate+1].rssi_thres) { if (rate_ctrl->state[rate+1].rssi_thres < - rate_table->info[rate]. - rssi_ack_deltamin) + rate_table->info[rate]. + rssi_ack_deltamin) rate_ctrl->state[rate].rssi_thres = 0; else { rate_ctrl->state[rate].rssi_thres = rate_ctrl->state[rate+1]. - rssi_thres - - rate_table->info[rate]. - rssi_ack_deltamin; + rssi_thres - + rate_table->info[rate]. + rssi_ack_deltamin; } if (rate_ctrl->state[rate].rssi_thres < - rate_table->info[rate]. - rssi_ack_validmin) { + rate_table->info[rate]. + rssi_ack_validmin) { rate_ctrl->state[rate].rssi_thres = rate_table->info[rate]. - rssi_ack_validmin; + rssi_ack_validmin; } } } @@ -1507,11 +1507,11 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (rate_ctrl->state[tx_rate].per < last_per) { for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) + rate_table->info[tx_rate].phy) break; if (rate_ctrl->state[rate].per > - rate_ctrl->state[rate+1].per) { + rate_ctrl->state[rate+1].per) { rate_ctrl->state[rate].per = rate_ctrl->state[rate+1].per; } @@ -1528,11 +1528,11 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Every so often, we reduce the thresholds and * PER (different for CCK and OFDM). */ if (now_msec - rate_ctrl->rssi_down_time >= - rate_table->rssi_reduce_interval) { + rate_table->rssi_reduce_interval) { for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { if (rate_ctrl->state[rate].rssi_thres > - rate_table->info[rate].rssi_ack_validmin) + rate_table->info[rate].rssi_ack_validmin) rate_ctrl->state[rate].rssi_thres -= 1; } rate_ctrl->rssi_down_time = now_msec; @@ -1541,7 +1541,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ if (now_msec - rate_ctrl->per_down_time >= - rate_table->rssi_reduce_interval) { + rate_table->rssi_reduce_interval) { for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { rate_ctrl->state[rate].per = 7 * rate_ctrl->state[rate].per / 8; @@ -1560,7 +1560,7 @@ static void ath_rc_update(struct ath_softc *sc, struct ath_tx_info_priv *info_priv, int final_ts_idx, int xretries, int long_retry) { - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; + struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rate_table *rate_table; struct ath_tx_ratectrl *rate_ctrl; struct ath_rc_series rcs[4]; @@ -1637,7 +1637,6 @@ static void ath_rc_update(struct ath_softc *sc, xretries, long_retry); } - /* * Process a tx descriptor for a completed transmit (success or failure). */ @@ -1651,13 +1650,13 @@ static void ath_rate_tx_complete(struct ath_softc *sc, struct ath_vap *avp; avp = rc_priv->avp; - if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) - || info_priv->tx.ts_status & ATH9K_TXERR_FILT) + if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) || + (info_priv->tx.ts_status & ATH9K_TXERR_FILT)) return; if (info_priv->tx.ts_rssi > 0) { ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi, - info_priv->tx.ts_rssi); + info_priv->tx.ts_rssi); } /* @@ -1682,7 +1681,6 @@ static void ath_rate_tx_complete(struct ath_softc *sc, info_priv->tx.ts_longretry); } - /* * Update the SIB's rate control information * @@ -1701,8 +1699,8 @@ static void ath_rc_sib_update(struct ath_softc *sc, struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rateset *rateset = negotiated_rates; u8 *ht_mcs = (u8 *)negotiated_htrates; - struct ath_tx_ratectrl *rate_ctrl = (struct ath_tx_ratectrl *) - (ath_rc_priv); + struct ath_tx_ratectrl *rate_ctrl = + (struct ath_tx_ratectrl *)ath_rc_priv; u8 i, j, k, hi = 0, hthi = 0; rate_table = (struct ath_rate_table *) @@ -1815,19 +1813,18 @@ static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv) } -static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta) +static void ath_setup_rates(struct ath_softc *sc, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, + struct ath_rate_node *rc_priv) { - struct ieee80211_supported_band *sband; - struct ieee80211_hw *hw = local_to_hw(local); - struct ath_softc *sc = hw->priv; - struct ath_rate_node *rc_priv = sta->rate_ctrl_priv; int i, j = 0; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + for (i = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[local->hw.conf.channel->band] & BIT(i)) { + if (sta->supp_rates[sband->band] & BIT(i)) { rc_priv->neg_rates.rs_rates[j] = (sband->bitrates[i].bitrate * 2) / 10; j++; @@ -1854,19 +1851,17 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) } /* Rate Control callbacks */ -static void ath_tx_status(void *priv, struct net_device *dev, +static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { struct ath_softc *sc = priv; struct ath_tx_info_priv *tx_info_priv; struct ath_node *an; - struct sta_info *sta; - struct ieee80211_local *local; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; __le16 fc; - local = hw_to_local(sc->hw); hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; @@ -1875,8 +1870,7 @@ static void ath_tx_status(void *priv, struct net_device *dev, an = ath_node_find(sc, hdr->addr1); spin_unlock_bh(&sc->node_lock); - sta = sta_info_get(local, hdr->addr1); - if (!an || !sta || !ieee80211_is_data(fc)) { + if (!an || !priv_sta || !ieee80211_is_data(fc)) { if (tx_info->driver_data[0] != NULL) { kfree(tx_info->driver_data[0]); tx_info->driver_data[0] = NULL; @@ -1884,37 +1878,40 @@ static void ath_tx_status(void *priv, struct net_device *dev, return; } if (tx_info->driver_data[0] != NULL) { - ath_rate_tx_complete(sc, an, sta->rate_ctrl_priv, tx_info_priv); + ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv); kfree(tx_info->driver_data[0]); tx_info->driver_data[0] = NULL; } } static void ath_tx_aggr_resp(struct ath_softc *sc, - struct sta_info *sta, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, struct ath_node *an, u8 tidno) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_local *local; struct ath_atx_tid *txtid; - struct ieee80211_supported_band *sband; u16 buffersize = 0; int state; - DECLARE_MAC_BUF(mac); + struct sta_info *si; - if (!sc->sc_txaggr) + if (!(sc->sc_flags & SC_OP_TXAGGR)) return; txtid = ATH_AN_2_TID(an, tidno); if (!txtid->paused) return; - local = hw_to_local(sc->hw); - sband = hw->wiphy->bands[hw->conf.channel->band]; + /* + * XXX: This is entirely busted, we aren't supposed to + * access the sta from here because it's internal + * to mac80211, and looking at the state without + * locking is wrong too. + */ + si = container_of(sta, struct sta_info, sta); buffersize = IEEE80211_MIN_AMPDU_BUF << sband->ht_info.ampdu_factor; /* FIXME */ - state = sta->ampdu_mlme.tid_state_tx[tidno]; + state = si->ampdu_mlme.tid_state_tx[tidno]; if (state & HT_ADDBA_RECEIVED_MSK) { txtid->addba_exchangecomplete = 1; @@ -1930,21 +1927,18 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, } } -static void ath_get_rate(void *priv, struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel) +static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + struct sk_buff *skb, struct rate_selection *sel) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - struct ath_softc *sc = (struct ath_softc *)priv; + struct ath_softc *sc = priv; struct ieee80211_hw *hw = sc->hw; struct ath_tx_info_priv *tx_info_priv; - struct ath_rate_node *ath_rc_priv; + struct ath_rate_node *ath_rc_priv = priv_sta; struct ath_node *an; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int is_probe, chk, ret; + int is_probe = FALSE, chk, ret; s8 lowest_idx; __le16 fc = hdr->frame_control; u8 *qc, tid; @@ -1957,18 +1951,15 @@ static void ath_get_rate(void *priv, struct net_device *dev, ASSERT(tx_info->driver_data[0] != NULL); tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - sta = sta_info_get(local, hdr->addr1); - lowest_idx = rate_lowest_index(local, sband, sta); + lowest_idx = rate_lowest_index(sband, sta); tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10; /* lowest rate for management and multicast/broadcast frames */ if (!ieee80211_is_data(fc) || - is_multicast_ether_addr(hdr->addr1) || !sta) { + is_multicast_ether_addr(hdr->addr1) || !sta) { sel->rate_idx = lowest_idx; return; } - ath_rc_priv = sta->rate_ctrl_priv; - /* Find tx rate for unicast frames */ ath_rate_findrate(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4, @@ -1977,8 +1968,7 @@ static void ath_get_rate(void *priv, struct net_device *dev, &is_probe, false); if (is_probe) - sel->probe_idx = ((struct ath_tx_ratectrl *) - sta->rate_ctrl_priv)->probe_rate; + sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate; /* Ratecontrol sometimes returns invalid rate index */ if (tx_info_priv->rcs[0].rix != 0xff) @@ -2022,38 +2012,31 @@ static void ath_get_rate(void *priv, struct net_device *dev, __func__, print_mac(mac, hdr->addr1)); } else if (chk == AGGR_EXCHANGE_PROGRESS) - ath_tx_aggr_resp(sc, sta, an, tid); + ath_tx_aggr_resp(sc, sband, sta, an, tid); } } } -static void ath_rate_init(void *priv, void *priv_sta, - struct ieee80211_local *local, - struct sta_info *sta) +static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta) { - struct ieee80211_supported_band *sband; - struct ieee80211_hw *hw = local_to_hw(local); - struct ieee80211_conf *conf = &local->hw.conf; - struct ath_softc *sc = hw->priv; + struct ath_softc *sc = priv; + struct ath_rate_node *ath_rc_priv = priv_sta; int i, j = 0; DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - sta->txrate_idx = rate_lowest_index(local, sband, sta); - - ath_setup_rates(local, sta); - if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { + ath_setup_rates(sc, sband, sta, ath_rc_priv); + if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) { for (i = 0; i < MCS_SET_SIZE; i++) { - if (conf->ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) - ((struct ath_rate_node *) - priv_sta)->neg_ht_rates.rs_rates[j++] = i; + if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) + ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; if (j == ATH_RATE_MAX) break; } - ((struct ath_rate_node *)priv_sta)->neg_ht_rates.rs_nrates = j; + ath_rc_priv->neg_ht_rates.rs_nrates = j; } - ath_rc_node_update(hw, priv_sta); + ath_rc_node_update(sc->hw, priv_sta); } static void ath_rate_clear(void *priv) @@ -2061,13 +2044,12 @@ static void ath_rate_clear(void *priv) return; } -static void *ath_rate_alloc(struct ieee80211_local *local) +static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - struct ieee80211_hw *hw = local_to_hw(local); struct ath_softc *sc = hw->priv; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); - return local->hw.priv; + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + return hw->priv; } static void ath_rate_free(void *priv) @@ -2075,24 +2057,28 @@ static void ath_rate_free(void *priv) return; } -static void *ath_rate_alloc_sta(void *priv, gfp_t gfp) +static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { struct ath_softc *sc = priv; struct ath_vap *avp = sc->sc_vaps[0]; struct ath_rate_node *rate_priv; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp); if (!rate_priv) { - DPRINTF(sc, ATH_DBG_FATAL, "%s:Unable to allocate" - "private rate control structure", __func__); + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to allocate private rc structure\n", + __func__); return NULL; } ath_rc_sib_init(rate_priv); + return rate_priv; } -static void ath_rate_free_sta(void *priv, void *priv_sta) +static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, + void *priv_sta) { struct ath_rate_node *rate_priv = priv_sta; struct ath_softc *sc = priv; @@ -2111,7 +2097,7 @@ static struct rate_control_ops ath_rate_ops = { .alloc = ath_rate_alloc, .free = ath_rate_free, .alloc_sta = ath_rate_alloc_sta, - .free_sta = ath_rate_free_sta + .free_sta = ath_rate_free_sta, }; int ath_rate_control_register(void) diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 71aef9c7523..b95b41508b9 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -71,9 +71,6 @@ enum ieee80211_fixed_rate_mode { */ #define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8))) -#define SHORT_PRE 1 -#define LONG_PRE 0 - #define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS #define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS #define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI @@ -102,18 +99,18 @@ enum { WLAN_RC_PHY_MAX }; -#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) -#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) +#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ + || (_phy == WLAN_RC_PHY_HT_40_DS) \ + || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) +#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ + || (_phy == WLAN_RC_PHY_HT_40_DS) \ + || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) #define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) + || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) #define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) @@ -135,56 +132,59 @@ enum { #define WLAN_RC_SGI_FLAG (0x04) #define WLAN_RC_HT_FLAG (0x08) -/* Index into the rate table */ -#define INIT_RATE_MAX_20 23 -#define INIT_RATE_MAX_40 40 - #define RATE_TABLE_SIZE 64 -/* XXX: Convert to kdoc */ +/** + * struct ath_rate_table - Rate Control table + * @valid: valid for use in rate control + * @valid_single_stream: valid for use in rate control for + * single stream operation + * @phy: CCK/OFDM + * @ratekbps: rate in Kbits per second + * @user_ratekbps: user rate in Kbits per second + * @ratecode: rate that goes into HW descriptors + * @short_preamble: Mask for enabling short preamble in ratecode for CCK + * @dot11rate: value that goes into supported + * rates info element of MLME + * @ctrl_rate: Index of next lower basic rate, used for duration computation + * @max_4ms_framelen: maximum frame length(bytes) for tx duration + * @probe_interval: interval for rate control to probe for other rates + * @rssi_reduce_interval: interval for rate control to reduce rssi + * @initial_ratemax: initial ratemax value used in ath_rc_sib_update() + */ struct ath_rate_table { int rate_cnt; struct { - int valid; /* Valid for use in rate control */ - int valid_single_stream;/* Valid for use in rate control - for single stream operation */ - u8 phy; /* CCK/OFDM/TURBO/XR */ - u32 ratekbps; /* Rate in Kbits per second */ - u32 user_ratekbps; /* User rate in KBits per second */ - u8 ratecode; /* rate that goes into - hw descriptors */ - u8 short_preamble; /* Mask for enabling short preamble - in rate code for CCK */ - u8 dot11rate; /* Value that goes into supported - rates info element of MLME */ - u8 ctrl_rate; /* Index of next lower basic rate, - used for duration computation */ - int8_t rssi_ack_validmin; /* Rate control related */ - int8_t rssi_ack_deltamin; /* Rate control related */ - u8 base_index; /* base rate index */ - u8 cw40index; /* 40cap rate index */ - u8 sgi_index; /* shortgi rate index */ - u8 ht_index; /* shortgi rate index */ - u32 max_4ms_framelen; /* Maximum frame length(bytes) - for 4ms tx duration */ + int valid; + int valid_single_stream; + u8 phy; + u32 ratekbps; + u32 user_ratekbps; + u8 ratecode; + u8 short_preamble; + u8 dot11rate; + u8 ctrl_rate; + int8_t rssi_ack_validmin; + int8_t rssi_ack_deltamin; + u8 base_index; + u8 cw40index; + u8 sgi_index; + u8 ht_index; + u32 max_4ms_framelen; } info[RATE_TABLE_SIZE]; - u32 probe_interval; /* interval for ratectrl to - probe for other rates */ - u32 rssi_reduce_interval; /* interval for ratectrl - to reduce RSSI */ - u8 initial_ratemax; /* the initial ratemax value used - in ath_rc_sib_update() */ + u32 probe_interval; + u32 rssi_reduce_interval; + u8 initial_ratemax; }; #define ATH_RC_PROBE_ALLOWED 0x00000001 #define ATH_RC_MINRATE_LASTRATE 0x00000002 -#define ATH_RC_SHORT_PREAMBLE 0x00000004 struct ath_rc_series { - u8 rix; - u8 tries; - u8 flags; - u32 max_4ms_framelen; + u8 rix; + u8 tries; + u8 flags; + u32 max_4ms_framelen; }; /* rcs_flags definition */ @@ -201,42 +201,56 @@ struct ath_rc_series { #define MAX_TX_RATE_PHY 48 struct ath_tx_ratectrl_state { - int8_t rssi_thres; /* required rssi for this rate (dB) */ - u8 per; /* recent estimate of packet error rate (%) */ + int8_t rssi_thres; /* required rssi for this rate (dB) */ + u8 per; /* recent estimate of packet error rate (%) */ }; +/** + * struct ath_tx_ratectrl - TX Rate control Information + * @state: RC state + * @rssi_last: last ACK rssi + * @rssi_last_lookup: last ACK rssi used for lookup + * @rssi_last_prev: previous last ACK rssi + * @rssi_last_prev2: 2nd previous last ACK rssi + * @rssi_sum_cnt: count of rssi_sum for averaging + * @rssi_sum_rate: rate that we are averaging + * @rssi_sum: running sum of rssi for averaging + * @probe_rate: rate we are probing at + * @rssi_time: msec timestamp for last ack rssi + * @rssi_down_time: msec timestamp for last down step + * @probe_time: msec timestamp for last probe + * @hw_maxretry_pktcnt: num of packets since we got HW max retry error + * @max_valid_rate: maximum number of valid rate + * @per_down_time: msec timestamp for last PER down step + * @valid_phy_ratecnt: valid rate count + * @rate_max_phy: phy index for the max rate + * @probe_interval: interval for ratectrl to probe for other rates + */ struct ath_tx_ratectrl { - struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; /* state */ - int8_t rssi_last; /* last ack rssi */ - int8_t rssi_last_lookup; /* last ack rssi used for lookup */ - int8_t rssi_last_prev; /* previous last ack rssi */ - int8_t rssi_last_prev2; /* 2nd previous last ack rssi */ - int32_t rssi_sum_cnt; /* count of rssi_sum for averaging */ - int32_t rssi_sum_rate; /* rate that we are averaging */ - int32_t rssi_sum; /* running sum of rssi for averaging */ - u32 valid_txrate_mask; /* mask of valid rates */ - u8 rate_table_size; /* rate table size */ - u8 rate_max; /* max rate that has recently worked */ - u8 probe_rate; /* rate we are probing at */ - u32 rssi_time; /* msec timestamp for last ack rssi */ - u32 rssi_down_time; /* msec timestamp for last down step */ - u32 probe_time; /* msec timestamp for last probe */ - u8 hw_maxretry_pktcnt; /* num packets since we got - HW max retry error */ - u8 max_valid_rate; /* maximum number of valid rate */ - u8 valid_rate_index[MAX_TX_RATE_TBL]; /* valid rate index */ - u32 per_down_time; /* msec timstamp for last - PER down step */ + struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; + int8_t rssi_last; + int8_t rssi_last_lookup; + int8_t rssi_last_prev; + int8_t rssi_last_prev2; + int32_t rssi_sum_cnt; + int32_t rssi_sum_rate; + int32_t rssi_sum; + u8 rate_table_size; + u8 probe_rate; + u32 rssi_time; + u32 rssi_down_time; + u32 probe_time; + u8 hw_maxretry_pktcnt; + u8 max_valid_rate; + u8 valid_rate_index[MAX_TX_RATE_TBL]; + u32 per_down_time; /* 11n state */ - u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; /* valid rate count */ - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL]; - u8 rc_phy_mode; - u8 rate_max_phy; /* Phy index for the max rate */ - u32 rate_max_lastused; /* msec timstamp of when we - last used rateMaxPhy */ - u32 probe_interval; /* interval for ratectrl to probe - for other rates */ + u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; + u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL]; + u8 rc_phy_mode; + u8 rate_max_phy; + u32 probe_interval; }; struct ath_rateset { @@ -248,29 +262,32 @@ struct ath_rateset { struct ath_rate_softc { /* phy tables that contain rate control data */ const void *hw_rate_table[ATH9K_MODE_MAX]; - int fixedrix; /* -1 or index of fixed rate */ + + /* -1 or index of fixed rate */ + int fixedrix; }; /* per-node state */ struct ath_rate_node { - struct ath_tx_ratectrl tx_ratectrl; /* rate control state proper */ - u32 prev_data_rix; /* rate idx of last data frame */ + struct ath_tx_ratectrl tx_ratectrl; - /* map of rate ix -> negotiated rate set ix */ - u8 rixmap[MAX_TX_RATE_TBL]; + /* rate idx of last data frame */ + u32 prev_data_rix; - /* map of ht rate ix -> negotiated rate set ix */ - u8 ht_rixmap[MAX_TX_RATE_TBL]; + /* ht capabilities */ + u8 ht_cap; - u8 ht_cap; /* ht capabilities */ - u8 ant_tx; /* current transmit antenna */ + /* When TRUE, only single stream Tx possible */ + u8 single_stream; - u8 single_stream; /* When TRUE, only single - stream Tx possible */ - struct ath_rateset neg_rates; /* Negotiated rates */ - struct ath_rateset neg_ht_rates; /* Negotiated HT rates */ - struct ath_rate_softc *asc; /* back pointer to atheros softc */ - struct ath_vap *avp; /* back pointer to vap */ + /* Negotiated rates */ + struct ath_rateset neg_rates; + + /* Negotiated HT rates */ + struct ath_rateset neg_ht_rates; + + struct ath_rate_softc *asc; + struct ath_vap *avp; }; /* Driver data of ieee80211_tx_info */ @@ -297,17 +314,10 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv); void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp); /* - * Return the tx rate series. - */ -void ath_rate_findrate(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv, - int num_tries, int num_rates, - unsigned int rcflag, struct ath_rc_series[], - int *is_probe, int isretry); -/* * Return rate index for given Dot11 Rate. */ u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11_rate); + u8 dot11_rate); /* Routines to register/unregister rate control algorithm */ int ath_rate_control_register(void); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 20ddb7acdb9..4983402af55 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -184,7 +184,7 @@ static int ath_ampdu_input(struct ath_softc *sc, tid = qc[0] & 0xf; } - if (sc->sc_opmode == ATH9K_M_STA) { + if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { /* Drop the frame not belonging to me. */ if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) { dev_kfree_skb(skb); @@ -449,17 +449,16 @@ static int ath_rx_indicate(struct ath_softc *sc, int type; /* indicate frame to the stack, which will free the old skb. */ - type = ath__rx_indicate(sc, skb, status, keyix); + type = _ath_rx_indicate(sc, skb, status, keyix); /* allocate a new skb and queue it to for H/W processing */ nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); if (nskb != NULL) { bf->bf_mpdu = nskb; - bf->bf_buf_addr = ath_skb_map_single(sc, - nskb, - PCI_DMA_FROMDEVICE, - /* XXX: Remove get_dma_mem_context() */ - get_dma_mem_context(bf, bf_dmacontext)); + bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data, + skb_end_pointer(nskb) - nskb->head, + PCI_DMA_FROMDEVICE); + bf->bf_dmacontext = bf->bf_buf_addr; ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf; /* queue the new wbuf to H/W */ @@ -505,7 +504,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) do { spin_lock_init(&sc->sc_rxflushlock); - sc->sc_rxflush = 0; + sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->sc_rxbuflock); /* @@ -542,9 +541,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) } bf->bf_mpdu = skb; - bf->bf_buf_addr = - ath_skb_map_single(sc, skb, PCI_DMA_FROMDEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data, + skb_end_pointer(skb) - skb->head, + PCI_DMA_FROMDEVICE); + bf->bf_dmacontext = bf->bf_buf_addr; ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf; } sc->sc_rxlink = NULL; @@ -598,6 +598,7 @@ void ath_rx_cleanup(struct ath_softc *sc) u32 ath_calcrxfilter(struct ath_softc *sc) { #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) + u32 rfilt; rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE) @@ -605,25 +606,29 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | ATH9K_RX_FILTER_MCAST; /* If not a STA, enable processing of Probe Requests */ - if (sc->sc_opmode != ATH9K_M_STA) + if (sc->sc_ah->ah_opmode != ATH9K_M_STA) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* Can't set HOSTAP into promiscous mode */ - if (sc->sc_opmode == ATH9K_M_MONITOR) { + if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) && + (sc->rx_filter & FIF_PROMISC_IN_BSS)) || + (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) { rfilt |= ATH9K_RX_FILTER_PROM; /* ??? To prevent from sending ACK */ rfilt &= ~ATH9K_RX_FILTER_UCAST; } - if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS || - sc->sc_scanning) + if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) && + (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) || + (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) rfilt |= ATH9K_RX_FILTER_BEACON; /* If in HOSTAP mode, want to enable reception of PSPOLL frames & beacon frames */ - if (sc->sc_opmode == ATH9K_M_HOSTAP) + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); return rfilt; + #undef RX_FILTER_PRESERVE } @@ -703,11 +708,11 @@ void ath_flushrecv(struct ath_softc *sc) * progress (see references to sc_rxflush) */ spin_lock_bh(&sc->sc_rxflushlock); - sc->sc_rxflush = 1; + sc->sc_flags |= SC_OP_RXFLUSH; ath_rx_tasklet(sc, 1); - sc->sc_rxflush = 0; + sc->sc_flags &= ~SC_OP_RXFLUSH; spin_unlock_bh(&sc->sc_rxflushlock); } @@ -720,7 +725,7 @@ int ath_rx_input(struct ath_softc *sc, struct ath_recv_status *rx_status, enum ATH_RX_TYPE *status) { - if (is_ampdu && sc->sc_rxaggr) { + if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) { *status = ATH_RX_CONSUMED; return ath_ampdu_input(sc, an, skb, rx_status); } else { @@ -751,7 +756,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) do { /* If handling rx interrupt and flush is in progress => exit */ - if (sc->sc_rxflush && (flush == 0)) + if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) break; spin_lock_bh(&sc->sc_rxbuflock); @@ -887,7 +892,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - memzero(&rx_status, sizeof(struct ath_recv_status)); + memset(&rx_status, 0, sizeof(struct ath_recv_status)); if (ds->ds_rxstat.rs_more) { /* @@ -901,7 +906,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * Enable this if you want to see * error frames in Monitor mode. */ - if (sc->sc_opmode != ATH9K_M_MONITOR) + if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR) goto rx_next; #endif /* fall thru for monitor mode handling... */ @@ -946,7 +951,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ - if (sc->sc_opmode == ATH9K_M_MONITOR) { + if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) { if (ds->ds_rxstat.rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) @@ -994,20 +999,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) rx_status.flags |= ATH_RX_SHORT_GI; } - /* sc->sc_noise_floor is only available when the station + /* sc_noise_floor is only available when the station attaches to an AP, so we use a default value if we are not yet attached. */ - - /* XXX we should use either sc->sc_noise_floor or - * ath_hal_getChanNoise(ah, &sc->sc_curchan) - * to calculate the noise floor. - * However, the value returned by ath_hal_getChanNoise - * seems to be incorrect (-31dBm on the last test), - * so we will use a hard-coded value until we - * figure out what is going on. - */ rx_status.abs_rssi = - ds->ds_rxstat.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; + ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor; pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, @@ -1090,7 +1086,7 @@ rx_next: "%s: Reset rx chain mask. " "Do internal reset\n", __func__); ASSERT(flush == 0); - ath_internal_reset(sc); + ath_reset(sc, false); } return 0; @@ -1128,7 +1124,7 @@ int ath_rx_aggr_start(struct ath_softc *sc, rxtid = &an->an_aggr.rx.tid[tid]; spin_lock_bh(&rxtid->tidlock); - if (sc->sc_rxaggr) { + if (sc->sc_flags & SC_OP_RXAGGR) { /* Allow aggregation reception * Adjust rx BA window size. Peer might indicate a * zero buffer size for a _dont_care_ condition. @@ -1161,7 +1157,7 @@ int ath_rx_aggr_start(struct ath_softc *sc, } else { /* Ensure the memory is zeroed out (all internal * pointers are null) */ - memzero(rxtid->rxbuf, ATH_TID_MAX_BUFS * + memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS * sizeof(struct ath_rxbuf)); DPRINTF(sc, ATH_DBG_AGGR, "%s: Allocated @%p\n", __func__, rxtid->rxbuf); @@ -1228,7 +1224,7 @@ void ath_rx_aggr_teardown(struct ath_softc *sc, void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_rxaggr) { + if (sc->sc_flags & SC_OP_RXAGGR) { struct ath_arx_tid *rxtid; int tidno; @@ -1260,7 +1256,7 @@ void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_rxaggr) { + if (sc->sc_flags & SC_OP_RXAGGR) { struct ath_arx_tid *rxtid; int tidno, i; @@ -1293,27 +1289,3 @@ void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an) { ath_rx_node_cleanup(sc, an); } - -dma_addr_t ath_skb_map_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa) -{ - /* - * NB: do NOT use skb->len, which is 0 on initialization. - * Use skb's entire data area instead. - */ - *pa = pci_map_single(sc->pdev, skb->data, - skb_end_pointer(skb) - skb->head, direction); - return *pa; -} - -void ath_skb_unmap_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa) -{ - /* Unmap skb's entire data area */ - pci_unmap_single(sc->pdev, *pa, - skb_end_pointer(skb) - skb->head, direction); -} diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index 42b0890a468..60617ae6620 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h @@ -899,12 +899,6 @@ enum { #define AR_GPIO_OUTPUT_MUX2 0x4064 #define AR_GPIO_OUTPUT_MUX3 0x4068 -#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 - #define AR_INPUT_STATE 0x406c #define AR_EEPROM_STATUS_DATA 0x407c diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 550129f717e..3a4757942b3 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -60,79 +60,6 @@ static u32 bits_per_symbol[][2] = { #define IS_HT_RATE(_rate) ((_rate) & 0x80) /* - * Insert a chain of ath_buf (descriptors) on a multicast txq - * but do NOT start tx DMA on this queue. - * NB: must be called with txq lock held - */ - -static void ath_tx_mcastqaddbuf(struct ath_softc *sc, - struct ath_txq *txq, - struct list_head *head) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_buf *bf; - - if (list_empty(head)) - return; - - /* - * Insert the frame on the outbound list and - * pass it on to the hardware. - */ - bf = list_first_entry(head, struct ath_buf, list); - - /* - * The CAB queue is started from the SWBA handler since - * frames only go out on DTIM and to avoid possible races. - */ - ath9k_hw_set_interrupts(ah, 0); - - /* - * If there is anything in the mcastq, we want to set - * the "more data" bit in the last item in the queue to - * indicate that there is "more data". It makes sense to add - * it here since you are *always* going to have - * more data when adding to this queue, no matter where - * you call from. - */ - - if (txq->axq_depth) { - struct ath_buf *lbf; - struct ieee80211_hdr *hdr; - - /* - * Add the "more data flag" to the last frame - */ - - lbf = list_entry(txq->axq_q.prev, struct ath_buf, list); - hdr = (struct ieee80211_hdr *) - ((struct sk_buff *)(lbf->bf_mpdu))->data; - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } - - /* - * Now, concat the frame onto the queue - */ - list_splice_tail_init(head, &txq->axq_q); - txq->axq_depth++; - txq->axq_totalqueued++; - txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); - - DPRINTF(sc, ATH_DBG_QUEUE, - "%s: txq depth = %d\n", __func__, txq->axq_depth); - if (txq->axq_link != NULL) { - *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DBG_XMIT, - "%s: link[%u](%p)=%llx (%p)\n", - __func__, - txq->axq_qnum, txq->axq_link, - ito64(bf->bf_daddr), bf->bf_desc); - } - txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link); - ath9k_hw_set_interrupts(ah, sc->sc_imask); -} - -/* * Insert a chain of ath_buf (descriptors) on a txq and * assume the descriptors are already chained together by caller. * NB: must be called with txq lock held @@ -277,8 +204,6 @@ static int ath_tx_prepare(struct ath_softc *sc, __le16 fc; u8 *qc; - memset(txctl, 0, sizeof(struct ath_tx_control)); - txctl->dev = sc; hdr = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -302,7 +227,6 @@ static int ath_tx_prepare(struct ath_softc *sc, } txctl->if_id = 0; - txctl->nextfraglen = 0; txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3); txctl->txpower = MAX_RATE_POWER; /* FIXME */ @@ -313,13 +237,13 @@ static int ath_tx_prepare(struct ath_softc *sc, if (tx_info->control.hw_key) { txctl->keyix = tx_info->control.hw_key->hw_key_idx; - txctl->frmlen += tx_info->control.icv_len; + txctl->frmlen += tx_info->control.hw_key->icv_len; - if (sc->sc_keytype == ATH9K_CIPHER_WEP) + if (tx_info->control.hw_key->alg == ALG_WEP) txctl->keytype = ATH9K_KEY_TYPE_WEP; - else if (sc->sc_keytype == ATH9K_CIPHER_TKIP) + else if (tx_info->control.hw_key->alg == ALG_TKIP) txctl->keytype = ATH9K_KEY_TYPE_TKIP; - else if (sc->sc_keytype == ATH9K_CIPHER_AES_CCM) + else if (tx_info->control.hw_key->alg == ALG_CCMP) txctl->keytype = ATH9K_KEY_TYPE_AES; } @@ -329,12 +253,18 @@ static int ath_tx_prepare(struct ath_softc *sc, /* Fill qnum */ - txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); - txq = &sc->sc_txq[txctl->qnum]; + if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) { + txctl->qnum = 0; + txq = sc->sc_cabq; + } else { + txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); + txq = &sc->sc_txq[txctl->qnum]; + } spin_lock_bh(&txq->axq_lock); /* Try to avoid running out of descriptors */ - if (txq->axq_depth >= (ATH_TXBUF - 20)) { + if (txq->axq_depth >= (ATH_TXBUF - 20) && + !(txctl->flags & ATH9K_TXDESC_CAB)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: TX queue: %d is full, depth: %d\n", __func__, @@ -354,7 +284,7 @@ static int ath_tx_prepare(struct ath_softc *sc, /* Fill flags */ - txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) txctl->flags |= ATH9K_TXDESC_NOACK; @@ -392,7 +322,7 @@ static int ath_tx_prepare(struct ath_softc *sc, * incremented by the fragmentation routine. */ if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) && - txctl->ht && sc->sc_txaggr) { + txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { struct ath_atx_tid *tid; tid = ATH_AN_2_TID(txctl->an, txctl->tidno); @@ -413,50 +343,18 @@ static int ath_tx_prepare(struct ath_softc *sc, } rix = rcs[0].rix; - /* - * Calculate duration. This logically belongs in the 802.11 - * layer but it lacks sufficient information to calculate it. - */ - if ((txctl->flags & ATH9K_TXDESC_NOACK) == 0 && !ieee80211_is_ctl(fc)) { - u16 dur; + if (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { /* - * XXX not right with fragmentation. - */ - if (sc->sc_flags & ATH_PREAMBLE_SHORT) - dur = rt->info[rix].spAckDuration; - else - dur = rt->info[rix].lpAckDuration; - - if (le16_to_cpu(hdr->frame_control) & - IEEE80211_FCTL_MOREFRAGS) { - dur += dur; /* Add additional 'SIFS + ACK' */ - - /* - ** Compute size of next fragment in order to compute - ** durations needed to update NAV. - ** The last fragment uses the ACK duration only. - ** Add time for next fragment. - */ - dur += ath9k_hw_computetxtime(sc->sc_ah, rt, - txctl->nextfraglen, - rix, sc->sc_flags & ATH_PREAMBLE_SHORT); - } - - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - /* - ** Force hardware to use computed duration for next - ** fragment by disabling multi-rate retry, which - ** updates duration based on the multi-rate - ** duration table. - */ - rcs[1].tries = rcs[2].tries = rcs[3].tries = 0; - rcs[1].rix = rcs[2].rix = rcs[3].rix = 0; - /* reset tries but keep rate index */ - rcs[0].tries = ATH_TXMAXTRY; - } - - hdr->duration_id = cpu_to_le16(dur); + ** Force hardware to use computed duration for next + ** fragment by disabling multi-rate retry, which + ** updates duration based on the multi-rate + ** duration table. + */ + rcs[1].tries = rcs[2].tries = rcs[3].tries = 0; + rcs[1].rix = rcs[2].rix = rcs[3].rix = 0; + /* reset tries but keep rate index */ + rcs[0].tries = ATH_TXMAXTRY; } /* @@ -484,12 +382,8 @@ static int ath_tx_prepare(struct ath_softc *sc, if (is_multicast_ether_addr(hdr->addr1)) { antenna = sc->sc_mcastantenna + 1; sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1; - } else - antenna = sc->sc_txantenna; + } -#ifdef USE_LEGACY_HAL - txctl->antenna = antenna; -#endif return 0; } @@ -502,7 +396,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc, { struct sk_buff *skb = bf->bf_mpdu; struct ath_xmit_status tx_status; - dma_addr_t *pa; /* * Set retry information. @@ -518,13 +411,12 @@ static void ath_tx_complete_buf(struct ath_softc *sc, if (!txok) { tx_status.flags |= ATH_TX_ERROR; - if (bf->bf_isxretried) + if (bf_isxretried(bf)) tx_status.flags |= ATH_TX_XRETRY; } /* Unmap this frame */ - pa = get_dma_mem_context(bf, bf_dmacontext); pci_unmap_single(sc->pdev, - *pa, + bf->bf_dmacontext, skb->len, PCI_DMA_TODEVICE); /* complete this frame */ @@ -629,7 +521,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) return 0; - isaggr = bf->bf_isaggr; + isaggr = bf_isaggr(bf); if (isaggr) { seq_st = ATH_DS_BA_SEQ(ds); memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3); @@ -651,7 +543,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) struct sk_buff *skb; struct ieee80211_hdr *hdr; - bf->bf_isretried = 1; + bf->bf_state.bf_type |= BUF_RETRY; bf->bf_retries++; skb = bf->bf_mpdu; @@ -698,7 +590,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rc; int streams, pktlen; - pktlen = bf->bf_isaggr ? bf->bf_al : bf->bf_frmlen; + pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; rc = rt->info[rix].rateCode; /* @@ -742,7 +634,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) int i, flags, rtsctsena = 0, dynamic_mimops = 0; u32 ctsduration = 0; u8 rix = 0, cix, ctsrate = 0; - u32 aggr_limit_with_rts = sc->sc_rtsaggrlimit; + u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit; struct ath_node *an = (struct ath_node *) bf->bf_node; /* @@ -781,7 +673,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * let rate series flags determine which rates will actually * use RTS. */ - if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf->bf_isdata) { + if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) { BUG_ON(!an); /* * 802.11g protection not needed, use our default behavior @@ -793,7 +685,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * and the second aggregate should have any protection at all. */ if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) { - if (!bf->bf_aggrburst) { + if (!bf_isaggrburst(bf)) { flags = ATH9K_TXDESC_RTSENA; dynamic_mimops = 1; } else { @@ -806,7 +698,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * Set protection if aggregate protection on */ if (sc->sc_config.ath_aggr_prot && - (!bf->bf_isaggr || (bf->bf_isaggr && bf->bf_al < 8192))) { + (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { flags = ATH9K_TXDESC_RTSENA; cix = rt->info[sc->sc_protrix].controlRate; rtsctsena = 1; @@ -815,7 +707,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) /* * For AR5416 - RTS cannot be followed by a frame larger than 8K. */ - if (bf->bf_isaggr && (bf->bf_al > aggr_limit_with_rts)) { + if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) { /* * Ensure that in the case of SM Dynamic power save * while we are bursting the second aggregate the @@ -832,12 +724,12 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) /* NB: cix is set above where RTS/CTS is enabled */ BUG_ON(cix == 0xff); ctsrate = rt->info[cix].rateCode | - (bf->bf_shpreamble ? rt->info[cix].shortPreamble : 0); + (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0); /* * Setup HAL rate series */ - memzero(series, sizeof(struct ath9k_11n_rate_series) * 4); + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); for (i = 0; i < 4; i++) { if (!bf->bf_rcs[i].tries) @@ -846,7 +738,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) rix = bf->bf_rcs[i].rix; series[i].Rate = rt->info[rix].rateCode | - (bf->bf_shpreamble ? rt->info[rix].shortPreamble : 0); + (bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0); series[i].Tries = bf->bf_rcs[i].tries; @@ -862,7 +754,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) sc, rix, bf, (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0, (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), - bf->bf_shpreamble); + bf_isshpreamble(bf)); if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) { @@ -875,7 +767,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) */ series[i].ChSel = sc->sc_tx_chainmask; } else { - if (bf->bf_ht) + if (bf_isht(bf)) series[i].ChSel = ath_chainmask_sel_logic(sc, an); else @@ -908,7 +800,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * use the precalculated ACK durations. */ if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */ - ctsduration += bf->bf_shpreamble ? + ctsduration += bf_isshpreamble(bf) ? rt->info[cix].spAckDuration : rt->info[cix].lpAckDuration; } @@ -916,7 +808,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) ctsduration += series[0].PktDuration; if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */ - ctsduration += bf->bf_shpreamble ? + ctsduration += bf_isshpreamble(bf) ? rt->info[rix].spAckDuration : rt->info[rix].lpAckDuration; } @@ -925,17 +817,17 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * Disable multi-rate retry when using RTS/CTS by clearing * series 1, 2 and 3. */ - memzero(&series[1], sizeof(struct ath9k_11n_rate_series) * 3); + memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3); } /* * set dur_update_en for l-sig computation except for PS-Poll frames */ ath9k_hw_set11n_ratescenario(ah, ds, lastds, - !bf->bf_ispspoll, - ctsrate, - ctsduration, - series, 4, flags); + !bf_ispspoll(bf), + ctsrate, + ctsduration, + series, 4, flags); if (sc->sc_config.ath_aggr_prot && flags) ath9k_hw_set11n_burstduration(ah, ds, 8192); } @@ -958,7 +850,7 @@ static int ath_tx_send_normal(struct ath_softc *sc, BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_isampdu = 0; /* regular HT frame */ + bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */ skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); @@ -998,7 +890,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) while (!list_empty(&tid->buf_q)) { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - ASSERT(!bf->bf_isretried); + ASSERT(!bf_isretried(bf)); list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list); ath_tx_send_normal(sc, txq, tid, &bf_head); } @@ -1025,7 +917,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, int isaggr, txfail, txpending, sendbar = 0, needreset = 0; int isnodegone = (an->an_flags & ATH_NODE_CLEAN); - isaggr = bf->bf_isaggr; + isaggr = bf_isaggr(bf); if (isaggr) { if (txok) { if (ATH_DS_TX_BA(ds)) { @@ -1038,7 +930,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3); } else { - memzero(ba, WME_BA_BMP_SIZE >> 3); + memset(ba, 0, WME_BA_BMP_SIZE >> 3); /* * AR5416 can become deaf/mute when BA @@ -1047,11 +939,11 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, * when perform internal reset in this routine. * Only enable reset in STA mode for now. */ - if (sc->sc_opmode == ATH9K_M_STA) + if (sc->sc_ah->ah_opmode == ATH9K_M_STA) needreset = 1; } } else { - memzero(ba, WME_BA_BMP_SIZE >> 3); + memset(ba, 0, WME_BA_BMP_SIZE >> 3); } } @@ -1075,7 +967,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, ath_tx_set_retry(sc, bf); txpending = 1; } else { - bf->bf_isxretried = 1; + bf->bf_state.bf_type |= BUF_XRETRY; txfail = 1; sendbar = 1; } @@ -1175,11 +1067,8 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, tbf->bf_lastfrm->bf_desc); /* copy the DMA context */ - copy_dma_mem_context( - get_dma_mem_context(tbf, - bf_dmacontext), - get_dma_mem_context(bf_last, - bf_dmacontext)); + tbf->bf_dmacontext = + bf_last->bf_dmacontext; } list_add_tail(&tbf->list, &bf_head); } else { @@ -1188,7 +1077,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, * software retry */ ath9k_hw_cleartxdesc(sc->sc_ah, - bf->bf_lastfrm->bf_desc); + bf->bf_lastfrm->bf_desc); } /* @@ -1242,7 +1131,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, } if (needreset) - ath_internal_reset(sc); + ath_reset(sc, false); return; } @@ -1331,7 +1220,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) txq->axq_depth--; - if (bf->bf_isaggr) + if (bf_isaggr(bf)) txq->axq_aggr_depth--; txok = (ds->ds_txstat.ts_status == 0); @@ -1345,14 +1234,14 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_unlock_bh(&sc->sc_txbuflock); } - if (!bf->bf_isampdu) { + if (!bf_isampdu(bf)) { /* * This frame is sent out as a single frame. * Use hardware retry status for this frame. */ bf->bf_retries = ds->ds_txstat.ts_longretry; if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) - bf->bf_isxretried = 1; + bf->bf_state.bf_type |= BUF_XRETRY; nbad = 0; } else { nbad = ath_tx_num_badfrms(sc, bf, txok); @@ -1368,7 +1257,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (ds->ds_txstat.ts_status == 0) nacked++; - if (bf->bf_isdata) { + if (bf_isdata(bf)) { if (isrifs) tmp_ds = bf->bf_rifslast->bf_desc; else @@ -1384,7 +1273,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) /* * Complete this transmit unit */ - if (bf->bf_isampdu) + if (bf_isampdu(bf)) ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, txok); else ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); @@ -1406,7 +1295,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) /* * schedule any pending packets if aggregation is enabled */ - if (sc->sc_txaggr) + if (sc->sc_flags & SC_OP_TXAGGR) ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); } @@ -1430,10 +1319,9 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) struct ath_hal *ah = sc->sc_ah; int i; int npend = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); /* XXX return value */ - if (!sc->sc_invalid) { + if (!(sc->sc_flags & SC_OP_INVALID)) { for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { ath_tx_stopdma(sc, &sc->sc_txq[i]); @@ -1454,10 +1342,11 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) "%s: Unable to stop TxDMA. Reset HAL!\n", __func__); spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, - &sc->sc_curchan, ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, true, &status)) { + if (!ath9k_hw_reset(ah, + sc->sc_ah->ah_curchan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, true, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u\n", @@ -1481,7 +1370,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc, { int index, cindex; - if (bf->bf_isretried) + if (bf_isretried(bf)) return; index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); @@ -1516,7 +1405,7 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_isampdu = 1; + bf->bf_state.bf_type |= BUF_AMPDU; bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */ bf->bf_tidno = txctl->tidno; @@ -1860,7 +1749,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, if (bf->bf_nframes == 1) { ASSERT(bf->bf_lastfrm == bf_last); - bf->bf_isaggr = 0; + bf->bf_state.bf_type &= ~BUF_AGGR; /* * clear aggr bits for every descriptor * XXX TODO: is there a way to optimize it? @@ -1877,7 +1766,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, /* * setup first desc with rate and aggr info */ - bf->bf_isaggr = 1; + bf->bf_state.bf_type |= BUF_AGGR; ath_buf_set_rate(sc, bf); ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al); @@ -1925,7 +1814,7 @@ static void ath_tid_drain(struct ath_softc *sc, list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list); /* update baw for software retried frame */ - if (bf->bf_isretried) + if (bf_isretried(bf)) ath_tx_update_baw(sc, tid, bf->bf_seqno); /* @@ -1990,13 +1879,18 @@ static int ath_tx_start_dma(struct ath_softc *sc, struct list_head bf_head; struct ath_desc *ds; struct ath_hal *ah = sc->sc_ah; - struct ath_txq *txq = &sc->sc_txq[txctl->qnum]; + struct ath_txq *txq; struct ath_tx_info_priv *tx_info_priv; struct ath_rc_series *rcs; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); __le16 fc = hdr->frame_control; + if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) + txq = sc->sc_cabq; + else + txq = &sc->sc_txq[txctl->qnum]; + /* For each sglist entry, allocate an ath_buf for DMA */ INIT_LIST_HEAD(&bf_head); spin_lock_bh(&sc->sc_txbuflock); @@ -2014,11 +1908,21 @@ static int ath_tx_start_dma(struct ath_softc *sc, /* set up this buffer */ ATH_TXBUF_RESET(bf); bf->bf_frmlen = txctl->frmlen; - bf->bf_isdata = ieee80211_is_data(fc); - bf->bf_isbar = ieee80211_is_back_req(fc); - bf->bf_ispspoll = ieee80211_is_pspoll(fc); + + ieee80211_is_data(fc) ? + (bf->bf_state.bf_type |= BUF_DATA) : + (bf->bf_state.bf_type &= ~BUF_DATA); + ieee80211_is_back_req(fc) ? + (bf->bf_state.bf_type |= BUF_BAR) : + (bf->bf_state.bf_type &= ~BUF_BAR); + ieee80211_is_pspoll(fc) ? + (bf->bf_state.bf_type |= BUF_PSPOLL) : + (bf->bf_state.bf_type &= ~BUF_PSPOLL); + (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? + (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : + (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); + bf->bf_flags = txctl->flags; - bf->bf_shpreamble = sc->sc_flags & ATH_PREAMBLE_SHORT; bf->bf_keytype = txctl->keytype; tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; rcs = tx_info_priv->rcs; @@ -2038,8 +1942,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, /* * Save the DMA context in the first ath_buf */ - copy_dma_mem_context(get_dma_mem_context(bf, bf_dmacontext), - get_dma_mem_context(txctl, dmacontext)); + bf->bf_dmacontext = txctl->dmacontext; /* * Formulate first tx descriptor with tx controls. @@ -2060,11 +1963,13 @@ static int ath_tx_start_dma(struct ath_softc *sc, ds); /* first descriptor */ bf->bf_lastfrm = bf; - bf->bf_ht = txctl->ht; + (txctl->ht) ? + (bf->bf_state.bf_type |= BUF_HT) : + (bf->bf_state.bf_type &= ~BUF_HT); spin_lock_bh(&txq->axq_lock); - if (txctl->ht && sc->sc_txaggr) { + if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno); if (ath_aggr_query(sc, an, txctl->tidno)) { /* @@ -2090,27 +1995,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, bf->bf_tidno = txctl->tidno; } - if (is_multicast_ether_addr(hdr->addr1)) { - struct ath_vap *avp = sc->sc_vaps[txctl->if_id]; - - /* - * When servicing one or more stations in power-save - * mode (or) if there is some mcast data waiting on - * mcast queue (to prevent out of order delivery of - * mcast,bcast packets) multicast frames must be - * buffered until after the beacon. We use the private - * mcast queue for that. - */ - /* XXX? more bit in 802.11 frame header */ - spin_lock_bh(&avp->av_mcastq.axq_lock); - if (txctl->ps || avp->av_mcastq.axq_depth) - ath_tx_mcastqaddbuf(sc, - &avp->av_mcastq, &bf_head); - else - ath_tx_txqaddbuf(sc, txq, &bf_head); - spin_unlock_bh(&avp->av_mcastq.axq_lock); - } else - ath_tx_txqaddbuf(sc, txq, &bf_head); + ath_tx_txqaddbuf(sc, txq, &bf_head); } spin_unlock_bh(&txq->axq_lock); return 0; @@ -2118,30 +2003,31 @@ static int ath_tx_start_dma(struct ath_softc *sc, static void xmit_map_sg(struct ath_softc *sc, struct sk_buff *skb, - dma_addr_t *pa, struct ath_tx_control *txctl) { struct ath_xmit_status tx_status; struct ath_atx_tid *tid; struct scatterlist sg; - *pa = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + txctl->dmacontext = pci_map_single(sc->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); /* setup S/G list */ memset(&sg, 0, sizeof(struct scatterlist)); - sg_dma_address(&sg) = *pa; + sg_dma_address(&sg) = txctl->dmacontext; sg_dma_len(&sg) = skb->len; if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) { /* * We have to do drop frame here. */ - pci_unmap_single(sc->pdev, *pa, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(sc->pdev, txctl->dmacontext, + skb->len, PCI_DMA_TODEVICE); tx_status.retries = 0; tx_status.flags = ATH_TX_ERROR; - if (txctl->ht && sc->sc_txaggr) { + if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { /* Reclaim the seqno. */ tid = ATH_AN_2_TID((struct ath_node *) txctl->an, txctl->tidno); @@ -2162,7 +2048,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) /* Setup tx descriptors */ error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, - "tx", nbufs * ATH_FRAG_PER_MSDU, ATH_TXDESC); + "tx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, "%s: failed to allocate tx descriptors: %d\n", @@ -2212,7 +2098,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) struct ath9k_tx_queue_info qi; int qnum; - memzero(&qi, sizeof(qi)); + memset(&qi, 0, sizeof(qi)); qi.tqi_subtype = subtype; qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; @@ -2403,6 +2289,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) struct ath_tx_control txctl; int error = 0; + memset(&txctl, 0, sizeof(struct ath_tx_control)); error = ath_tx_prepare(sc, skb, &txctl); if (error == 0) /* @@ -2410,9 +2297,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) * ath_tx_start_dma() will be called either synchronously * or asynchrounsly once DMA is complete. */ - xmit_map_sg(sc, skb, - get_dma_mem_context(&txctl, dmacontext), - &txctl); + xmit_map_sg(sc, skb, &txctl); else ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); @@ -2424,8 +2309,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) void ath_tx_tasklet(struct ath_softc *sc) { - u64 tsf = ath9k_hw_gettsf64(sc->sc_ah); - int i, nacked = 0; + int i; u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1); ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask); @@ -2435,10 +2319,8 @@ void ath_tx_tasklet(struct ath_softc *sc) */ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) - nacked += ath_tx_processq(sc, &sc->sc_txq[i]); + ath_tx_processq(sc, &sc->sc_txq[i]); } - if (nacked) - sc->sc_lastrx = tsf; } void ath_tx_draintxq(struct ath_softc *sc, @@ -2486,14 +2368,14 @@ void ath_tx_draintxq(struct ath_softc *sc, spin_unlock_bh(&txq->axq_lock); - if (bf->bf_isampdu) + if (bf_isampdu(bf)) ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, 0); else ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); } /* flush any pending frames if aggregation is enabled */ - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { if (!retry_tx) { spin_lock_bh(&txq->axq_lock); ath_txq_drain_pending_buffers(sc, txq, @@ -2509,7 +2391,7 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx) { /* stop beacon queue. The beacon will be freed when * we go to INIT state */ - if (!sc->sc_invalid) { + if (!(sc->sc_flags & SC_OP_INVALID)) { (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__, ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq)); @@ -2536,7 +2418,7 @@ enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, struct ath_atx_tid *txtid; DECLARE_MAC_BUF(mac); - if (!sc->sc_txaggr) + if (!(sc->sc_flags & SC_OP_TXAGGR)) return AGGR_NOT_REQUIRED; /* ADDBA exchange must be completed before sending aggregates */ @@ -2583,7 +2465,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, return -1; } - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { txtid = ATH_AN_2_TID(an, tid); txtid->addba_exchangeinprogress = 1; ath_tx_pause_tid(sc, txtid); @@ -2647,7 +2529,7 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, spin_lock_bh(&txq->axq_lock); while (!list_empty(&txtid->buf_q)) { bf = list_first_entry(&txtid->buf_q, struct ath_buf, list); - if (!bf->bf_isretried) { + if (!bf_isretried(bf)) { /* * NB: it's based on the assumption that * software retried frame will always stay @@ -2743,7 +2625,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { struct ath_atx_tid *tid; struct ath_atx_ac *ac; int tidno, acno; @@ -2855,7 +2737,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { struct ath_atx_tid *tid; int tidno, i; @@ -2869,3 +2751,57 @@ void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an) } } } + +void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) +{ + int hdrlen, padsize; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ath_tx_control txctl; + + /* + * As a temporary workaround, assign seq# here; this will likely need + * to be cleaned up to work better with Beacon transmission and virtual + * BSSes. + */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + } + + /* Add the padding after the header if this is not already done */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + if (hdrlen & 3) { + padsize = hdrlen % 4; + if (skb_headroom(skb) < padsize) { + DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding " + "failed\n", __func__); + dev_kfree_skb_any(skb); + return; + } + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, hdrlen); + } + + DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n", + __func__, + skb); + + memset(&txctl, 0, sizeof(struct ath_tx_control)); + txctl.flags = ATH9K_TXDESC_CAB; + if (ath_tx_prepare(sc, skb, &txctl) == 0) { + /* + * Start DMA mapping. + * ath_tx_start_dma() will be called either synchronously + * or asynchrounsly once DMA is complete. + */ + xmit_map_sg(sc, skb, &txctl); + } else { + ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); + DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__); + dev_kfree_skb_any(skb); + } +} + diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index bd65c485098..ecb02bdaab5 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -2258,7 +2258,7 @@ static int atmel_get_freq(struct net_device *dev, static int atmel_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + struct iw_point *dwrq, char *extra) { struct atmel_private *priv = netdev_priv(dev); diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 12617cd0b78..77406245dc7 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -158,7 +158,7 @@ static int atmel_probe(struct pcmcia_device *p_dev) DEBUG(0, "atmel_attach()\n"); /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = NULL; @@ -224,13 +224,58 @@ static int card_present(void *arg) return 0; } +static int atmel_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->index == 0) + return -ENODEV; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + p_dev->conf.Attributes |= CONF_ENABLE_SPKR; + p_dev->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + return pcmcia_request_io(p_dev, &p_dev->io); +} + static int atmel_config(struct pcmcia_device *link) { - tuple_t tuple; - cisparse_t parse; local_info_t *dev; int last_fn, last_ret; - u_char buf[64]; struct pcmcia_device_id *did; dev = link->priv; @@ -238,11 +283,6 @@ static int atmel_config(struct pcmcia_device *link) DEBUG(0, "atmel_config(0x%p)\n", link); - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - /* In this loop, we scan the CIS for configuration table entries, each of which describes a valid card configuration, including @@ -255,66 +295,8 @@ static int atmel_config(struct pcmcia_device *link) these things without consulting the CIS, and most client drivers will only use the CIS to fill in implementation-defined details. */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (1) { - cistpl_cftable_entry_t dflt = { 0 }; - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(link, &tuple) != 0 || - pcmcia_parse_tuple(link, &tuple, &parse) != 0) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; - if (cfg->index == 0) goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) - link->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; - else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) - link->conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - - /* If we got this far, we're cool! */ - break; - - next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); - } + if (pcmcia_loop_config(link, atmel_config_check, NULL)) + goto failed; /* Allocate an interrupt line. Note that this does not assign a @@ -360,6 +342,7 @@ static int atmel_config(struct pcmcia_device *link) cs_failed: cs_error(link, last_fn, last_ret); + failed: atmel_release(link); return -ENODEV; } diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 1fa043d1802..1f81d36f87c 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -80,6 +80,18 @@ config B43_NPHY SAY N. +config B43_PHY_LP + bool "IEEE 802.11g LP-PHY support (BROKEN)" + depends on B43 && EXPERIMENTAL && BROKEN + ---help--- + Support for the LP-PHY. + The LP-PHY is an IEEE 802.11g based PHY built into some notebooks + and embedded devices. + + THIS IS BROKEN AND DOES NOT WORK YET. + + SAY N. + # This config option automatically enables b43 LEDS support, # if it's possible. config B43_LEDS diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 8c52b0b9862..14a02b3aea5 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -1,8 +1,11 @@ b43-y += main.o b43-y += tables.o b43-$(CONFIG_B43_NPHY) += tables_nphy.o -b43-y += phy.o -b43-$(CONFIG_B43_NPHY) += nphy.o +b43-y += phy_common.o +b43-y += phy_g.o +b43-y += phy_a.o +b43-$(CONFIG_B43_NPHY) += phy_n.o +b43-$(CONFIG_B43_PHY_LP) += phy_lp.o b43-y += sysfs.o b43-y += xmit.o b43-y += lo.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index edcdfa36645..427b8203e3f 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -12,7 +12,7 @@ #include "leds.h" #include "rfkill.h" #include "lo.h" -#include "phy.h" +#include "phy_common.h" /* The unique identifier of the firmware that's officially supported by @@ -173,6 +173,11 @@ enum { #define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ #define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */ #define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ +/* TSSI information */ +#define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */ +#define B43_SHM_SH_TSSI_OFDM_A 0x0068 /* TSSI for last 4 OFDM frames (32bit) */ +#define B43_SHM_SH_TSSI_OFDM_G 0x0070 /* TSSI for last 4 OFDM frames (32bit) */ +#define B43_TSSI_MAX 0x7F /* Max value for one TSSI value */ /* SHM_SHARED TX FIFO variables */ #define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */ #define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */ @@ -508,122 +513,6 @@ struct b43_iv { } __attribute__((__packed__)); -struct b43_phy { - /* Band support flags. */ - bool supports_2ghz; - bool supports_5ghz; - - /* GMODE bit enabled? */ - bool gmode; - - /* Analog Type */ - u8 analog; - /* B43_PHYTYPE_ */ - u8 type; - /* PHY revision number. */ - u8 rev; - - /* Radio versioning */ - u16 radio_manuf; /* Radio manufacturer */ - u16 radio_ver; /* Radio version */ - u8 radio_rev; /* Radio revision */ - - bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ - - /* ACI (adjacent channel interference) flags. */ - bool aci_enable; - bool aci_wlan_automatic; - bool aci_hw_rssi; - - /* Radio switched on/off */ - bool radio_on; - struct { - /* Values saved when turning the radio off. - * They are needed when turning it on again. */ - bool valid; - u16 rfover; - u16 rfoverval; - } radio_off_context; - - u16 minlowsig[2]; - u16 minlowsigpos[2]; - - /* TSSI to dBm table in use */ - const s8 *tssi2dbm; - /* Target idle TSSI */ - int tgt_idle_tssi; - /* Current idle TSSI */ - int cur_idle_tssi; - - /* LocalOscillator control values. */ - struct b43_txpower_lo_control *lo_control; - /* Values from b43_calc_loopback_gain() */ - s16 max_lb_gain; /* Maximum Loopback gain in hdB */ - s16 trsw_rx_gain; /* TRSW RX gain in hdB */ - s16 lna_lod_gain; /* LNA lod */ - s16 lna_gain; /* LNA */ - s16 pga_gain; /* PGA */ - - /* Desired TX power level (in dBm). - * This is set by the user and adjusted in b43_phy_xmitpower(). */ - u8 power_level; - /* A-PHY TX Power control value. */ - u16 txpwr_offset; - - /* Current TX power level attenuation control values */ - struct b43_bbatt bbatt; - struct b43_rfatt rfatt; - u8 tx_control; /* B43_TXCTL_XXX */ - - /* Hardware Power Control enabled? */ - bool hardware_power_control; - - /* Current Interference Mitigation mode */ - int interfmode; - /* Stack of saved values from the Interference Mitigation code. - * Each value in the stack is layed out as follows: - * bit 0-11: offset - * bit 12-15: register ID - * bit 16-32: value - * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT - */ -#define B43_INTERFSTACK_SIZE 26 - u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure - - /* Saved values from the NRSSI Slope calculation */ - s16 nrssi[2]; - s32 nrssislope; - /* In memory nrssi lookup table. */ - s8 nrssi_lt[64]; - - /* current channel */ - u8 channel; - - u16 lofcal; - - u16 initval; //FIXME rename? - - /* PHY TX errors counter. */ - atomic_t txerr_cnt; - - /* The device does address auto increment for the OFDM tables. - * We cache the previously used address here and omit the address - * write on the next table access, if possible. */ - u16 ofdmtab_addr; /* The address currently set in hardware. */ - enum { /* The last data flow direction. */ - B43_OFDMTAB_DIRECTION_UNKNOWN = 0, - B43_OFDMTAB_DIRECTION_READ, - B43_OFDMTAB_DIRECTION_WRITE, - } ofdmtab_addr_direction; - -#if B43_DEBUG - /* Manual TX-power control enabled? */ - bool manual_txpower_control; - /* PHY registers locked by b43_phy_lock()? */ - bool phy_locked; -#endif /* B43_DEBUG */ -}; - /* Data structures for DMA transmission, per 80211 core. */ struct b43_dma { struct b43_dmaring *tx_ring_AC_BK; /* Background */ @@ -680,7 +569,7 @@ struct b43_key { #define B43_QOS_VOICE B43_QOS_PARAMS(3) /* QOS parameter hardware data structure offsets. */ -#define B43_NR_QOSPARAMS 22 +#define B43_NR_QOSPARAMS 16 enum { B43_QOSPARAM_TXOP = 0, B43_QOSPARAM_CWMIN, @@ -696,8 +585,6 @@ enum { struct b43_qos_params { /* The QOS parameters */ struct ieee80211_tx_queue_params p; - /* Does this need to get uploaded to hardware? */ - bool need_hw_update; }; struct b43_wldev; @@ -759,11 +646,13 @@ struct b43_wl { bool beacon_templates_virgin; /* Never wrote the templates? */ struct work_struct beacon_update_trigger; - /* The current QOS parameters for the 4 queues. - * This is protected by the irq_lock. */ + /* The current QOS parameters for the 4 queues. */ struct b43_qos_params qos_params[4]; - /* Workqueue for updating QOS parameters in hardware. */ - struct work_struct qos_update_work; + + /* Work for adjustment of the transmission power. + * This is scheduled when we determine that the actual TX output + * power doesn't match what we want. */ + struct work_struct txpower_adjust_work; }; /* In-memory representation of a cached microcode file. */ @@ -908,6 +797,15 @@ static inline int b43_is_mode(struct b43_wl *wl, int type) return (wl->operating && wl->if_type == type); } +/** + * b43_current_band - Returns the currently used band. + * Returns one of IEEE80211_BAND_2GHZ and IEEE80211_BAND_5GHZ. + */ +static inline enum ieee80211_band b43_current_band(struct b43_wl *wl) +{ + return wl->hw->conf.channel->band; +} + static inline u16 b43_read16(struct b43_wldev *dev, u16 offset) { return ssb_read16(dev->dev, offset); diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 29851bc1101..06a01da8016 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -443,76 +443,6 @@ out_unlock: return count; } -static ssize_t txpower_g_read_file(struct b43_wldev *dev, - char *buf, size_t bufsize) -{ - ssize_t count = 0; - - if (dev->phy.type != B43_PHYTYPE_G) { - fappend("Device is not a G-PHY\n"); - goto out; - } - fappend("Control: %s\n", dev->phy.manual_txpower_control ? - "MANUAL" : "AUTOMATIC"); - fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att); - fappend("Radio attenuation: %u\n", dev->phy.rfatt.att); - fappend("TX Mixer Gain: %s\n", - (dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF"); - fappend("PA Gain 2dB: %s\n", - (dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF"); - fappend("PA Gain 3dB: %s\n", - (dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF"); - fappend("\n\n"); - fappend("You can write to this file:\n"); - fappend("Writing \"auto\" enables automatic txpower control.\n"); - fappend - ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" " - "enables manual txpower control.\n"); - fappend("Example: 5 4 0 0 1\n"); - fappend("Enables manual control with Baseband attenuation 5, " - "Radio attenuation 4, No TX Mixer Gain, " - "No PA Gain 2dB, With PA Gain 3dB.\n"); -out: - return count; -} - -static int txpower_g_write_file(struct b43_wldev *dev, - const char *buf, size_t count) -{ - if (dev->phy.type != B43_PHYTYPE_G) - return -ENODEV; - if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { - /* Automatic control */ - dev->phy.manual_txpower_control = 0; - b43_phy_xmitpower(dev); - } else { - int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0; - /* Manual control */ - if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt, - &txmix, &pa2db, &pa3db) != 5) - return -EINVAL; - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - dev->phy.manual_txpower_control = 1; - dev->phy.bbatt.att = bbatt; - dev->phy.rfatt.att = rfatt; - dev->phy.tx_control = 0; - if (txmix) - dev->phy.tx_control |= B43_TXCTL_TXMIX; - if (pa2db) - dev->phy.tx_control |= B43_TXCTL_PA2DB; - if (pa3db) - dev->phy.tx_control |= B43_TXCTL_PA3DB; - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_set_txpower_g(dev, &dev->phy.bbatt, - &dev->phy.rfatt, dev->phy.tx_control); - b43_radio_unlock(dev); - b43_phy_unlock(dev); - } - - return 0; -} - /* wl->irq_lock is locked */ static int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) @@ -560,7 +490,7 @@ static ssize_t loctls_read_file(struct b43_wldev *dev, err = -ENODEV; goto out; } - lo = phy->lo_control; + lo = phy->g->lo_control; fappend("-- Local Oscillator calibration data --\n\n"); fappend("HW-power-control enabled: %d\n", dev->phy.hardware_power_control); @@ -578,8 +508,8 @@ static ssize_t loctls_read_file(struct b43_wldev *dev, list_for_each_entry(cal, &lo->calib_list, list) { bool active; - active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && - b43_compare_rfatt(&cal->rfatt, &phy->rfatt)); + active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) && + b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt)); fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d " "(expires in %lu sec)%s\n", cal->bbatt.att, @@ -763,7 +693,6 @@ B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1); B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); -B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0); B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); @@ -877,7 +806,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev) ADD_FILE(mmio32write, 0200); ADD_FILE(tsf, 0600); ADD_FILE(txstat, 0400); - ADD_FILE(txpower_g, 0600); ADD_FILE(restart, 0200); ADD_FILE(loctls, 0400); @@ -907,7 +835,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) debugfs_remove(e->file_mmio32write.dentry); debugfs_remove(e->file_tsf.dentry); debugfs_remove(e->file_txstat.dentry); - debugfs_remove(e->file_txpower_g.dentry); debugfs_remove(e->file_restart.dentry); debugfs_remove(e->file_loctls.dentry); diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 9c854d6aae3..6a18a147046 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -29,7 +29,7 @@ #include "b43.h" #include "lo.h" -#include "phy.h" +#include "phy_g.h" #include "main.h" #include <linux/delay.h> @@ -174,7 +174,8 @@ static u16 lo_txctl_register_table(struct b43_wldev *dev, static void lo_measure_txctl_values(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; u16 reg, mask; u16 trsw_rx, pga; u16 radio_pctl_reg; @@ -195,7 +196,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) int lb_gain; /* Loopback gain (in dB) */ trsw_rx = 0; - lb_gain = phy->max_lb_gain / 2; + lb_gain = gphy->max_lb_gain / 2; if (lb_gain > 10) { radio_pctl_reg = 0; pga = abs(10 - lb_gain) / 6; @@ -226,7 +227,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) } b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) & 0xFFF0) | radio_pctl_reg); - b43_phy_set_baseband_attenuation(dev, 2); + b43_gphy_set_baseband_attenuation(dev, 2); reg = lo_txctl_register_table(dev, &mask, NULL); mask = ~mask; @@ -277,7 +278,8 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) static void lo_read_power_vector(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; int i; u64 tmp; u64 power_vector = 0; @@ -298,6 +300,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev, s16 max_rx_gain, int use_trsw_rx) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; u16 tmp; if (max_rx_gain < 0) @@ -308,7 +311,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev, int trsw_rx_gain; if (use_trsw_rx) { - trsw_rx_gain = phy->trsw_rx_gain / 2; + trsw_rx_gain = gphy->trsw_rx_gain / 2; if (max_rx_gain >= trsw_rx_gain) { trsw_rx_gain = max_rx_gain - trsw_rx_gain; trsw_rx = 0x20; @@ -316,38 +319,38 @@ static void lo_measure_gain_values(struct b43_wldev *dev, } else trsw_rx_gain = max_rx_gain; if (trsw_rx_gain < 9) { - phy->lna_lod_gain = 0; + gphy->lna_lod_gain = 0; } else { - phy->lna_lod_gain = 1; + gphy->lna_lod_gain = 1; trsw_rx_gain -= 8; } trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D); - phy->pga_gain = trsw_rx_gain / 3; - if (phy->pga_gain >= 5) { - phy->pga_gain -= 5; - phy->lna_gain = 2; + gphy->pga_gain = trsw_rx_gain / 3; + if (gphy->pga_gain >= 5) { + gphy->pga_gain -= 5; + gphy->lna_gain = 2; } else - phy->lna_gain = 0; + gphy->lna_gain = 0; } else { - phy->lna_gain = 0; - phy->trsw_rx_gain = 0x20; + gphy->lna_gain = 0; + gphy->trsw_rx_gain = 0x20; if (max_rx_gain >= 0x14) { - phy->lna_lod_gain = 1; - phy->pga_gain = 2; + gphy->lna_lod_gain = 1; + gphy->pga_gain = 2; } else if (max_rx_gain >= 0x12) { - phy->lna_lod_gain = 1; - phy->pga_gain = 1; + gphy->lna_lod_gain = 1; + gphy->pga_gain = 1; } else if (max_rx_gain >= 0xF) { - phy->lna_lod_gain = 1; - phy->pga_gain = 0; + gphy->lna_lod_gain = 1; + gphy->pga_gain = 0; } else { - phy->lna_lod_gain = 0; - phy->pga_gain = 0; + gphy->lna_lod_gain = 0; + gphy->pga_gain = 0; } } tmp = b43_radio_read16(dev, 0x7A); - if (phy->lna_lod_gain == 0) + if (gphy->lna_lod_gain == 0) tmp &= ~0x0008; else tmp |= 0x0008; @@ -392,10 +395,11 @@ static void lo_measure_setup(struct b43_wldev *dev, { struct ssb_sprom *sprom = &dev->dev->bus->sprom; struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; u16 tmp; - if (b43_has_hardware_pctl(phy)) { + if (b43_has_hardware_pctl(dev)) { sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01)); sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL); @@ -496,7 +500,7 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); if (phy->rev >= 2) b43_dummy_transmission(dev); - b43_radio_selectchannel(dev, 6, 0); + b43_gphy_channel_switch(dev, 6, 0); b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); @@ -520,18 +524,19 @@ static void lo_measure_restore(struct b43_wldev *dev, struct lo_g_saved_values *sav) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; u16 tmp; if (phy->rev >= 2) { b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); - tmp = (phy->pga_gain << 8); + tmp = (gphy->pga_gain << 8); b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0); udelay(5); b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2); udelay(2); b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3); } else { - tmp = (phy->pga_gain | 0xEFA0); + tmp = (gphy->pga_gain | 0xEFA0); b43_phy_write(dev, B43_PHY_PGACTL, tmp); } if (phy->type == B43_PHYTYPE_G) { @@ -572,7 +577,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E); b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0); } - if (b43_has_hardware_pctl(phy)) { + if (b43_has_hardware_pctl(dev)) { tmp = (sav->phy_lo_mask & 0xBFFF); b43_phy_write(dev, B43_PHY_LO_MASK, tmp); b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01); @@ -580,7 +585,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14); b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl); } - b43_radio_selectchannel(dev, sav->old_channel, 1); + b43_gphy_channel_switch(dev, sav->old_channel, 1); } struct b43_lo_g_statemachine { @@ -597,6 +602,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, struct b43_lo_g_statemachine *d) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct b43_loctl test_loctl; struct b43_loctl orig_loctl; struct b43_loctl prev_loctl = { @@ -646,9 +652,9 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, test_loctl.q != prev_loctl.q) && (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) { b43_lo_write(dev, &test_loctl); - feedth = lo_measure_feedthrough(dev, phy->lna_gain, - phy->pga_gain, - phy->trsw_rx_gain); + feedth = lo_measure_feedthrough(dev, gphy->lna_gain, + gphy->pga_gain, + gphy->trsw_rx_gain); if (feedth < d->lowest_feedth) { memcpy(probe_loctl, &test_loctl, sizeof(struct b43_loctl)); @@ -677,6 +683,7 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, int *max_rx_gain) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct b43_lo_g_statemachine d; u16 feedth; int found_lower; @@ -693,17 +700,17 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, max_repeat = 4; do { b43_lo_write(dev, &d.min_loctl); - feedth = lo_measure_feedthrough(dev, phy->lna_gain, - phy->pga_gain, - phy->trsw_rx_gain); + feedth = lo_measure_feedthrough(dev, gphy->lna_gain, + gphy->pga_gain, + gphy->trsw_rx_gain); if (feedth < 0x258) { if (feedth >= 0x12C) *max_rx_gain += 6; else *max_rx_gain += 3; - feedth = lo_measure_feedthrough(dev, phy->lna_gain, - phy->pga_gain, - phy->trsw_rx_gain); + feedth = lo_measure_feedthrough(dev, gphy->lna_gain, + gphy->pga_gain, + gphy->trsw_rx_gain); } d.lowest_feedth = feedth; @@ -752,6 +759,7 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, const struct b43_rfatt *rfatt) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct b43_loctl loctl = { .i = 0, .q = 0, @@ -782,11 +790,11 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, if (rfatt->with_padmix) max_rx_gain -= pad_mix_gain; if (has_loopback_gain(phy)) - max_rx_gain += phy->max_lb_gain; + max_rx_gain += gphy->max_lb_gain; lo_measure_gain_values(dev, max_rx_gain, has_loopback_gain(phy)); - b43_phy_set_baseband_attenuation(dev, bbatt->att); + b43_gphy_set_baseband_attenuation(dev, bbatt->att); lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); lo_measure_restore(dev, &saved_regs); @@ -820,7 +828,7 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, const struct b43_bbatt *bbatt, const struct b43_rfatt *rfatt) { - struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; struct b43_lo_calib *c; c = b43_find_lo_calib(lo, bbatt, rfatt); @@ -839,7 +847,8 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; int i; int rf_offset, bb_offset; const struct b43_rfatt *rfatt; @@ -917,14 +926,14 @@ static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf) void b43_lo_g_adjust(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; struct b43_lo_calib *cal; struct b43_rfatt rf; - memcpy(&rf, &phy->rfatt, sizeof(rf)); + memcpy(&rf, &gphy->rfatt, sizeof(rf)); b43_lo_fixup_rfatt(&rf); - cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf); + cal = b43_get_calib_lo_settings(dev, &gphy->bbatt, &rf); if (!cal) return; b43_lo_write(dev, &cal->ctl); @@ -952,7 +961,8 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, void b43_lo_g_maintanance_work(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; unsigned long now; unsigned long expire; struct b43_lo_calib *cal, *tmp; @@ -962,7 +972,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) if (!lo) return; now = jiffies; - hwpctl = b43_has_hardware_pctl(phy); + hwpctl = b43_has_hardware_pctl(dev); if (hwpctl) { /* Read the power vector and update it, if needed. */ @@ -983,8 +993,8 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) if (!time_before(cal->calib_time, expire)) continue; /* This item expired. */ - if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && - b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) { + if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) && + b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) { B43_WARN_ON(current_item_expired); current_item_expired = 1; } @@ -1002,7 +1012,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) /* Recalibrate currently used LO setting. */ if (b43_debug(dev, B43_DBG_LO)) b43dbg(dev->wl, "LO: Recalibrating current LO setting\n"); - cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt); + cal = b43_calibrate_lo_setting(dev, &gphy->bbatt, &gphy->rfatt); if (cal) { list_add(&cal->list, &lo->calib_list); b43_lo_write(dev, &cal->ctl); @@ -1013,7 +1023,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) void b43_lo_g_cleanup(struct b43_wldev *dev) { - struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; struct b43_lo_calib *cal, *tmp; if (!lo) @@ -1027,9 +1037,7 @@ void b43_lo_g_cleanup(struct b43_wldev *dev) /* LO Initialization */ void b43_lo_g_init(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - - if (b43_has_hardware_pctl(phy)) { + if (b43_has_hardware_pctl(dev)) { lo_read_power_vector(dev); b43_gphy_dc_lt_init(dev, 1); } diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 1da321cabc1..3b27e20eff8 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -1,7 +1,9 @@ #ifndef B43_LO_H_ #define B43_LO_H_ -#include "phy.h" +/* G-PHY Local Oscillator */ + +#include "phy_g.h" struct b43_wldev; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7205a936ec7..14c44df584d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -44,8 +44,9 @@ #include "b43.h" #include "main.h" #include "debugfs.h" -#include "phy.h" -#include "nphy.h" +#include "phy_common.h" +#include "phy_g.h" +#include "phy_n.h" #include "dma.h" #include "pio.h" #include "sysfs.h" @@ -814,7 +815,7 @@ void b43_dummy_transmission(struct b43_wldev *dev) break; udelay(10); } - for (i = 0x00; i < 0x0A; i++) { + for (i = 0x00; i < 0x19; i++) { value = b43_read16(dev, 0x0690); if (!(value & 0x0100)) break; @@ -1051,23 +1052,6 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) } } -/* Turn the Analog ON/OFF */ -static void b43_switch_analog(struct b43_wldev *dev, int on) -{ - switch (dev->phy.type) { - case B43_PHYTYPE_A: - case B43_PHYTYPE_G: - b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); - break; - case B43_PHYTYPE_N: - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, - on ? 0 : 0x7FFF); - break; - default: - B43_WARN_ON(1); - } -} - void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) { u32 tmslow; @@ -1090,8 +1074,12 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ msleep(1); - /* Turn Analog ON */ - b43_switch_analog(dev, 1); + /* Turn Analog ON, but only if we already know the PHY-type. + * This protects against very early setup where we don't know the + * PHY-type, yet. wireless_core_reset will be called once again later, + * when we know the PHY-type. */ + if (dev->phy.ops) + dev->phy.ops->switch_analog(dev, 1); macctl = b43_read32(dev, B43_MMIO_MACCTL); macctl &= ~B43_MACCTL_GMODE; @@ -1174,6 +1162,8 @@ static void b43_calculate_link_quality(struct b43_wldev *dev) { /* Top half of Link Quality calculation. */ + if (dev->phy.type != B43_PHYTYPE_G) + return; if (dev->noisecalc.calculation_running) return; dev->noisecalc.calculation_running = 1; @@ -1184,7 +1174,7 @@ static void b43_calculate_link_quality(struct b43_wldev *dev) static void handle_irq_noise(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *phy = dev->phy.g; u16 tmp; u8 noise[4]; u8 i, j; @@ -1192,6 +1182,9 @@ static void handle_irq_noise(struct b43_wldev *dev) /* Bottom half of Link Quality calculation. */ + if (dev->phy.type != B43_PHYTYPE_G) + return; + /* Possible race condition: It might be possible that the user * changed to a different channel in the meantime since we * started the calculation. We ignore that fact, since it's @@ -1251,13 +1244,13 @@ generate_new: static void handle_irq_tbtt_indication(struct b43_wldev *dev) { - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + if (b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) { ///TODO: PS TBTT } else { if (1 /*FIXME: the last PSpoll frame was sent successfully */ ) b43_power_saving_ctl_bits(dev, 0); } - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) dev->dfq_valid = 1; } @@ -1606,8 +1599,8 @@ static void handle_irq_beacon(struct b43_wldev *dev) struct b43_wl *wl = dev->wl; u32 cmd, beacon0_valid, beacon1_valid; - if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) && - !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) + if (!b43_is_mode(wl, NL80211_IFTYPE_AP) && + !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) return; /* This is the bottom half of the asynchronous beacon update. */ @@ -2575,10 +2568,10 @@ static void b43_adjust_opmode(struct b43_wldev *dev) ctl &= ~B43_MACCTL_BEACPROMISC; ctl |= B43_MACCTL_INFRA; - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || - b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) + if (b43_is_mode(wl, NL80211_IFTYPE_AP) || + b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) ctl |= B43_MACCTL_AP; - else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) ctl &= ~B43_MACCTL_INFRA; if (wl->filter_flags & FIF_CONTROL) @@ -2688,9 +2681,8 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { - b43_radio_turn_off(dev, 1); + b43_phy_exit(dev); b43_gpio_cleanup(dev); - b43_lo_g_cleanup(dev); /* firmware is released later */ } @@ -2700,7 +2692,7 @@ static void b43_chip_exit(struct b43_wldev *dev) static int b43_chip_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - int err, tmp; + int err; u32 value32, macctl; u16 value16; @@ -2725,19 +2717,20 @@ static int b43_chip_init(struct b43_wldev *dev) err = b43_upload_initvals(dev); if (err) goto err_gpio_clean; - b43_radio_turn_on(dev); - b43_write16(dev, 0x03E6, 0x0000); + /* Turn the Analog on and initialize the PHY. */ + phy->ops->switch_analog(dev, 1); err = b43_phy_init(dev); if (err) - goto err_radio_off; + goto err_gpio_clean; - /* Select initial Interference Mitigation. */ - tmp = phy->interfmode; - phy->interfmode = B43_INTERFMODE_NONE; - b43_radio_set_interference_mitigation(dev, tmp); + /* Disable Interference Mitigation. */ + if (phy->ops->interf_mitigation) + phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE); - b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT); + /* Select the antennae */ + if (phy->ops->set_rx_antenna) + phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT); b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT); if (phy->type == B43_PHYTYPE_B) { @@ -2790,8 +2783,6 @@ static int b43_chip_init(struct b43_wldev *dev) out: return err; -err_radio_off: - b43_radio_turn_off(dev, 1); err_gpio_clean: b43_gpio_cleanup(dev); return err; @@ -2799,25 +2790,13 @@ err_gpio_clean: static void b43_periodic_every60sec(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + const struct b43_phy_operations *ops = dev->phy.ops; - if (phy->type != B43_PHYTYPE_G) - return; - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { - b43_mac_suspend(dev); - b43_calc_nrssi_slope(dev); - if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { - u8 old_chan = phy->channel; - - /* VCO Calibration */ - if (old_chan >= 8) - b43_radio_selectchannel(dev, 1, 0); - else - b43_radio_selectchannel(dev, 13, 0); - b43_radio_selectchannel(dev, old_chan, 0); - } - b43_mac_enable(dev); - } + if (ops->pwork_60sec) + ops->pwork_60sec(dev); + + /* Force check the TX power emission now. */ + b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME); } static void b43_periodic_every30sec(struct b43_wldev *dev) @@ -2845,32 +2824,8 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) } } - if (phy->type == B43_PHYTYPE_G) { - //TODO: update_aci_moving_average - if (phy->aci_enable && phy->aci_wlan_automatic) { - b43_mac_suspend(dev); - if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) { - if (0 /*TODO: bunch of conditions */ ) { - b43_radio_set_interference_mitigation - (dev, B43_INTERFMODE_MANUALWLAN); - } - } else if (1 /*TODO*/) { - /* - if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) { - b43_radio_set_interference_mitigation(dev, - B43_INTERFMODE_NONE); - } - */ - } - b43_mac_enable(dev); - } else if (phy->interfmode == B43_INTERFMODE_NONWLAN && - phy->rev == 1) { - //TODO: implement rev1 workaround - } - } - b43_phy_xmitpower(dev); //FIXME: unless scanning? - b43_lo_g_maintanance_work(dev); - //TODO for APHY (temperature?) + if (phy->ops->pwork_15sec) + phy->ops->pwork_15sec(dev); atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); wmb(); @@ -3104,36 +3059,31 @@ static void b43_qos_params_upload(struct b43_wldev *dev, } } -/* Update the QOS parameters in hardware. */ -static void b43_qos_update(struct b43_wldev *dev) +/* Mapping of mac80211 queue numbers to b43 QoS SHM offsets. */ +static const u16 b43_qos_shm_offsets[] = { + /* [mac80211-queue-nr] = SHM_OFFSET, */ + [0] = B43_QOS_VOICE, + [1] = B43_QOS_VIDEO, + [2] = B43_QOS_BESTEFFORT, + [3] = B43_QOS_BACKGROUND, +}; + +/* Update all QOS parameters in hardware. */ +static void b43_qos_upload_all(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; struct b43_qos_params *params; - unsigned long flags; unsigned int i; - /* Mapping of mac80211 queues to b43 SHM offsets. */ - static const u16 qos_shm_offsets[] = { - [0] = B43_QOS_VOICE, - [1] = B43_QOS_VIDEO, - [2] = B43_QOS_BESTEFFORT, - [3] = B43_QOS_BACKGROUND, - }; - BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); + BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != + ARRAY_SIZE(wl->qos_params)); b43_mac_suspend(dev); - spin_lock_irqsave(&wl->irq_lock, flags); - for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { params = &(wl->qos_params[i]); - if (params->need_hw_update) { - b43_qos_params_upload(dev, &(params->p), - qos_shm_offsets[i]); - params->need_hw_update = 0; - } + b43_qos_params_upload(dev, &(params->p), + b43_qos_shm_offsets[i]); } - - spin_unlock_irqrestore(&wl->irq_lock, flags); b43_mac_enable(dev); } @@ -3142,25 +3092,50 @@ static void b43_qos_clear(struct b43_wl *wl) struct b43_qos_params *params; unsigned int i; + /* Initialize QoS parameters to sane defaults. */ + + BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != + ARRAY_SIZE(wl->qos_params)); + for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { params = &(wl->qos_params[i]); - memset(&(params->p), 0, sizeof(params->p)); - params->p.aifs = -1; - params->need_hw_update = 1; + switch (b43_qos_shm_offsets[i]) { + case B43_QOS_VOICE: + params->p.txop = 0; + params->p.aifs = 2; + params->p.cw_min = 0x0001; + params->p.cw_max = 0x0001; + break; + case B43_QOS_VIDEO: + params->p.txop = 0; + params->p.aifs = 2; + params->p.cw_min = 0x0001; + params->p.cw_max = 0x0001; + break; + case B43_QOS_BESTEFFORT: + params->p.txop = 0; + params->p.aifs = 3; + params->p.cw_min = 0x0001; + params->p.cw_max = 0x03FF; + break; + case B43_QOS_BACKGROUND: + params->p.txop = 0; + params->p.aifs = 7; + params->p.cw_min = 0x0001; + params->p.cw_max = 0x03FF; + break; + default: + B43_WARN_ON(1); + } } } /* Initialize the core's QOS capabilities */ static void b43_qos_init(struct b43_wldev *dev) { - struct b43_wl *wl = dev->wl; - unsigned int i; - /* Upload the current QOS parameters. */ - for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) - wl->qos_params[i].need_hw_update = 1; - b43_qos_update(dev); + b43_qos_upload_all(dev); /* Enable QOS support. */ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); @@ -3169,25 +3144,13 @@ static void b43_qos_init(struct b43_wldev *dev) | B43_MMIO_IFSCTL_USE_EDCF); } -static void b43_qos_update_work(struct work_struct *work) -{ - struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work); - struct b43_wldev *dev; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) - b43_qos_update(dev); - mutex_unlock(&wl->mutex); -} - static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, const struct ieee80211_tx_queue_params *params) { struct b43_wl *wl = hw_to_b43_wl(hw); - unsigned long flags; + struct b43_wldev *dev; unsigned int queue = (unsigned int)_queue; - struct b43_qos_params *p; + int err = -ENODEV; if (queue >= ARRAY_SIZE(wl->qos_params)) { /* Queue not available or don't support setting @@ -3195,16 +3158,25 @@ static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, * confuse mac80211. */ return 0; } + BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != + ARRAY_SIZE(wl->qos_params)); - spin_lock_irqsave(&wl->irq_lock, flags); - p = &(wl->qos_params[queue]); - memcpy(&(p->p), params, sizeof(p->p)); - p->need_hw_update = 1; - spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) + goto out_unlock; - queue_work(hw->workqueue, &wl->qos_update_work); + memcpy(&(wl->qos_params[queue].p), params, sizeof(*params)); + b43_mac_suspend(dev); + b43_qos_params_upload(dev, &(wl->qos_params[queue].p), + b43_qos_shm_offsets[queue]); + b43_mac_enable(dev); + err = 0; - return 0; +out_unlock: + mutex_unlock(&wl->mutex); + + return err; } static int b43_op_get_tx_stats(struct ieee80211_hw *hw, @@ -3401,7 +3373,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ if (conf->channel->hw_value != phy->channel) - b43_radio_selectchannel(dev, conf->channel->hw_value, 0); + b43_switch_channel(dev, conf->channel->hw_value); /* Enable/Disable ShortSlot timing. */ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != @@ -3417,26 +3389,30 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) /* Adjust the desired TX power level. */ if (conf->power_level != 0) { - if (conf->power_level != phy->power_level) { - phy->power_level = conf->power_level; - b43_phy_xmitpower(dev); + spin_lock_irqsave(&wl->irq_lock, flags); + if (conf->power_level != phy->desired_txpower) { + phy->desired_txpower = conf->power_level; + b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | + B43_TXPWR_IGNORE_TSSI); } + spin_unlock_irqrestore(&wl->irq_lock, flags); } /* Antennas for RX and management frame TX. */ antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx); b43_mgmtframe_txantenna(dev, antenna); antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); - b43_set_rx_antenna(dev, antenna); + if (phy->ops->set_rx_antenna) + phy->ops->set_rx_antenna(dev, antenna); /* Update templates for AP/mesh mode. */ - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || - b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) + if (b43_is_mode(wl, NL80211_IFTYPE_AP) || + b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) b43_set_beacon_int(dev, conf->beacon_int); if (!!conf->radio_enabled != phy->radio_on) { if (conf->radio_enabled) { - b43_radio_turn_on(dev); + b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); b43info(dev->wl, "Radio turned on by software\n"); if (!dev->radio_hw_enable) { b43info(dev->wl, "The hardware RF-kill button " @@ -3444,7 +3420,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) "Press the button to turn it on.\n"); } } else { - b43_radio_turn_off(dev, 0); + b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); b43info(dev->wl, "Radio turned off by software\n"); } } @@ -3619,14 +3595,14 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, else memset(wl->bssid, 0, ETH_ALEN); if (b43_status(dev) >= B43_STAT_INITIALIZED) { - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || - b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) { + if (b43_is_mode(wl, NL80211_IFTYPE_AP) || + b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) { B43_WARN_ON(vif->type != wl->if_type); if (conf->changed & IEEE80211_IFCC_SSID) b43_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->changed & IEEE80211_IFCC_BEACON) b43_update_templates(wl); - } else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) { + } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { if (conf->changed & IEEE80211_IFCC_BEACON) b43_update_templates(wl); } @@ -3818,48 +3794,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) static void setup_struct_phy_for_init(struct b43_wldev *dev, struct b43_phy *phy) { - struct b43_txpower_lo_control *lo; - int i; - - memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); - memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); - - phy->aci_enable = 0; - phy->aci_wlan_automatic = 0; - phy->aci_hw_rssi = 0; - - phy->radio_off_context.valid = 0; - - lo = phy->lo_control; - if (lo) { - memset(lo, 0, sizeof(*(phy->lo_control))); - lo->tx_bias = 0xFF; - INIT_LIST_HEAD(&lo->calib_list); - } - phy->max_lb_gain = 0; - phy->trsw_rx_gain = 0; - phy->txpwr_offset = 0; - - /* NRSSI */ - phy->nrssislope = 0; - for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++) - phy->nrssi[i] = -1000; - for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++) - phy->nrssi_lt[i] = i; - - phy->lofcal = 0xFFFF; - phy->initval = 0xFFFF; - - phy->interfmode = B43_INTERFMODE_NONE; - phy->channel = 0xFF; - phy->hardware_power_control = !!modparam_hwpctl; - + phy->next_txpwr_check_time = jiffies; /* PHY TX errors counter. */ atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); - - /* OFDM-table address caching. */ - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; } static void setup_struct_wldev_for_init(struct b43_wldev *dev) @@ -3965,7 +3903,7 @@ static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) pu_delay = 3700; else pu_delay = 1050; - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle) + if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle) pu_delay = 500; if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8)) pu_delay = max(pu_delay, (u16)2400); @@ -3979,7 +3917,7 @@ static void b43_set_pretbtt(struct b43_wldev *dev) u16 pretbtt; /* The time value is in microseconds. */ - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) { + if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) { pretbtt = 2; } else { if (dev->phy.type == B43_PHYTYPE_A) @@ -3995,7 +3933,6 @@ static void b43_set_pretbtt(struct b43_wldev *dev) /* Locking: wl->mutex */ static void b43_wireless_core_exit(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; u32 macctl; B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); @@ -4016,12 +3953,7 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) b43_dma_free(dev); b43_pio_free(dev); b43_chip_exit(dev); - b43_radio_turn_off(dev, 1); - b43_switch_analog(dev, 0); - if (phy->dyn_tssi_tbl) - kfree(phy->tssi2dbm); - kfree(phy->lo_control); - phy->lo_control = NULL; + dev->phy.ops->switch_analog(dev, 0); if (dev->wl->current_beacon) { dev_kfree_skb_any(dev->wl->current_beacon); dev->wl->current_beacon = NULL; @@ -4052,29 +3984,23 @@ static int b43_wireless_core_init(struct b43_wldev *dev) b43_wireless_core_reset(dev, tmp); } - if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) { - phy->lo_control = - kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL); - if (!phy->lo_control) { - err = -ENOMEM; - goto err_busdown; - } - } + /* Reset all data structures. */ setup_struct_wldev_for_init(dev); - - err = b43_phy_init_tssi2dbm_table(dev); - if (err) - goto err_kfree_lo_control; + phy->ops->prepare_structs(dev); /* Enable IRQ routing to this device. */ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); b43_imcfglo_timeouts_workaround(dev); b43_bluetooth_coext_disable(dev); - b43_phy_early_init(dev); + if (phy->ops->prepare_hardware) { + err = phy->ops->prepare_hardware(dev); + if (err) + goto err_busdown; + } err = b43_chip_init(dev); if (err) - goto err_kfree_tssitbl; + goto err_busdown; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_WLCOREREV, dev->dev->id.revision); hf = b43_hf_read(dev); @@ -4140,15 +4066,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev) out: return err; - err_chip_exit: +err_chip_exit: b43_chip_exit(dev); - err_kfree_tssitbl: - if (phy->dyn_tssi_tbl) - kfree(phy->tssi2dbm); - err_kfree_lo_control: - kfree(phy->lo_control); - phy->lo_control = NULL; - err_busdown: +err_busdown: ssb_bus_may_powerdown(bus); B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); return err; @@ -4164,11 +4084,11 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ - if (conf->type != IEEE80211_IF_TYPE_AP && - conf->type != IEEE80211_IF_TYPE_MESH_POINT && - conf->type != IEEE80211_IF_TYPE_STA && - conf->type != IEEE80211_IF_TYPE_WDS && - conf->type != IEEE80211_IF_TYPE_IBSS) + if (conf->type != NL80211_IFTYPE_AP && + conf->type != NL80211_IFTYPE_MESH_POINT && + conf->type != NL80211_IFTYPE_STATION && + conf->type != NL80211_IFTYPE_WDS && + conf->type != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; mutex_lock(&wl->mutex); @@ -4283,7 +4203,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) struct b43_wldev *dev = wl->current_dev; b43_rfkill_exit(dev); - cancel_work_sync(&(wl->qos_update_work)); cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); @@ -4291,6 +4210,8 @@ static void b43_op_stop(struct ieee80211_hw *hw) b43_wireless_core_stop(dev); b43_wireless_core_exit(dev); mutex_unlock(&wl->mutex); + + cancel_work_sync(&(wl->txpower_adjust_work)); } static int b43_op_set_retry_limit(struct ieee80211_hw *hw, @@ -4313,7 +4234,8 @@ out_unlock: return err; } -static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) +static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, bool set) { struct b43_wl *wl = hw_to_b43_wl(hw); unsigned long flags; @@ -4328,7 +4250,7 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) static void b43_op_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd notify_cmd, - const u8 *addr) + struct ieee80211_sta *sta) { struct b43_wl *wl = hw_to_b43_wl(hw); @@ -4422,6 +4344,7 @@ static void b43_wireless_core_detach(struct b43_wldev *dev) /* We release firmware that late to not be required to re-request * is all the time when we reinit the core. */ b43_release_firmware(dev); + b43_phy_free(dev); } static int b43_wireless_core_attach(struct b43_wldev *dev) @@ -4495,30 +4418,35 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) } } + err = b43_phy_allocate(dev); + if (err) + goto err_powerdown; + dev->phy.gmode = have_2ghz_phy; tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; b43_wireless_core_reset(dev, tmp); err = b43_validate_chipaccess(dev); if (err) - goto err_powerdown; + goto err_phy_free; err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy); if (err) - goto err_powerdown; + goto err_phy_free; /* Now set some default "current_dev" */ if (!wl->current_dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43_chip_reset); - b43_radio_turn_off(dev, 1); - b43_switch_analog(dev, 0); + dev->phy.ops->switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); out: return err; +err_phy_free: + b43_phy_free(dev); err_powerdown: ssb_bus_may_powerdown(bus); return err; @@ -4615,9 +4543,11 @@ static void b43_sprom_fixup(struct ssb_bus *bus) pdev = bus->host_pci; if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) || IS_PDEV(pdev, BROADCOM, 0x4320, DELL, 0x0003) || + IS_PDEV(pdev, BROADCOM, 0x4320, HP, 0x12f8) || IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) || IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) || - IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013)) + IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013) || + IS_PDEV(pdev, BROADCOM, 0x4320, MOTOROLA, 0x7010)) bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST; } } @@ -4650,7 +4580,15 @@ static int b43_wireless_init(struct ssb_device *dev) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_WDS) | + BIT(NL80211_IFTYPE_ADHOC); + hw->queues = b43_modparam_qos ? 4 : 1; + hw->max_altrates = 1; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); @@ -4667,8 +4605,8 @@ static int b43_wireless_init(struct ssb_device *dev) spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); INIT_LIST_HEAD(&wl->devlist); - INIT_WORK(&wl->qos_update_work, b43_qos_update_work); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); + INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); ssb_set_devtypedata(dev, wl); b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index b8aa16307f7..3cfc30307a2 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -82,13 +82,13 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) tuple.TupleOffset = 0; res = pcmcia_get_first_tuple(dev, &tuple); - if (res != CS_SUCCESS) + if (res != 0) goto err_kfree_ssb; res = pcmcia_get_tuple_data(dev, &tuple); - if (res != CS_SUCCESS) + if (res != 0) goto err_kfree_ssb; - res = pcmcia_parse_tuple(dev, &tuple, &parse); - if (res != CS_SUCCESS) + res = pcmcia_parse_tuple(&tuple, &parse); + if (res != 0) goto err_kfree_ssb; dev->conf.ConfigBase = parse.config.base; @@ -107,13 +107,13 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) win.Size = SSB_CORE_SIZE; win.AccessSpeed = 250; res = pcmcia_request_window(&dev, &win, &dev->win); - if (res != CS_SUCCESS) + if (res != 0) goto err_kfree_ssb; mem.CardOffset = 0; mem.Page = 0; res = pcmcia_map_mem_page(dev->win, &mem); - if (res != CS_SUCCESS) + if (res != 0) goto err_disable; dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; @@ -121,11 +121,11 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) dev->irq.Handler = NULL; /* The handler is registered later. */ dev->irq.Instance = NULL; res = pcmcia_request_irq(dev, &dev->irq); - if (res != CS_SUCCESS) + if (res != 0) goto err_disable; res = pcmcia_request_configuration(dev, &dev->conf); - if (res != CS_SUCCESS) + if (res != 0) goto err_disable; err = ssb_bus_pcmciabus_register(ssb, dev, win.Base); diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h deleted file mode 100644 index 4aab1090352..00000000000 --- a/drivers/net/wireless/b43/phy.h +++ /dev/null @@ -1,340 +0,0 @@ -#ifndef B43_PHY_H_ -#define B43_PHY_H_ - -#include <linux/types.h> - -struct b43_wldev; -struct b43_phy; - -/*** PHY Registers ***/ - -/* Routing */ -#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ -#define B43_PHYROUTE_BASE 0x0000 /* Base registers */ -#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */ -#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */ -#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */ - -/* CCK (B-PHY) registers. */ -#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE) -/* N-PHY registers. */ -#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE) -/* N-PHY BMODE registers. */ -#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE) -/* OFDM (A-PHY) registers. */ -#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) -/* Extended G-PHY registers. */ -#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) - -/* OFDM (A) PHY Registers */ -#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */ -#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */ -#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ -#define B43_PHY_BBANDCFG_RXANT_SHIFT 7 -#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ -#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */ -#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ -#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */ -#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ -#define B43_PHY_CRS0 B43_PHY_OFDM(0x29) -#define B43_PHY_CRS0_EN 0x4000 -#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30) -#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ -#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ -#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ -#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */ -#define B43_PHY_LMS B43_PHY_OFDM(0x55) -#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ -#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ -#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ -#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */ -#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ -#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ -#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ -#define B43_PHY_OTABLENR_SHIFT 10 -#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ -#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ -#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ -#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */ -#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B) -#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */ -#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ -#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ -#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ -#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */ -#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */ -#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0) -#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1) -#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) -#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) -#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) -#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */ -#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */ -#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ -#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) -#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) -#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) -#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ -#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ -#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */ -#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */ -#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ -#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ -#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ - -/* CCK (B) PHY Registers */ -#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */ -#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */ -#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */ -#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ -#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ -#define B43_PHY_PGACTL_UNKNOWN 0xEFA0 -#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */ -#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */ -#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */ -#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */ -#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35) -#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */ -#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */ -#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */ - -/* Extended G-PHY Registers */ -#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ -#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */ -#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ -#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ -#define B43_PHY_GTABNR_SHIFT 10 -#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */ -#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */ -#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */ -#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */ -#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */ -#define B43_PHY_RFOVERVAL_EXTLNA 0x8000 -#define B43_PHY_RFOVERVAL_LNA 0x7000 -#define B43_PHY_RFOVERVAL_LNA_SHIFT 12 -#define B43_PHY_RFOVERVAL_PGA 0x0F00 -#define B43_PHY_RFOVERVAL_PGA_SHIFT 8 -#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */ -#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0 -#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */ -#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */ -#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */ -#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */ -#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */ - -/*** OFDM table numbers ***/ -#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset)) -#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0) -#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0) -#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename -#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4) -#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0) -#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3) -#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0) -#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0) -#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0) -#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0) -#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0) -#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0) -#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0) -#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0) -#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) -#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) -#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) -#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename -#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename -#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) -#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) -#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename -#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) -#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove! -#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0) -#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) -#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) -#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) -#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0) -#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0) -#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0) - -u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset); -void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, - u16 offset, u16 value); -u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset); -void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, - u16 offset, u32 value); - -/*** G-PHY table numbers */ -#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset)) -#define B43_GTAB_NRSSI B43_GTAB(0x00, 0) -#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120) -#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298) - -u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement -void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement - -#define B43_DEFAULT_CHANNEL_A 36 -#define B43_DEFAULT_CHANNEL_BG 6 - -enum { - B43_ANTENNA0, /* Antenna 0 */ - B43_ANTENNA1, /* Antenna 0 */ - B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ - B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ - B43_ANTENNA2, - B43_ANTENNA3 = 8, - - B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, - B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, -}; - -enum { - B43_INTERFMODE_NONE, - B43_INTERFMODE_NONWLAN, - B43_INTERFMODE_MANUALWLAN, - B43_INTERFMODE_AUTOWLAN, -}; - -/* Masks for the different PHY versioning registers. */ -#define B43_PHYVER_ANALOG 0xF000 -#define B43_PHYVER_ANALOG_SHIFT 12 -#define B43_PHYVER_TYPE 0x0F00 -#define B43_PHYVER_TYPE_SHIFT 8 -#define B43_PHYVER_VERSION 0x00FF - -void b43_phy_lock(struct b43_wldev *dev); -void b43_phy_unlock(struct b43_wldev *dev); - - -/* Read a value from a PHY register */ -u16 b43_phy_read(struct b43_wldev *dev, u16 offset); -/* Write a value to a PHY register */ -void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val); -/* Mask a PHY register with a mask */ -void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask); -/* OR a PHY register with a bitmap */ -void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set); -/* Mask and OR a PHY register with a mask and bitmap */ -void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); - - -int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev); - -void b43_phy_early_init(struct b43_wldev *dev); -int b43_phy_init(struct b43_wldev *dev); - -void b43_set_rx_antenna(struct b43_wldev *dev, int antenna); - -void b43_phy_xmitpower(struct b43_wldev *dev); - -/* Returns the boolean whether the board has HardwarePowerControl */ -bool b43_has_hardware_pctl(struct b43_phy *phy); -/* Returns the boolean whether "TX Magnification" is enabled. */ -#define has_tx_magnification(phy) \ - (((phy)->rev >= 2) && \ - ((phy)->radio_ver == 0x2050) && \ - ((phy)->radio_rev == 8)) -/* Card uses the loopback gain stuff */ -#define has_loopback_gain(phy) \ - (((phy)->rev > 1) || ((phy)->gmode)) - -/* Radio Attenuation (RF Attenuation) */ -struct b43_rfatt { - u8 att; /* Attenuation value */ - bool with_padmix; /* Flag, PAD Mixer enabled. */ -}; -struct b43_rfatt_list { - /* Attenuation values list */ - const struct b43_rfatt *list; - u8 len; - /* Minimum/Maximum attenuation values */ - u8 min_val; - u8 max_val; -}; - -/* Returns true, if the values are the same. */ -static inline bool b43_compare_rfatt(const struct b43_rfatt *a, - const struct b43_rfatt *b) -{ - return ((a->att == b->att) && - (a->with_padmix == b->with_padmix)); -} - -/* Baseband Attenuation */ -struct b43_bbatt { - u8 att; /* Attenuation value */ -}; -struct b43_bbatt_list { - /* Attenuation values list */ - const struct b43_bbatt *list; - u8 len; - /* Minimum/Maximum attenuation values */ - u8 min_val; - u8 max_val; -}; - -/* Returns true, if the values are the same. */ -static inline bool b43_compare_bbatt(const struct b43_bbatt *a, - const struct b43_bbatt *b) -{ - return (a->att == b->att); -} - -/* tx_control bits. */ -#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ -#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ -#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */ - -/* Write BasebandAttenuation value to the device. */ -void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, - u16 baseband_attenuation); - -extern const u8 b43_radio_channel_codes_bg[]; - -void b43_radio_lock(struct b43_wldev *dev); -void b43_radio_unlock(struct b43_wldev *dev); - - -/* Read a value from a 16bit radio register */ -u16 b43_radio_read16(struct b43_wldev *dev, u16 offset); -/* Write a value to a 16bit radio register */ -void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val); -/* Mask a 16bit radio register with a mask */ -void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask); -/* OR a 16bit radio register with a bitmap */ -void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set); -/* Mask and OR a PHY register with a mask and bitmap */ -void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); - - -u16 b43_radio_init2050(struct b43_wldev *dev); -void b43_radio_init2060(struct b43_wldev *dev); - -void b43_radio_turn_on(struct b43_wldev *dev); -void b43_radio_turn_off(struct b43_wldev *dev, bool force); - -int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel, - int synthetic_pu_workaround); - -u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel); -u8 b43_radio_aci_scan(struct b43_wldev *dev); - -int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode); - -void b43_calc_nrssi_slope(struct b43_wldev *dev); -void b43_calc_nrssi_threshold(struct b43_wldev *dev); -s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset); -void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val); -void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val); -void b43_nrssi_mem_update(struct b43_wldev *dev); - -void b43_radio_set_tx_iq(struct b43_wldev *dev); -u16 b43_radio_calibrationvalue(struct b43_wldev *dev); - -void b43_put_attenuation_into_ranges(struct b43_wldev *dev, - int *_bbatt, int *_rfatt); - -void b43_set_txpower_g(struct b43_wldev *dev, - const struct b43_bbatt *bbatt, - const struct b43_rfatt *rfatt, u8 tx_control); - -#endif /* B43_PHY_H_ */ diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c new file mode 100644 index 00000000000..0f1a84c9de6 --- /dev/null +++ b/drivers/net/wireless/b43/phy_a.c @@ -0,0 +1,643 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11a PHY driver + + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, + Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> + Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de> + Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> + Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> + + 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, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "phy_a.h" +#include "phy_common.h" +#include "wa.h" +#include "tables.h" +#include "main.h" + + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_a(u8 channel) +{ + B43_WARN_ON(channel > 200); + + return (5000 + 5 * channel); +} + +static inline u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +#if 0 +/* This function converts a TSSI value to dBm in Q5.2 */ +static s8 b43_aphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_a *aphy = phy->a; + s8 dbm = 0; + s32 tmp; + + tmp = (aphy->tgt_idle_tssi - aphy->cur_idle_tssi + tssi); + tmp += 0x80; + tmp = clamp_val(tmp, 0x00, 0xFF); + dbm = aphy->tssi2dbm[tmp]; + //TODO: There's a FIXME on the specs + + return dbm; +} +#endif + +void b43_radio_set_tx_iq(struct b43_wldev *dev) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = b43_radio_read16(dev, 0x001E); + int i, j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] << 4 | data_low[j])) { + b43_phy_write(dev, 0x0069, + (i - j) << 8 | 0x00C0); + return; + } + } + } +} + +static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel) +{ + u16 freq, r8, tmp; + + freq = channel2freq_a(channel); + + r8 = b43_radio_read16(dev, 0x0008); + b43_write16(dev, 0x03F0, freq); + b43_radio_write16(dev, 0x0008, r8); + + //TODO: write max channel TX power? to Radio 0x2D + tmp = b43_radio_read16(dev, 0x002E); + tmp &= 0x0080; + //TODO: OR tmp with the Power out estimation for this channel? + b43_radio_write16(dev, 0x002E, tmp); + + if (freq >= 4920 && freq <= 5500) { + /* + * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; + * = (freq * 0.025862069 + */ + r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ + } + b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) + & 0x000F) | (r8 << 4)); + b43_radio_write16(dev, 0x002A, (r8 << 4)); + b43_radio_write16(dev, 0x002B, (r8 << 4)); + b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) + & 0x00F0) | (r8 << 4)); + b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) + & 0xFF0F) | 0x00B0); + b43_radio_write16(dev, 0x0035, 0x00AA); + b43_radio_write16(dev, 0x0036, 0x0085); + b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) + & 0xFF20) | + freq_r3A_value(freq)); + b43_radio_write16(dev, 0x003D, + b43_radio_read16(dev, 0x003D) & 0x00FF); + b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) + & 0xFF7F) | 0x0080); + b43_radio_write16(dev, 0x0035, + b43_radio_read16(dev, 0x0035) & 0xFFEF); + b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) + & 0xFFEF) | 0x0010); + b43_radio_set_tx_iq(dev); + //TODO: TSSI2dbm workaround +//FIXME b43_phy_xmitpower(dev); +} + +void b43_radio_init2060(struct b43_wldev *dev) +{ + b43_radio_write16(dev, 0x0004, 0x00C0); + b43_radio_write16(dev, 0x0005, 0x0008); + b43_radio_write16(dev, 0x0009, 0x0040); + b43_radio_write16(dev, 0x0005, 0x00AA); + b43_radio_write16(dev, 0x0032, 0x008F); + b43_radio_write16(dev, 0x0006, 0x008F); + b43_radio_write16(dev, 0x0034, 0x008F); + b43_radio_write16(dev, 0x002C, 0x0007); + b43_radio_write16(dev, 0x0082, 0x0080); + b43_radio_write16(dev, 0x0080, 0x0000); + b43_radio_write16(dev, 0x003F, 0x00DA); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); + b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); + b43_phy_write(dev, 0x0063, 0xDDC6); + b43_phy_write(dev, 0x0069, 0x07BE); + b43_phy_write(dev, 0x006A, 0x0000); + + aphy_channel_switch(dev, dev->phy.ops->get_default_chan(dev)); + + msleep(1); +} + +static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) +{ + int i; + + if (dev->phy.rev < 3) { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0xFFF8); + } + else + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); + } + } else { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0x0820); + else + for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); + } +} + +static void b43_phy_ww(struct b43_wldev *dev) +{ + u16 b, curr_s, best_s = 0xFFFF; + int i; + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); + b43_phy_write(dev, B43_PHY_OFDM(0x82), + (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); + b43_radio_write16(dev, 0x0009, + b43_radio_read16(dev, 0x0009) | 0x0080); + b43_radio_write16(dev, 0x0012, + (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); + b43_wa_initgains(dev); + b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); + b = b43_phy_read(dev, B43_PHY_PWRDOWN); + b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) | 0x0004); + for (i = 0x10; i <= 0x20; i++) { + b43_radio_write16(dev, 0x0013, i); + curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; + if (!curr_s) { + best_s = 0x0000; + break; + } else if (curr_s >= 0x0080) + curr_s = 0x0100 - curr_s; + if (curr_s < best_s) + best_s = curr_s; + } + b43_phy_write(dev, B43_PHY_PWRDOWN, b); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) & 0xFFFB); + b43_radio_write16(dev, 0x0013, best_s); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); + b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); + b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); + b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); + b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); + b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); + b43_phy_write(dev, B43_PHY_OFDM(0xBB), + (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); + b43_phy_write(dev, B43_PHY_OFDM61, + (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120); + b43_phy_write(dev, B43_PHY_OFDM(0x13), + (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); + b43_phy_write(dev, B43_PHY_OFDM(0x14), + (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); + for (i = 0; i < 6; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); + b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); +} + +static void hardware_pctl_init_aphy(struct b43_wldev *dev) +{ + //TODO +} + +void b43_phy_inita(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + /* This lowlevel A-PHY init is also called from G-PHY init. + * So we must not access phy->a, if called from G-PHY code. + */ + B43_WARN_ON((phy->type != B43_PHYTYPE_A) && + (phy->type != B43_PHYTYPE_G)); + + might_sleep(); + + if (phy->rev >= 6) { + if (phy->type == B43_PHYTYPE_A) + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); + if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); + else + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); + } + + b43_wa_all(dev); + + if (phy->type == B43_PHYTYPE_A) { + if (phy->gmode && (phy->rev < 3)) + b43_phy_write(dev, 0x0034, + b43_phy_read(dev, 0x0034) | 0x0001); + b43_phy_rssiagc(dev, 0); + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); + + b43_radio_init2060(dev); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + ((bus->boardinfo.type == SSB_BOARD_BU4306) || + (bus->boardinfo.type == SSB_BOARD_BU4309))) { + ; //TODO: A PHY LO + } + + if (phy->rev >= 3) + b43_phy_ww(dev); + + hardware_pctl_init_aphy(dev); + + //TODO: radar detection + } + + if ((phy->type == B43_PHYTYPE_G) && + (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { + b43_phy_write(dev, B43_PHY_OFDM(0x6E), + (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) + & 0xE000) | 0x3CF); + } +} + +/* Initialise the TSSI->dBm lookup table */ +static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_a *aphy = phy->a; + s16 pab0, pab1, pab2; + + pab0 = (s16) (dev->dev->bus->sprom.pa1b0); + pab1 = (s16) (dev->dev->bus->sprom.pa1b1); + pab2 = (s16) (dev->dev->bus->sprom.pa1b2); + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if ((s8) dev->dev->bus->sprom.itssi_a != 0 && + (s8) dev->dev->bus->sprom.itssi_a != -1) + aphy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.itssi_a); + else + aphy->tgt_idle_tssi = 62; + aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0, + pab1, pab2); + if (!aphy->tssi2dbm) + return -ENOMEM; + } else { + /* pabX values not set in SPROM, + * but APHY needs a generated table. */ + aphy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate tssi2dBm " + "table (wrong SPROM info)!\n"); + return -ENODEV; + } + + return 0; +} + +static int b43_aphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_a *aphy; + int err; + + aphy = kzalloc(sizeof(*aphy), GFP_KERNEL); + if (!aphy) + return -ENOMEM; + dev->phy.a = aphy; + + err = b43_aphy_init_tssi2dbm_table(dev); + if (err) + goto err_free_aphy; + + return 0; + +err_free_aphy: + kfree(aphy); + dev->phy.a = NULL; + + return err; +} + +static void b43_aphy_op_prepare_structs(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_a *aphy = phy->a; + const void *tssi2dbm; + int tgt_idle_tssi; + + /* tssi2dbm table is constant, so it is initialized at alloc time. + * Save a copy of the pointer. */ + tssi2dbm = aphy->tssi2dbm; + tgt_idle_tssi = aphy->tgt_idle_tssi; + + /* Zero out the whole PHY structure. */ + memset(aphy, 0, sizeof(*aphy)); + + aphy->tssi2dbm = tssi2dbm; + aphy->tgt_idle_tssi = tgt_idle_tssi; + + //TODO init struct b43_phy_a + +} + +static void b43_aphy_op_free(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_a *aphy = phy->a; + + kfree(aphy->tssi2dbm); + aphy->tssi2dbm = NULL; + + kfree(aphy); + dev->phy.a = NULL; +} + +static int b43_aphy_op_init(struct b43_wldev *dev) +{ + b43_phy_inita(dev); + + return 0; +} + +static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset) +{ + /* OFDM registers are base-registers for the A-PHY. */ + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { + offset &= ~B43_PHYROUTE; + offset |= B43_PHYROUTE_BASE; + } + +#if B43_DEBUG + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { + /* Ext-G registers are only available on G-PHYs */ + b43err(dev->wl, "Invalid EXT-G PHY access at " + "0x%04X on A-PHY\n", offset); + dump_stack(); + } + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { + /* N-BMODE registers are only available on N-PHYs */ + b43err(dev->wl, "Invalid N-BMODE PHY access at " + "0x%04X on A-PHY\n", offset); + dump_stack(); + } +#endif /* B43_DEBUG */ + + return offset; +} + +static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg) +{ + reg = adjust_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + reg = adjust_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_aphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* A-PHY needs 0x40 for read access */ + reg |= 0x40; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_aphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) +{ + return (dev->phy.rev >= 5); +} + +static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{ + struct b43_phy *phy = &dev->phy; + + if (state == RFKILL_STATE_UNBLOCKED) { + if (phy->radio_on) + return; + b43_radio_write16(dev, 0x0004, 0x00C0); + b43_radio_write16(dev, 0x0005, 0x0008); + b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7); + b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7); + b43_radio_init2060(dev); + } else { + b43_radio_write16(dev, 0x0004, 0x00FF); + b43_radio_write16(dev, 0x0005, 0x00FB); + b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008); + b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); + } +} + +static int b43_aphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if (new_channel > 200) + return -EINVAL; + aphy_channel_switch(dev, new_channel); + + return 0; +} + +static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev) +{ + return 36; /* Default to channel 36 */ +} + +static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) +{//TODO + struct b43_phy *phy = &dev->phy; + u64 hf; + u16 tmp; + int autodiv = 0; + + if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) + autodiv = 1; + + hf = b43_hf_read(dev); + hf &= ~B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); + + tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + + if (autodiv) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + if (antenna == B43_ANTENNA_AUTO0) + tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; + else + tmp |= B43_PHY_ANTDWELL_AUTODIV1; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } + if (phy->rev < 3) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + tmp = (tmp & 0xFF00) | 0x24; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } else { + tmp = b43_phy_read(dev, B43_PHY_OFDM61); + tmp |= 0x10; + b43_phy_write(dev, B43_PHY_OFDM61, tmp); + if (phy->analog == 3) { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, + 0x1D); + b43_phy_write(dev, B43_PHY_ADIVRELATED, + 8); + } else { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, + 0x3A); + tmp = + b43_phy_read(dev, + B43_PHY_ADIVRELATED); + tmp = (tmp & 0xFF00) | 8; + b43_phy_write(dev, B43_PHY_ADIVRELATED, + tmp); + } + } + + hf |= B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); +} + +static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev) +{//TODO +} + +static enum b43_txpwr_result b43_aphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{//TODO + return B43_TXPWR_RES_DONE; +} + +static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) +{//TODO +} + +static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev) +{//TODO +} + +const struct b43_phy_operations b43_phyops_a = { + .allocate = b43_aphy_op_allocate, + .free = b43_aphy_op_free, + .prepare_structs = b43_aphy_op_prepare_structs, + .init = b43_aphy_op_init, + .phy_read = b43_aphy_op_read, + .phy_write = b43_aphy_op_write, + .radio_read = b43_aphy_op_radio_read, + .radio_write = b43_aphy_op_radio_write, + .supports_hwpctl = b43_aphy_op_supports_hwpctl, + .software_rfkill = b43_aphy_op_software_rfkill, + .switch_analog = b43_phyop_switch_analog_generic, + .switch_channel = b43_aphy_op_switch_channel, + .get_default_chan = b43_aphy_op_get_default_chan, + .set_rx_antenna = b43_aphy_op_set_rx_antenna, + .recalc_txpower = b43_aphy_op_recalc_txpower, + .adjust_txpower = b43_aphy_op_adjust_txpower, + .pwork_15sec = b43_aphy_op_pwork_15sec, + .pwork_60sec = b43_aphy_op_pwork_60sec, +}; diff --git a/drivers/net/wireless/b43/phy_a.h b/drivers/net/wireless/b43/phy_a.h new file mode 100644 index 00000000000..5cfaab7b16e --- /dev/null +++ b/drivers/net/wireless/b43/phy_a.h @@ -0,0 +1,130 @@ +#ifndef LINUX_B43_PHY_A_H_ +#define LINUX_B43_PHY_A_H_ + +#include "phy_common.h" + + +/* OFDM (A) PHY Registers */ +#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */ +#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */ +#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ +#define B43_PHY_BBANDCFG_RXANT_SHIFT 7 +#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ +#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */ +#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ +#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */ +#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ +#define B43_PHY_CRS0 B43_PHY_OFDM(0x29) +#define B43_PHY_CRS0_EN 0x4000 +#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30) +#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ +#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ +#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ +#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */ +#define B43_PHY_LMS B43_PHY_OFDM(0x55) +#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ +#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ +#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ +#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */ +#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ +#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ +#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ +#define B43_PHY_OTABLENR_SHIFT 10 +#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ +#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ +#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ +#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */ +#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B) +#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */ +#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ +#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ +#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ +#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */ +#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */ +#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0) +#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1) +#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) +#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) +#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) +#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */ +#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */ +#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ +#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) +#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) +#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) +#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ +#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ +#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */ +#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */ +#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ +#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ +#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ + +/*** OFDM table numbers ***/ +#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset)) +#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename +#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4) +#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0) +#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3) +#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0) +#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0) +#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0) +#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0) +#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0) +#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0) +#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) +#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) +#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) +#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename +#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename +#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) +#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) +#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename +#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) +#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove! +#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0) +#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) +#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0) +#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0) +#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0) + +u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, + u16 offset, u16 value); +u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, + u16 offset, u32 value); + + +struct b43_phy_a { + /* Pointer to the table used to convert a + * TSSI value to dBm-Q5.2 */ + const s8 *tssi2dbm; + /* Target idle TSSI */ + int tgt_idle_tssi; + /* Current idle TSSI */ + int cur_idle_tssi;//FIXME value currently not set + + /* A-PHY TX Power control value. */ + u16 txpwr_offset; + + //TODO lots of missing stuff +}; + +/** + * b43_phy_inita - Lowlevel A-PHY init routine. + * This is _only_ used by the G-PHY code. + */ +void b43_phy_inita(struct b43_wldev *dev); + + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_a; + +#endif /* LINUX_B43_PHY_A_H_ */ diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c new file mode 100644 index 00000000000..af37abccccb --- /dev/null +++ b/drivers/net/wireless/b43/phy_common.c @@ -0,0 +1,381 @@ +/* + + Broadcom B43 wireless driver + Common PHY routines + + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, + Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> + Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de> + Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> + Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> + + 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, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "phy_common.h" +#include "phy_g.h" +#include "phy_a.h" +#include "phy_n.h" +#include "phy_lp.h" +#include "b43.h" +#include "main.h" + + +int b43_phy_allocate(struct b43_wldev *dev) +{ + struct b43_phy *phy = &(dev->phy); + int err; + + phy->ops = NULL; + + switch (phy->type) { + case B43_PHYTYPE_A: + phy->ops = &b43_phyops_a; + break; + case B43_PHYTYPE_G: + phy->ops = &b43_phyops_g; + break; + case B43_PHYTYPE_N: +#ifdef CONFIG_B43_NPHY + phy->ops = &b43_phyops_n; +#endif + break; + case B43_PHYTYPE_LP: +#ifdef CONFIG_B43_PHY_LP + phy->ops = &b43_phyops_lp; +#endif + break; + } + if (B43_WARN_ON(!phy->ops)) + return -ENODEV; + + err = phy->ops->allocate(dev); + if (err) + phy->ops = NULL; + + return err; +} + +void b43_phy_free(struct b43_wldev *dev) +{ + dev->phy.ops->free(dev); + dev->phy.ops = NULL; +} + +int b43_phy_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + const struct b43_phy_operations *ops = phy->ops; + int err; + + phy->channel = ops->get_default_chan(dev); + + ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); + err = ops->init(dev); + if (err) { + b43err(dev->wl, "PHY init failed\n"); + goto err_block_rf; + } + /* Make sure to switch hardware and firmware (SHM) to + * the default channel. */ + err = b43_switch_channel(dev, ops->get_default_chan(dev)); + if (err) { + b43err(dev->wl, "PHY init: Channel switch to default failed\n"); + goto err_phy_exit; + } + + return 0; + +err_phy_exit: + if (ops->exit) + ops->exit(dev); +err_block_rf: + ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + + return err; +} + +void b43_phy_exit(struct b43_wldev *dev) +{ + const struct b43_phy_operations *ops = dev->phy.ops; + + ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + if (ops->exit) + ops->exit(dev); +} + +bool b43_has_hardware_pctl(struct b43_wldev *dev) +{ + if (!dev->phy.hardware_power_control) + return 0; + if (!dev->phy.ops->supports_hwpctl) + return 0; + return dev->phy.ops->supports_hwpctl(dev); +} + +void b43_radio_lock(struct b43_wldev *dev) +{ + u32 macctl; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK); + macctl |= B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit the write and wait for the device + * to exit any radio register access. */ + b43_read32(dev, B43_MMIO_MACCTL); + udelay(10); +} + +void b43_radio_unlock(struct b43_wldev *dev) +{ + u32 macctl; + + /* Commit any write */ + b43_read16(dev, B43_MMIO_PHY_VER); + /* unlock */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK)); + macctl &= ~B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); +} + +void b43_phy_lock(struct b43_wldev *dev) +{ +#if B43_DEBUG + B43_WARN_ON(dev->phy.phy_locked); + dev->phy.phy_locked = 1; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); + + if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); +} + +void b43_phy_unlock(struct b43_wldev *dev) +{ +#if B43_DEBUG + B43_WARN_ON(!dev->phy.phy_locked); + dev->phy.phy_locked = 0; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); + + if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) + b43_power_saving_ctl_bits(dev, 0); +} + +u16 b43_radio_read(struct b43_wldev *dev, u16 reg) +{ + return dev->phy.ops->radio_read(dev, reg); +} + +void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + dev->phy.ops->radio_write(dev, reg, value); +} + +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) & mask); +} + +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) | set); +} + +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_radio_write16(dev, offset, + (b43_radio_read16(dev, offset) & mask) | set); +} + +u16 b43_phy_read(struct b43_wldev *dev, u16 reg) +{ + return dev->phy.ops->phy_read(dev, reg); +} + +void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + dev->phy.ops->phy_write(dev, reg, value); +} + +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) & mask); +} + +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) | set); +} + +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_phy_write(dev, offset, + (b43_phy_read(dev, offset) & mask) | set); +} + +int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) +{ + struct b43_phy *phy = &(dev->phy); + u16 channelcookie, savedcookie; + int err; + + if (new_channel == B43_DEFAULT_CHANNEL) + new_channel = phy->ops->get_default_chan(dev); + + /* First we set the channel radio code to prevent the + * firmware from sending ghost packets. + */ + channelcookie = new_channel; + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + channelcookie |= 0x100; + //FIXME set 40Mhz flag if required + savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); + + /* Now try to switch the PHY hardware channel. */ + err = phy->ops->switch_channel(dev, new_channel); + if (err) + goto err_restore_cookie; + + dev->phy.channel = new_channel; + /* Wait for the radio to tune to the channel and stabilize. */ + msleep(8); + + return 0; + +err_restore_cookie: + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_CHAN, savedcookie); + + return err; +} + +void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) +{ + struct b43_phy *phy = &dev->phy; + + if (state == RFKILL_STATE_HARD_BLOCKED) { + /* We cannot hardware-block the device */ + state = RFKILL_STATE_SOFT_BLOCKED; + } + + phy->ops->software_rfkill(dev, state); + phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); +} + +/** + * b43_phy_txpower_adjust_work - TX power workqueue. + * + * Workqueue for updating the TX power parameters in hardware. + */ +void b43_phy_txpower_adjust_work(struct work_struct *work) +{ + struct b43_wl *wl = container_of(work, struct b43_wl, + txpower_adjust_work); + struct b43_wldev *dev; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + + if (likely(dev && (b43_status(dev) >= B43_STAT_STARTED))) + dev->phy.ops->adjust_txpower(dev); + + mutex_unlock(&wl->mutex); +} + +/* Called with wl->irq_lock locked */ +void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) +{ + struct b43_phy *phy = &dev->phy; + unsigned long now = jiffies; + enum b43_txpwr_result result; + + if (!(flags & B43_TXPWR_IGNORE_TIME)) { + /* Check if it's time for a TXpower check. */ + if (time_before(now, phy->next_txpwr_check_time)) + return; /* Not yet */ + } + /* The next check will be needed in two seconds, or later. */ + phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2)); + + if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306)) + return; /* No software txpower adjustment needed */ + + result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI)); + if (result == B43_TXPWR_RES_DONE) + return; /* We are done. */ + B43_WARN_ON(result != B43_TXPWR_RES_NEED_ADJUST); + B43_WARN_ON(phy->ops->adjust_txpower == NULL); + + /* We must adjust the transmission power in hardware. + * Schedule b43_phy_txpower_adjust_work(). */ + queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work); +} + +int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset) +{ + const bool is_ofdm = (shm_offset != B43_SHM_SH_TSSI_CCK); + unsigned int a, b, c, d; + unsigned int average; + u32 tmp; + + tmp = b43_shm_read32(dev, B43_SHM_SHARED, shm_offset); + a = tmp & 0xFF; + b = (tmp >> 8) & 0xFF; + c = (tmp >> 16) & 0xFF; + d = (tmp >> 24) & 0xFF; + if (a == 0 || a == B43_TSSI_MAX || + b == 0 || b == B43_TSSI_MAX || + c == 0 || c == B43_TSSI_MAX || + d == 0 || d == B43_TSSI_MAX) + return -ENOENT; + /* The values are OK. Clear them. */ + tmp = B43_TSSI_MAX | (B43_TSSI_MAX << 8) | + (B43_TSSI_MAX << 16) | (B43_TSSI_MAX << 24); + b43_shm_write32(dev, B43_SHM_SHARED, shm_offset, tmp); + + if (is_ofdm) { + a = (a + 32) & 0x3F; + b = (b + 32) & 0x3F; + c = (c + 32) & 0x3F; + d = (d + 32) & 0x3F; + } + + /* Get the average of the values with 0.5 added to each value. */ + average = (a + b + c + d + 2) / 4; + if (is_ofdm) { + /* Adjust for CCK-boost */ + if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO) + & B43_HF_CCKBOOST) + average = (average >= 13) ? (average - 13) : 0; + } + + return average; +} + +void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on) +{ + b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); +} diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h new file mode 100644 index 00000000000..c9f5430d1d7 --- /dev/null +++ b/drivers/net/wireless/b43/phy_common.h @@ -0,0 +1,413 @@ +#ifndef LINUX_B43_PHY_COMMON_H_ +#define LINUX_B43_PHY_COMMON_H_ + +#include <linux/rfkill.h> + +struct b43_wldev; + + +/* PHY register routing bits */ +#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ +#define B43_PHYROUTE_BASE 0x0000 /* Base registers */ +#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */ +#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */ +#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */ + +/* CCK (B-PHY) registers. */ +#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY registers. */ +#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY BMODE registers. */ +#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE) +/* OFDM (A-PHY) registers. */ +#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) +/* Extended G-PHY registers. */ +#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) + + +/* Masks for the PHY versioning registers. */ +#define B43_PHYVER_ANALOG 0xF000 +#define B43_PHYVER_ANALOG_SHIFT 12 +#define B43_PHYVER_TYPE 0x0F00 +#define B43_PHYVER_TYPE_SHIFT 8 +#define B43_PHYVER_VERSION 0x00FF + +/** + * enum b43_interference_mitigation - Interference Mitigation mode + * + * @B43_INTERFMODE_NONE: Disabled + * @B43_INTERFMODE_NONWLAN: Non-WLAN Interference Mitigation + * @B43_INTERFMODE_MANUALWLAN: WLAN Interference Mitigation + * @B43_INTERFMODE_AUTOWLAN: Automatic WLAN Interference Mitigation + */ +enum b43_interference_mitigation { + B43_INTERFMODE_NONE, + B43_INTERFMODE_NONWLAN, + B43_INTERFMODE_MANUALWLAN, + B43_INTERFMODE_AUTOWLAN, +}; + +/* Antenna identifiers */ +enum { + B43_ANTENNA0, /* Antenna 0 */ + B43_ANTENNA1, /* Antenna 0 */ + B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ + B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ + B43_ANTENNA2, + B43_ANTENNA3 = 8, + + B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, + B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, +}; + +/** + * enum b43_txpwr_result - Return value for the recalc_txpower PHY op. + * + * @B43_TXPWR_RES_NEED_ADJUST: Values changed. Hardware adjustment is needed. + * @B43_TXPWR_RES_DONE: No more work to do. Everything is done. + */ +enum b43_txpwr_result { + B43_TXPWR_RES_NEED_ADJUST, + B43_TXPWR_RES_DONE, +}; + +/** + * struct b43_phy_operations - Function pointers for PHY ops. + * + * @allocate: Allocate and initialise the PHY data structures. + * Must not be NULL. + * @free: Destroy and free the PHY data structures. + * Must not be NULL. + * + * @prepare_structs: Prepare the PHY data structures. + * The data structures allocated in @allocate are + * initialized here. + * Must not be NULL. + * @prepare_hardware: Prepare the PHY. This is called before b43_chip_init to + * do some early early PHY hardware init. + * Can be NULL, if not required. + * @init: Initialize the PHY. + * Must not be NULL. + * @exit: Shutdown the PHY. + * Can be NULL, if not required. + * + * @phy_read: Read from a PHY register. + * Must not be NULL. + * @phy_write: Write to a PHY register. + * Must not be NULL. + * @radio_read: Read from a Radio register. + * Must not be NULL. + * @radio_write: Write to a Radio register. + * Must not be NULL. + * + * @supports_hwpctl: Returns a boolean whether Hardware Power Control + * is supported or not. + * If NULL, hwpctl is assumed to be never supported. + * @software_rfkill: Turn the radio ON or OFF. + * Possible state values are + * RFKILL_STATE_SOFT_BLOCKED or + * RFKILL_STATE_UNBLOCKED + * Must not be NULL. + * @switch_analog: Turn the Analog on/off. + * Must not be NULL. + * @switch_channel: Switch the radio to another channel. + * Must not be NULL. + * @get_default_chan: Just returns the default channel number. + * Must not be NULL. + * @set_rx_antenna: Set the antenna used for RX. + * Can be NULL, if not supported. + * @interf_mitigation: Switch the Interference Mitigation mode. + * Can be NULL, if not supported. + * + * @recalc_txpower: Recalculate the transmission power parameters. + * This callback has to recalculate the TX power settings, + * but does not need to write them to the hardware, yet. + * Returns enum b43_txpwr_result to indicate whether the hardware + * needs to be adjusted. + * If B43_TXPWR_NEED_ADJUST is returned, @adjust_txpower + * will be called later. + * If the parameter "ignore_tssi" is true, the TSSI values should + * be ignored and a recalculation of the power settings should be + * done even if the TSSI values did not change. + * This callback is called with wl->irq_lock held and must not sleep. + * Must not be NULL. + * @adjust_txpower: Write the previously calculated TX power settings + * (from @recalc_txpower) to the hardware. + * This function may sleep. + * Can be NULL, if (and ONLY if) @recalc_txpower _always_ + * returns B43_TXPWR_RES_DONE. + * + * @pwork_15sec: Periodic work. Called every 15 seconds. + * Can be NULL, if not required. + * @pwork_60sec: Periodic work. Called every 60 seconds. + * Can be NULL, if not required. + */ +struct b43_phy_operations { + /* Initialisation */ + int (*allocate)(struct b43_wldev *dev); + void (*free)(struct b43_wldev *dev); + void (*prepare_structs)(struct b43_wldev *dev); + int (*prepare_hardware)(struct b43_wldev *dev); + int (*init)(struct b43_wldev *dev); + void (*exit)(struct b43_wldev *dev); + + /* Register access */ + u16 (*phy_read)(struct b43_wldev *dev, u16 reg); + void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value); + u16 (*radio_read)(struct b43_wldev *dev, u16 reg); + void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value); + + /* Radio */ + bool (*supports_hwpctl)(struct b43_wldev *dev); + void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); + void (*switch_analog)(struct b43_wldev *dev, bool on); + int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); + unsigned int (*get_default_chan)(struct b43_wldev *dev); + void (*set_rx_antenna)(struct b43_wldev *dev, int antenna); + int (*interf_mitigation)(struct b43_wldev *dev, + enum b43_interference_mitigation new_mode); + + /* Transmission power adjustment */ + enum b43_txpwr_result (*recalc_txpower)(struct b43_wldev *dev, + bool ignore_tssi); + void (*adjust_txpower)(struct b43_wldev *dev); + + /* Misc */ + void (*pwork_15sec)(struct b43_wldev *dev); + void (*pwork_60sec)(struct b43_wldev *dev); +}; + +struct b43_phy_a; +struct b43_phy_g; +struct b43_phy_n; +struct b43_phy_lp; + +struct b43_phy { + /* Hardware operation callbacks. */ + const struct b43_phy_operations *ops; + + /* Most hardware context information is stored in the standard- + * specific data structures pointed to by the pointers below. + * Only one of them is valid (the currently enabled PHY). */ +#ifdef CONFIG_B43_DEBUG + /* No union for debug build to force NULL derefs in buggy code. */ + struct { +#else + union { +#endif + /* A-PHY specific information */ + struct b43_phy_a *a; + /* G-PHY specific information */ + struct b43_phy_g *g; + /* N-PHY specific information */ + struct b43_phy_n *n; + /* LP-PHY specific information */ + struct b43_phy_lp *lp; + }; + + /* Band support flags. */ + bool supports_2ghz; + bool supports_5ghz; + + /* GMODE bit enabled? */ + bool gmode; + + /* Analog Type */ + u8 analog; + /* B43_PHYTYPE_ */ + u8 type; + /* PHY revision number. */ + u8 rev; + + /* Radio versioning */ + u16 radio_manuf; /* Radio manufacturer */ + u16 radio_ver; /* Radio version */ + u8 radio_rev; /* Radio revision */ + + /* Software state of the radio */ + bool radio_on; + + /* Desired TX power level (in dBm). + * This is set by the user and adjusted in b43_phy_xmitpower(). */ + int desired_txpower; + + /* Hardware Power Control enabled? */ + bool hardware_power_control; + + /* The time (in absolute jiffies) when the next TX power output + * check is needed. */ + unsigned long next_txpwr_check_time; + + /* current channel */ + unsigned int channel; + + /* PHY TX errors counter. */ + atomic_t txerr_cnt; + +#ifdef CONFIG_B43_DEBUG + /* PHY registers locked by b43_phy_lock()? */ + bool phy_locked; +#endif /* B43_DEBUG */ +}; + + +/** + * b43_phy_allocate - Allocate PHY structs + * Allocate the PHY data structures, based on the current dev->phy.type + */ +int b43_phy_allocate(struct b43_wldev *dev); + +/** + * b43_phy_free - Free PHY structs + */ +void b43_phy_free(struct b43_wldev *dev); + +/** + * b43_phy_init - Initialise the PHY + */ +int b43_phy_init(struct b43_wldev *dev); + +/** + * b43_phy_exit - Cleanup PHY + */ +void b43_phy_exit(struct b43_wldev *dev); + +/** + * b43_has_hardware_pctl - Hardware Power Control supported? + * Returns a boolean, whether hardware power control is supported. + */ +bool b43_has_hardware_pctl(struct b43_wldev *dev); + +/** + * b43_phy_read - 16bit PHY register read access + */ +u16 b43_phy_read(struct b43_wldev *dev, u16 reg); + +/** + * b43_phy_write - 16bit PHY register write access + */ +void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value); + +/** + * b43_phy_mask - Mask a PHY register with a mask + */ +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask); + +/** + * b43_phy_set - OR a PHY register with a bitmap + */ +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set); + +/** + * b43_phy_maskset - Mask and OR a PHY register with a mask and bitmap + */ +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + +/** + * b43_radio_read - 16bit Radio register read access + */ +u16 b43_radio_read(struct b43_wldev *dev, u16 reg); +#define b43_radio_read16 b43_radio_read /* DEPRECATED */ + +/** + * b43_radio_write - 16bit Radio register write access + */ +void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value); +#define b43_radio_write16 b43_radio_write /* DEPRECATED */ + +/** + * b43_radio_mask - Mask a 16bit radio register with a mask + */ +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask); + +/** + * b43_radio_set - OR a 16bit radio register with a bitmap + */ +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set); + +/** + * b43_radio_maskset - Mask and OR a radio register with a mask and bitmap + */ +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + +/** + * b43_radio_lock - Lock firmware radio register access + */ +void b43_radio_lock(struct b43_wldev *dev); + +/** + * b43_radio_unlock - Unlock firmware radio register access + */ +void b43_radio_unlock(struct b43_wldev *dev); + +/** + * b43_phy_lock - Lock firmware PHY register access + */ +void b43_phy_lock(struct b43_wldev *dev); + +/** + * b43_phy_unlock - Unlock firmware PHY register access + */ +void b43_phy_unlock(struct b43_wldev *dev); + +/** + * b43_switch_channel - Switch to another channel + */ +int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); +/** + * B43_DEFAULT_CHANNEL - Switch to the default channel. + */ +#define B43_DEFAULT_CHANNEL UINT_MAX + +/** + * b43_software_rfkill - Turn the radio ON or OFF in software. + */ +void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); + +/** + * b43_phy_txpower_check - Check TX power output. + * + * Compare the current TX power output to the desired power emission + * and schedule an adjustment in case it mismatches. + * Requires wl->irq_lock locked. + * + * @flags: OR'ed enum b43_phy_txpower_check_flags flags. + * See the docs below. + */ +void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags); +/** + * enum b43_phy_txpower_check_flags - Flags for b43_phy_txpower_check() + * + * @B43_TXPWR_IGNORE_TIME: Ignore the schedule time and force-redo + * the check now. + * @B43_TXPWR_IGNORE_TSSI: Redo the recalculation, even if the average + * TSSI did not change. + */ +enum b43_phy_txpower_check_flags { + B43_TXPWR_IGNORE_TIME = (1 << 0), + B43_TXPWR_IGNORE_TSSI = (1 << 1), +}; + +struct work_struct; +void b43_phy_txpower_adjust_work(struct work_struct *work); + +/** + * b43_phy_shm_tssi_read - Read the average of the last 4 TSSI from SHM. + * + * @shm_offset: The SHM address to read the values from. + * + * Returns the average of the 4 TSSI values, or a negative error code. + */ +int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset); + +/** + * b43_phy_switch_analog_generic - Generic PHY operation for switching the Analog. + * + * It does the switching based on the PHY0 core register. + * Do _not_ call this directly. Only use it as a switch_analog callback + * for struct b43_phy_operations. + */ +void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on); + + +#endif /* LINUX_B43_PHY_COMMON_H_ */ diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy_g.c index 305d4cd6fd0..232181f6333 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -1,10 +1,11 @@ /* Broadcom B43 wireless driver + IEEE 802.11g PHY driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> - Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> + Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -25,38 +26,14 @@ */ -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/types.h> -#include <linux/bitrev.h> - #include "b43.h" -#include "phy.h" -#include "nphy.h" -#include "main.h" -#include "tables.h" +#include "phy_g.h" +#include "phy_common.h" #include "lo.h" -#include "wa.h" - - -static const s8 b43_tssi2dbm_b_table[] = { - 0x4D, 0x4C, 0x4B, 0x4A, - 0x4A, 0x49, 0x48, 0x47, - 0x47, 0x46, 0x45, 0x45, - 0x44, 0x43, 0x42, 0x42, - 0x41, 0x40, 0x3F, 0x3E, - 0x3D, 0x3C, 0x3B, 0x3A, - 0x39, 0x38, 0x37, 0x36, - 0x35, 0x34, 0x32, 0x31, - 0x30, 0x2F, 0x2D, 0x2C, - 0x2B, 0x29, 0x28, 0x26, - 0x25, 0x23, 0x21, 0x1F, - 0x1D, 0x1A, 0x17, 0x14, - 0x10, 0x0C, 0x06, 0x00, - -7, -7, -7, -7, - -7, -7, -7, -7, - -7, -7, -7, -7, -}; +#include "main.h" + +#include <linux/bitrev.h> + static const s8 b43_tssi2dbm_g_table[] = { 77, 77, 77, 76, @@ -84,8 +61,20 @@ const u8 b43_radio_channel_codes_bg[] = { 72, 84, }; + +static void b43_calc_nrssi_threshold(struct b43_wldev *dev); + + #define bitrev4(tmp) (bitrev8(tmp) >> 4) -static void b43_phy_initg(struct b43_wldev *dev); + + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_bg(u8 channel) +{ + B43_WARN_ON(!(channel >= 1 && channel <= 14)); + + return b43_radio_channel_codes_bg[channel - 1]; +} static void generate_rfatt_list(struct b43_wldev *dev, struct b43_rfatt_list *list) @@ -130,7 +119,7 @@ static void generate_rfatt_list(struct b43_wldev *dev, {.att = 9,.with_padmix = 1,}, }; - if (!b43_has_hardware_pctl(phy)) { + if (!b43_has_hardware_pctl(dev)) { /* Software pctl */ list->list = rfatt_0; list->len = ARRAY_SIZE(rfatt_0); @@ -174,140 +163,55 @@ static void generate_bbatt_list(struct b43_wldev *dev, list->max_val = 8; } -bool b43_has_hardware_pctl(struct b43_phy *phy) -{ - if (!phy->hardware_power_control) - return 0; - switch (phy->type) { - case B43_PHYTYPE_A: - if (phy->rev >= 5) - return 1; - break; - case B43_PHYTYPE_G: - if (phy->rev >= 6) - return 1; - break; - default: - B43_WARN_ON(1); - } - return 0; -} - static void b43_shm_clear_tssi(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - - switch (phy->type) { - case B43_PHYTYPE_A: - b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F); - b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F); - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F); - b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F); - b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F); - b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F); - break; - } -} - -/* Lock the PHY registers against concurrent access from the microcode. - * This lock is nonrecursive. */ -void b43_phy_lock(struct b43_wldev *dev) -{ -#if B43_DEBUG - B43_WARN_ON(dev->phy.phy_locked); - dev->phy.phy_locked = 1; -#endif - B43_WARN_ON(dev->dev->id.revision < 3); - - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F); } -void b43_phy_unlock(struct b43_wldev *dev) +/* Synthetic PU workaround */ +static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel) { -#if B43_DEBUG - B43_WARN_ON(!dev->phy.phy_locked); - dev->phy.phy_locked = 0; -#endif - B43_WARN_ON(dev->dev->id.revision < 3); + struct b43_phy *phy = &dev->phy; - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, 0); -} + might_sleep(); -/* Different PHYs require different register routing flags. - * This adjusts (and does sanity checks on) the routing flags. - */ -static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy, - u16 offset, struct b43_wldev *dev) -{ - if (phy->type == B43_PHYTYPE_A) { - /* OFDM registers are base-registers for the A-PHY. */ - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { - offset &= ~B43_PHYROUTE; - offset |= B43_PHYROUTE_BASE; - } + if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) { + /* We do not need the workaround. */ + return; } -#if B43_DEBUG - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { - /* Ext-G registers are only available on G-PHYs */ - if (phy->type != B43_PHYTYPE_G) { - b43err(dev->wl, "Invalid EXT-G PHY access at " - "0x%04X on PHY type %u\n", offset, phy->type); - dump_stack(); - } - } - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { - /* N-BMODE registers are only available on N-PHYs */ - if (phy->type != B43_PHYTYPE_N) { - b43err(dev->wl, "Invalid N-BMODE PHY access at " - "0x%04X on PHY type %u\n", offset, phy->type); - dump_stack(); - } + if (channel <= 10) { + b43_write16(dev, B43_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1)); } -#endif /* B43_DEBUG */ - - return offset; -} - -u16 b43_phy_read(struct b43_wldev * dev, u16 offset) -{ - struct b43_phy *phy = &dev->phy; - - offset = adjust_phyreg_for_phytype(phy, offset, dev); - b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); - return b43_read16(dev, B43_MMIO_PHY_DATA); + msleep(1); + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); } -void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val) +/* Set the baseband attenuation value on chip. */ +void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation) { struct b43_phy *phy = &dev->phy; - offset = adjust_phyreg_for_phytype(phy, offset, dev); - b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); - b43_write16(dev, B43_MMIO_PHY_DATA, val); -} - -void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) -{ - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) & mask); -} - -void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) -{ - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) | set); -} - -void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) -{ - b43_phy_write(dev, offset, - (b43_phy_read(dev, offset) & mask) | set); + if (phy->analog == 0) { + b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0) + & 0xFFF0) | + baseband_attenuation); + } else if (phy->analog > 1) { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFFC3) | (baseband_attenuation << 2)); + } else { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFF87) | (baseband_attenuation << 3)); + } } /* Adjust the transmission power output (G-PHY) */ @@ -316,7 +220,8 @@ void b43_set_txpower_g(struct b43_wldev *dev, const struct b43_rfatt *rfatt, u8 tx_control) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; u16 bb, rf; u16 tx_bias, tx_magn; @@ -327,11 +232,12 @@ void b43_set_txpower_g(struct b43_wldev *dev, if (unlikely(tx_bias == 0xFF)) tx_bias = 0; - /* Save the values for later */ - phy->tx_control = tx_control; - memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); - phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); - memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); + /* Save the values for later. Use memmove, because it's valid + * to pass &gphy->rfatt as rfatt pointer argument. Same for bbatt. */ + gphy->tx_control = tx_control; + memmove(&gphy->rfatt, rfatt, sizeof(*rfatt)); + gphy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); + memmove(&gphy->bbatt, bbatt, sizeof(*bbatt)); if (b43_debug(dev, B43_DBG_XMITPOWER)) { b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), " @@ -340,7 +246,7 @@ void b43_set_txpower_g(struct b43_wldev *dev, bb, rf, tx_control, tx_bias, tx_magn); } - b43_phy_set_baseband_attenuation(dev, bb); + b43_gphy_set_baseband_attenuation(dev, bb); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf); if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { b43_radio_write16(dev, 0x43, @@ -358,179 +264,23 @@ void b43_set_txpower_g(struct b43_wldev *dev, b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) & 0xFFF0) | (tx_bias & 0x000F)); } - if (phy->type == B43_PHYTYPE_G) - b43_lo_g_adjust(dev); -} - -static void default_baseband_attenuation(struct b43_wldev *dev, - struct b43_bbatt *bb) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) - bb->att = 0; - else - bb->att = 2; -} - -static void default_radio_attenuation(struct b43_wldev *dev, - struct b43_rfatt *rf) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - - rf->with_padmix = 0; - - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && - bus->boardinfo.type == SSB_BOARD_BCM4309G) { - if (bus->boardinfo.rev < 0x43) { - rf->att = 2; - return; - } else if (bus->boardinfo.rev < 0x51) { - rf->att = 3; - return; - } - } - - if (phy->type == B43_PHYTYPE_A) { - rf->att = 0x60; - return; - } - - switch (phy->radio_ver) { - case 0x2053: - switch (phy->radio_rev) { - case 1: - rf->att = 6; - return; - } - break; - case 0x2050: - switch (phy->radio_rev) { - case 0: - rf->att = 5; - return; - case 1: - if (phy->type == B43_PHYTYPE_G) { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) - rf->att = 3; - else if (bus->boardinfo.vendor == - SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == - SSB_BOARD_BU4306) - rf->att = 3; - else - rf->att = 1; - } else { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) - rf->att = 7; - else - rf->att = 6; - } - return; - case 2: - if (phy->type == B43_PHYTYPE_G) { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) - rf->att = 3; - else if (bus->boardinfo.vendor == - SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == - SSB_BOARD_BU4306) - rf->att = 5; - else if (bus->chip_id == 0x4320) - rf->att = 4; - else - rf->att = 3; - } else - rf->att = 6; - return; - case 3: - rf->att = 5; - return; - case 4: - case 5: - rf->att = 1; - return; - case 6: - case 7: - rf->att = 5; - return; - case 8: - rf->att = 0xA; - rf->with_padmix = 1; - return; - case 9: - default: - rf->att = 5; - return; - } - } - rf->att = 5; -} - -static u16 default_tx_control(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->radio_ver != 0x2050) - return 0; - if (phy->radio_rev == 1) - return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX; - if (phy->radio_rev < 6) - return B43_TXCTL_PA2DB; - if (phy->radio_rev == 8) - return B43_TXCTL_TXMIX; - return 0; -} - -/* This func is called "PHY calibrate" in the specs... */ -void b43_phy_early_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - - default_baseband_attenuation(dev, &phy->bbatt); - default_radio_attenuation(dev, &phy->rfatt); - phy->tx_control = (default_tx_control(dev) << 4); - - /* Commit previous writes */ - b43_read32(dev, B43_MMIO_MACCTL); - - if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) { - generate_rfatt_list(dev, &lo->rfatt_list); - generate_bbatt_list(dev, &lo->bbatt_list); - } - if (phy->type == B43_PHYTYPE_G && phy->rev == 1) { - /* Workaround: Temporarly disable gmode through the early init - * phase, as the gmode stuff is not needed for phy rev 1 */ - phy->gmode = 0; - b43_wireless_core_reset(dev, 0); - b43_phy_initg(dev); - phy->gmode = 1; - b43_wireless_core_reset(dev, B43_TMSLOW_GMODE); - } + b43_lo_g_adjust(dev); } /* GPHY_TSSI_Power_Lookup_Table_Init */ static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; int i; u16 value; for (i = 0; i < 32; i++) - b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]); + b43_ofdmtab_write16(dev, 0x3C20, i, gphy->tssi2dbm[i]); for (i = 32; i < 64; i++) - b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]); + b43_ofdmtab_write16(dev, 0x3C00, i - 32, gphy->tssi2dbm[i]); for (i = 0; i < 64; i += 2) { - value = (u16) phy->tssi2dbm[i]; - value |= ((u16) phy->tssi2dbm[i + 1]) << 8; + value = (u16) gphy->tssi2dbm[i]; + value |= ((u16) gphy->tssi2dbm[i + 1]) << 8; b43_phy_write(dev, 0x380 + (i / 2), value); } } @@ -539,7 +289,8 @@ static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev) static void b43_gphy_gain_lt_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; u16 nr_written = 0; u16 tmp; u8 rf, bb; @@ -561,1509 +312,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev) } } -static void hardware_pctl_init_aphy(struct b43_wldev *dev) -{ - //TODO -} - -static void hardware_pctl_init_gphy(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0) - | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); - b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00) - | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); - b43_gphy_tssi_power_lt_init(dev); - b43_gphy_gain_lt_init(dev); - b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF); - b43_phy_write(dev, 0x0014, 0x0000); - - B43_WARN_ON(phy->rev < 6); - b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) - | 0x0800); - b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) - & 0xFEFF); - b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) - & 0xFFBF); - - b43_gphy_dc_lt_init(dev, 1); -} - -/* HardwarePowerControl init for A and G PHY */ -static void b43_hardware_pctl_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (!b43_has_hardware_pctl(phy)) { - /* No hardware power control */ - b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL); - return; - } - /* Init the hwpctl related hardware */ - switch (phy->type) { - case B43_PHYTYPE_A: - hardware_pctl_init_aphy(dev); - break; - case B43_PHYTYPE_G: - hardware_pctl_init_gphy(dev); - break; - default: - B43_WARN_ON(1); - } - /* Enable hardware pctl in firmware. */ - b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); -} - -static void b43_hardware_pctl_early_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (!b43_has_hardware_pctl(phy)) { - b43_phy_write(dev, 0x047A, 0xC111); - return; - } - - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF); - b43_phy_write(dev, 0x002F, 0x0202); - b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002); - b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000); - if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { - b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) - & 0xFF0F) | 0x0010); - b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) - | 0x8000); - b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) - & 0xFFC0) | 0x0010); - b43_phy_write(dev, 0x002E, 0xC07F); - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) - | 0x0400); - } else { - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) - | 0x0200); - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) - | 0x0400); - b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) - & 0x7FFF); - b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F) - & 0xFFFE); - b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) - & 0xFFC0) | 0x0010); - b43_phy_write(dev, 0x002E, 0xC07F); - b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) - & 0xFF0F) | 0x0010); - } -} - -/* Intialize B/G PHY power control - * as described in http://bcm-specs.sipsolutions.net/InitPowerControl - */ -static void b43_phy_init_pctl(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - struct b43_rfatt old_rfatt; - struct b43_bbatt old_bbatt; - u8 old_tx_control = 0; - - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306)) - return; - - b43_phy_write(dev, 0x0028, 0x8018); - - /* This does something with the Analog... */ - b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0) - & 0xFFDF); - - if (phy->type == B43_PHYTYPE_G && !phy->gmode) - return; - b43_hardware_pctl_early_init(dev); - if (phy->cur_idle_tssi == 0) { - if (phy->radio_ver == 0x2050 && phy->analog == 0) { - b43_radio_write16(dev, 0x0076, - (b43_radio_read16(dev, 0x0076) - & 0x00F7) | 0x0084); - } else { - struct b43_rfatt rfatt; - struct b43_bbatt bbatt; - - memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt)); - memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt)); - old_tx_control = phy->tx_control; - - bbatt.att = 11; - if (phy->radio_rev == 8) { - rfatt.att = 15; - rfatt.with_padmix = 1; - } else { - rfatt.att = 9; - rfatt.with_padmix = 0; - } - b43_set_txpower_g(dev, &bbatt, &rfatt, 0); - } - b43_dummy_transmission(dev); - phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); - if (B43_DEBUG) { - /* Current-Idle-TSSI sanity check. */ - if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) { - b43dbg(dev->wl, - "!WARNING! Idle-TSSI phy->cur_idle_tssi " - "measuring failed. (cur=%d, tgt=%d). Disabling TX power " - "adjustment.\n", phy->cur_idle_tssi, - phy->tgt_idle_tssi); - phy->cur_idle_tssi = 0; - } - } - if (phy->radio_ver == 0x2050 && phy->analog == 0) { - b43_radio_write16(dev, 0x0076, - b43_radio_read16(dev, 0x0076) - & 0xFF7B); - } else { - b43_set_txpower_g(dev, &old_bbatt, - &old_rfatt, old_tx_control); - } - } - b43_hardware_pctl_init(dev); - b43_shm_clear_tssi(dev); -} - -static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) -{ - int i; - - if (dev->phy.rev < 3) { - if (enable) - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { - b43_ofdmtab_write16(dev, - B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, 0xFFF8); - } - else - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { - b43_ofdmtab_write16(dev, - B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); - } - } else { - if (enable) - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, 0x0820); - else - for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); - } -} - -static void b43_phy_ww(struct b43_wldev *dev) -{ - u16 b, curr_s, best_s = 0xFFFF; - int i; - - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); - b43_phy_write(dev, B43_PHY_OFDM(0x1B), - b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); - b43_phy_write(dev, B43_PHY_OFDM(0x82), - (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); - b43_radio_write16(dev, 0x0009, - b43_radio_read16(dev, 0x0009) | 0x0080); - b43_radio_write16(dev, 0x0012, - (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); - b43_wa_initgains(dev); - b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); - b = b43_phy_read(dev, B43_PHY_PWRDOWN); - b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); - b43_radio_write16(dev, 0x0004, - b43_radio_read16(dev, 0x0004) | 0x0004); - for (i = 0x10; i <= 0x20; i++) { - b43_radio_write16(dev, 0x0013, i); - curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; - if (!curr_s) { - best_s = 0x0000; - break; - } else if (curr_s >= 0x0080) - curr_s = 0x0100 - curr_s; - if (curr_s < best_s) - best_s = curr_s; - } - b43_phy_write(dev, B43_PHY_PWRDOWN, b); - b43_radio_write16(dev, 0x0004, - b43_radio_read16(dev, 0x0004) & 0xFFFB); - b43_radio_write16(dev, 0x0013, best_s); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); - b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); - b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); - b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); - b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); - b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); - b43_phy_write(dev, B43_PHY_OFDM(0xBB), - (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); - b43_phy_write(dev, B43_PHY_OFDM61, - (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120); - b43_phy_write(dev, B43_PHY_OFDM(0x13), - (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); - b43_phy_write(dev, B43_PHY_OFDM(0x14), - (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); - for (i = 0; i < 6; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); - b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); -} - -/* Initialize APHY. This is also called for the GPHY in some cases. */ -static void b43_phy_inita(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - - might_sleep(); - - if (phy->rev >= 6) { - if (phy->type == B43_PHYTYPE_A) - b43_phy_write(dev, B43_PHY_OFDM(0x1B), - b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); - if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) - b43_phy_write(dev, B43_PHY_ENCORE, - b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); - else - b43_phy_write(dev, B43_PHY_ENCORE, - b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); - } - - b43_wa_all(dev); - - if (phy->type == B43_PHYTYPE_A) { - if (phy->gmode && (phy->rev < 3)) - b43_phy_write(dev, 0x0034, - b43_phy_read(dev, 0x0034) | 0x0001); - b43_phy_rssiagc(dev, 0); - - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); - - b43_radio_init2060(dev); - - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - ((bus->boardinfo.type == SSB_BOARD_BU4306) || - (bus->boardinfo.type == SSB_BOARD_BU4309))) { - ; //TODO: A PHY LO - } - - if (phy->rev >= 3) - b43_phy_ww(dev); - - hardware_pctl_init_aphy(dev); - - //TODO: radar detection - } - - if ((phy->type == B43_PHYTYPE_G) && - (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { - b43_phy_write(dev, B43_PHY_OFDM(0x6E), - (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) - & 0xE000) | 0x3CF); - } -} - -static void b43_phy_initb5(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - u16 offset, value; - u8 old_channel; - - if (phy->analog == 1) { - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) - | 0x0050); - } - if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type != SSB_BOARD_BU4306)) { - value = 0x2120; - for (offset = 0x00A8; offset < 0x00C7; offset++) { - b43_phy_write(dev, offset, value); - value += 0x202; - } - } - b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF) - | 0x0700); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x0038, 0x0667); - - if (phy->gmode || phy->rev >= 2) { - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) - | 0x0020); - b43_radio_write16(dev, 0x0051, - b43_radio_read16(dev, 0x0051) - | 0x0004); - } - b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); - - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); - - b43_phy_write(dev, 0x001C, 0x186A); - - b43_phy_write(dev, 0x0013, - (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900); - b43_phy_write(dev, 0x0035, - (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064); - b43_phy_write(dev, 0x005D, - (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); - } - - if (dev->bad_frames_preempt) { - b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, - b43_phy_read(dev, - B43_PHY_RADIO_BITFIELD) | (1 << 11)); - } - - if (phy->analog == 1) { - b43_phy_write(dev, 0x0026, 0xCE00); - b43_phy_write(dev, 0x0021, 0x3763); - b43_phy_write(dev, 0x0022, 0x1BC3); - b43_phy_write(dev, 0x0023, 0x06F9); - b43_phy_write(dev, 0x0024, 0x037E); - } else - b43_phy_write(dev, 0x0026, 0xCC00); - b43_phy_write(dev, 0x0030, 0x00C6); - b43_write16(dev, 0x03EC, 0x3F22); - - if (phy->analog == 1) - b43_phy_write(dev, 0x0020, 0x3E1C); - else - b43_phy_write(dev, 0x0020, 0x301C); - - if (phy->analog == 0) - b43_write16(dev, 0x03E4, 0x3000); - - old_channel = phy->channel; - /* Force to channel 7, even if not supported. */ - b43_radio_selectchannel(dev, 7, 0); - - if (phy->radio_ver != 0x2050) { - b43_radio_write16(dev, 0x0075, 0x0080); - b43_radio_write16(dev, 0x0079, 0x0081); - } - - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x005A, 0x0070); - } - - b43_radio_write16(dev, 0x005B, 0x007B); - b43_radio_write16(dev, 0x005C, 0x00B0); - - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007); - - b43_radio_selectchannel(dev, old_channel, 0); - - b43_phy_write(dev, 0x0014, 0x0080); - b43_phy_write(dev, 0x0032, 0x00CA); - b43_phy_write(dev, 0x002A, 0x88A3); - - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - - if (phy->radio_ver == 0x2050) - b43_radio_write16(dev, 0x005D, 0x000D); - - b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); -} - -static void b43_phy_initb6(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset, val; - u8 old_channel; - - b43_phy_write(dev, 0x003E, 0x817A); - b43_radio_write16(dev, 0x007A, - (b43_radio_read16(dev, 0x007A) | 0x0058)); - if (phy->radio_rev == 4 || phy->radio_rev == 5) { - b43_radio_write16(dev, 0x51, 0x37); - b43_radio_write16(dev, 0x52, 0x70); - b43_radio_write16(dev, 0x53, 0xB3); - b43_radio_write16(dev, 0x54, 0x9B); - b43_radio_write16(dev, 0x5A, 0x88); - b43_radio_write16(dev, 0x5B, 0x88); - b43_radio_write16(dev, 0x5D, 0x88); - b43_radio_write16(dev, 0x5E, 0x88); - b43_radio_write16(dev, 0x7D, 0x88); - b43_hf_write(dev, b43_hf_read(dev) - | B43_HF_TSSIRPSMW); - } - B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */ - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x51, 0); - b43_radio_write16(dev, 0x52, 0x40); - b43_radio_write16(dev, 0x53, 0xB7); - b43_radio_write16(dev, 0x54, 0x98); - b43_radio_write16(dev, 0x5A, 0x88); - b43_radio_write16(dev, 0x5B, 0x6B); - b43_radio_write16(dev, 0x5C, 0x0F); - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) { - b43_radio_write16(dev, 0x5D, 0xFA); - b43_radio_write16(dev, 0x5E, 0xD8); - } else { - b43_radio_write16(dev, 0x5D, 0xF5); - b43_radio_write16(dev, 0x5E, 0xB8); - } - b43_radio_write16(dev, 0x0073, 0x0003); - b43_radio_write16(dev, 0x007D, 0x00A8); - b43_radio_write16(dev, 0x007C, 0x0001); - b43_radio_write16(dev, 0x007E, 0x0008); - } - val = 0x1E1F; - for (offset = 0x0088; offset < 0x0098; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - val = 0x3E3F; - for (offset = 0x0098; offset < 0x00A8; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - val = 0x2120; - for (offset = 0x00A8; offset < 0x00C8; offset++) { - b43_phy_write(dev, offset, (val & 0x3F3F)); - val += 0x0202; - } - if (phy->type == B43_PHYTYPE_G) { - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0020); - b43_radio_write16(dev, 0x0051, - b43_radio_read16(dev, 0x0051) | 0x0004); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); - b43_phy_write(dev, 0x5B, 0); - b43_phy_write(dev, 0x5C, 0); - } - - old_channel = phy->channel; - if (old_channel >= 8) - b43_radio_selectchannel(dev, 1, 0); - else - b43_radio_selectchannel(dev, 13, 0); - - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - udelay(40); - if (phy->radio_rev < 6 || phy->radio_rev == 8) { - b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C) - | 0x0002)); - b43_radio_write16(dev, 0x50, 0x20); - } - if (phy->radio_rev <= 2) { - b43_radio_write16(dev, 0x7C, 0x20); - b43_radio_write16(dev, 0x5A, 0x70); - b43_radio_write16(dev, 0x5B, 0x7B); - b43_radio_write16(dev, 0x5C, 0xB0); - } - b43_radio_write16(dev, 0x007A, - (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007); - - b43_radio_selectchannel(dev, old_channel, 0); - - b43_phy_write(dev, 0x0014, 0x0200); - if (phy->radio_rev >= 6) - b43_phy_write(dev, 0x2A, 0x88C2); - else - b43_phy_write(dev, 0x2A, 0x8AC0); - b43_phy_write(dev, 0x0038, 0x0668); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - if (phy->radio_rev <= 5) { - b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D) - & 0xFF80) | 0x0003); - } - if (phy->radio_rev <= 2) - b43_radio_write16(dev, 0x005D, 0x000D); - - if (phy->analog == 4) { - b43_write16(dev, 0x3E4, 9); - b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61) - & 0x0FFF); - } else { - b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) - | 0x0004); - } - if (phy->type == B43_PHYTYPE_B) - B43_WARN_ON(1); - else if (phy->type == B43_PHYTYPE_G) - b43_write16(dev, 0x03E6, 0x0); -} - -static void b43_calc_loopback_gain(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 backup_phy[16] = { 0 }; - u16 backup_radio[3]; - u16 backup_bband; - u16 i, j, loop_i_max; - u16 trsw_rx; - u16 loop1_outer_done, loop1_inner_done; - - backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0); - backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); - backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER); - backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); - backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); - } - backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A)); - backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59)); - backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58)); - backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A)); - backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03)); - backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); - backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); - backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B)); - backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); - backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - backup_bband = phy->bbatt.att; - backup_radio[0] = b43_radio_read16(dev, 0x52); - backup_radio[1] = b43_radio_read16(dev, 0x43); - backup_radio[2] = b43_radio_read16(dev, 0x7A); - - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF); - b43_phy_write(dev, B43_PHY_CCKBBANDCFG, - b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000); - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD); - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, - B43_PHY_ANALOGOVERVAL) & 0xFFFE); - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, - B43_PHY_ANALOGOVERVAL) & 0xFFFD); - } - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C); - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - (b43_phy_read(dev, B43_PHY_RFOVERVAL) - & 0xFFCF) | 0x10); - - b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); - b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); - - b43_phy_write(dev, B43_PHY_CCK(0x0A), - b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, - B43_PHY_ANALOGOVERVAL) & 0xFFFB); - } - b43_phy_write(dev, B43_PHY_CCK(0x03), - (b43_phy_read(dev, B43_PHY_CCK(0x03)) - & 0xFF9F) | 0x40); - - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x43, 0x000F); - } else { - b43_radio_write16(dev, 0x52, 0); - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | 0x9); - } - b43_phy_set_baseband_attenuation(dev, 11); - - if (phy->rev >= 3) - b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); - else - b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); - b43_phy_write(dev, B43_PHY_LO_CTL, 0); - - b43_phy_write(dev, B43_PHY_CCK(0x2B), - (b43_phy_read(dev, B43_PHY_CCK(0x2B)) - & 0xFFC0) | 0x01); - b43_phy_write(dev, B43_PHY_CCK(0x2B), - (b43_phy_read(dev, B43_PHY_CCK(0x2B)) - & 0xC0FF) | 0x800); - - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); - - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { - if (phy->rev >= 7) { - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) - | 0x0800); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) - | 0x8000); - } - } - b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A) - & 0x00F7); - - j = 0; - loop_i_max = (phy->radio_rev == 8) ? 15 : 9; - for (i = 0; i < loop_i_max; i++) { - for (j = 0; j < 16; j++) { - b43_radio_write16(dev, 0x43, i); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - (b43_phy_read(dev, B43_PHY_RFOVERVAL) - & 0xF0FF) | (j << 8)); - b43_phy_write(dev, B43_PHY_PGACTL, - (b43_phy_read(dev, B43_PHY_PGACTL) - & 0x0FFF) | 0xA000); - b43_phy_write(dev, B43_PHY_PGACTL, - b43_phy_read(dev, B43_PHY_PGACTL) - | 0xF000); - udelay(20); - if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) - goto exit_loop1; - } - } - exit_loop1: - loop1_outer_done = i; - loop1_inner_done = j; - if (j >= 8) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) - | 0x30); - trsw_rx = 0x1B; - for (j = j - 8; j < 16; j++) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - (b43_phy_read(dev, B43_PHY_RFOVERVAL) - & 0xF0FF) | (j << 8)); - b43_phy_write(dev, B43_PHY_PGACTL, - (b43_phy_read(dev, B43_PHY_PGACTL) - & 0x0FFF) | 0xA000); - b43_phy_write(dev, B43_PHY_PGACTL, - b43_phy_read(dev, B43_PHY_PGACTL) - | 0xF000); - udelay(20); - trsw_rx -= 3; - if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) - goto exit_loop2; - } - } else - trsw_rx = 0x18; - exit_loop2: - - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); - } - b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]); - b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]); - b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]); - b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]); - b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]); - b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); - b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); - b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]); - b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); - - b43_phy_set_baseband_attenuation(dev, backup_bband); - - b43_radio_write16(dev, 0x52, backup_radio[0]); - b43_radio_write16(dev, 0x43, backup_radio[1]); - b43_radio_write16(dev, 0x7A, backup_radio[2]); - - b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003); - udelay(10); - b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]); - b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]); - b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]); - b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]); - - phy->max_lb_gain = - ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11; - phy->trsw_rx_gain = trsw_rx * 2; -} - -static void b43_phy_initg(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 tmp; - - if (phy->rev == 1) - b43_phy_initb5(dev); - else - b43_phy_initb6(dev); - - if (phy->rev >= 2 || phy->gmode) - b43_phy_inita(dev); - - if (phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_ANALOGOVER, 0); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0); - } - if (phy->rev == 2) { - b43_phy_write(dev, B43_PHY_RFOVER, 0); - b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); - } - if (phy->rev > 5) { - b43_phy_write(dev, B43_PHY_RFOVER, 0x400); - b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); - } - if (phy->gmode || phy->rev >= 2) { - tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM); - tmp &= B43_PHYVER_VERSION; - if (tmp == 3 || tmp == 5) { - b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816); - b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); - } - if (tmp == 5) { - b43_phy_write(dev, B43_PHY_OFDM(0xCC), - (b43_phy_read(dev, B43_PHY_OFDM(0xCC)) - & 0x00FF) | 0x1F00); - } - } - if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) - b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); - if (phy->radio_rev == 8) { - b43_phy_write(dev, B43_PHY_EXTG(0x01), - b43_phy_read(dev, B43_PHY_EXTG(0x01)) - | 0x80); - b43_phy_write(dev, B43_PHY_OFDM(0x3E), - b43_phy_read(dev, B43_PHY_OFDM(0x3E)) - | 0x4); - } - if (has_loopback_gain(phy)) - b43_calc_loopback_gain(dev); - - if (phy->radio_rev != 8) { - if (phy->initval == 0xFFFF) - phy->initval = b43_radio_init2050(dev); - else - b43_radio_write16(dev, 0x0078, phy->initval); - } - b43_lo_g_init(dev); - if (has_tx_magnification(phy)) { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFF00) - | phy->lo_control->tx_bias | phy-> - lo_control->tx_magn); - } else { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFFF0) - | phy->lo_control->tx_bias); - } - if (phy->rev >= 6) { - b43_phy_write(dev, B43_PHY_CCK(0x36), - (b43_phy_read(dev, B43_PHY_CCK(0x36)) - & 0x0FFF) | (phy->lo_control-> - tx_bias << 12)); - } - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); - else - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); - if (phy->rev < 2) - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); - else - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); - if (phy->gmode || phy->rev >= 2) { - b43_lo_g_adjust(dev); - b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); - } - - if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { - /* The specs state to update the NRSSI LT with - * the value 0x7FFFFFFF here. I think that is some weird - * compiler optimization in the original driver. - * Essentially, what we do here is resetting all NRSSI LT - * entries to -32 (see the clamp_val() in nrssi_hw_update()) - */ - b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? - b43_calc_nrssi_threshold(dev); - } else if (phy->gmode || phy->rev >= 2) { - if (phy->nrssi[0] == -1000) { - B43_WARN_ON(phy->nrssi[1] != -1000); - b43_calc_nrssi_slope(dev); - } else - b43_calc_nrssi_threshold(dev); - } - if (phy->radio_rev == 8) - b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230); - b43_phy_init_pctl(dev); - /* FIXME: The spec says in the following if, the 0 should be replaced - 'if OFDM may not be used in the current locale' - but OFDM is legal everywhere */ - if ((dev->dev->bus->chip_id == 0x4306 - && dev->dev->bus->chip_package == 2) || 0) { - b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) - & 0xBFFF); - b43_phy_write(dev, B43_PHY_OFDM(0xC3), - b43_phy_read(dev, B43_PHY_OFDM(0xC3)) - & 0x7FFF); - } -} - -/* Set the baseband attenuation value on chip. */ -void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, - u16 baseband_attenuation) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->analog == 0) { - b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0) - & 0xFFF0) | - baseband_attenuation); - } else if (phy->analog > 1) { - b43_phy_write(dev, B43_PHY_DACCTL, - (b43_phy_read(dev, B43_PHY_DACCTL) - & 0xFFC3) | (baseband_attenuation << 2)); - } else { - b43_phy_write(dev, B43_PHY_DACCTL, - (b43_phy_read(dev, B43_PHY_DACCTL) - & 0xFF87) | (baseband_attenuation << 3)); - } -} - -/* http://bcm-specs.sipsolutions.net/EstimatePowerOut - * This function converts a TSSI value to dBm in Q5.2 - */ -static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) -{ - struct b43_phy *phy = &dev->phy; - s8 dbm = 0; - s32 tmp; - - tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi); - - switch (phy->type) { - case B43_PHYTYPE_A: - tmp += 0x80; - tmp = clamp_val(tmp, 0x00, 0xFF); - dbm = phy->tssi2dbm[tmp]; - //TODO: There's a FIXME on the specs - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - tmp = clamp_val(tmp, 0x00, 0x3F); - dbm = phy->tssi2dbm[tmp]; - break; - default: - B43_WARN_ON(1); - } - - return dbm; -} - -void b43_put_attenuation_into_ranges(struct b43_wldev *dev, - int *_bbatt, int *_rfatt) -{ - int rfatt = *_rfatt; - int bbatt = *_bbatt; - struct b43_txpower_lo_control *lo = dev->phy.lo_control; - - /* Get baseband and radio attenuation values into their permitted ranges. - * Radio attenuation affects power level 4 times as much as baseband. */ - - /* Range constants */ - const int rf_min = lo->rfatt_list.min_val; - const int rf_max = lo->rfatt_list.max_val; - const int bb_min = lo->bbatt_list.min_val; - const int bb_max = lo->bbatt_list.max_val; - - while (1) { - if (rfatt > rf_max && bbatt > bb_max - 4) - break; /* Can not get it into ranges */ - if (rfatt < rf_min && bbatt < bb_min + 4) - break; /* Can not get it into ranges */ - if (bbatt > bb_max && rfatt > rf_max - 1) - break; /* Can not get it into ranges */ - if (bbatt < bb_min && rfatt < rf_min + 1) - break; /* Can not get it into ranges */ - - if (bbatt > bb_max) { - bbatt -= 4; - rfatt += 1; - continue; - } - if (bbatt < bb_min) { - bbatt += 4; - rfatt -= 1; - continue; - } - if (rfatt > rf_max) { - rfatt -= 1; - bbatt += 4; - continue; - } - if (rfatt < rf_min) { - rfatt += 1; - bbatt -= 4; - continue; - } - break; - } - - *_rfatt = clamp_val(rfatt, rf_min, rf_max); - *_bbatt = clamp_val(bbatt, bb_min, bb_max); -} - -/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ -void b43_phy_xmitpower(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - - if (phy->cur_idle_tssi == 0) - return; - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306)) - return; -#ifdef CONFIG_B43_DEBUG - if (phy->manual_txpower_control) - return; -#endif - - switch (phy->type) { - case B43_PHYTYPE_A:{ - - //TODO: Nothing for A PHYs yet :-/ - - break; - } - case B43_PHYTYPE_B: - case B43_PHYTYPE_G:{ - u16 tmp; - s8 v0, v1, v2, v3; - s8 average; - int max_pwr; - int desired_pwr, estimated_pwr, pwr_adjust; - int rfatt_delta, bbatt_delta; - int rfatt, bbatt; - u8 tx_control; - - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); - v0 = (s8) (tmp & 0x00FF); - v1 = (s8) ((tmp & 0xFF00) >> 8); - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A); - v2 = (s8) (tmp & 0x00FF); - v3 = (s8) ((tmp & 0xFF00) >> 8); - tmp = 0; - - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F - || v3 == 0x7F) { - tmp = - b43_shm_read16(dev, B43_SHM_SHARED, 0x0070); - v0 = (s8) (tmp & 0x00FF); - v1 = (s8) ((tmp & 0xFF00) >> 8); - tmp = - b43_shm_read16(dev, B43_SHM_SHARED, 0x0072); - v2 = (s8) (tmp & 0x00FF); - v3 = (s8) ((tmp & 0xFF00) >> 8); - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F - || v3 == 0x7F) - return; - v0 = (v0 + 0x20) & 0x3F; - v1 = (v1 + 0x20) & 0x3F; - v2 = (v2 + 0x20) & 0x3F; - v3 = (v3 + 0x20) & 0x3F; - tmp = 1; - } - b43_shm_clear_tssi(dev); - - average = (v0 + v1 + v2 + v3 + 2) / 4; - - if (tmp - && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & - 0x8)) - average -= 13; - - estimated_pwr = - b43_phy_estimate_power_out(dev, average); - - max_pwr = dev->dev->bus->sprom.maxpwr_bg; - if ((dev->dev->bus->sprom.boardflags_lo - & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) - max_pwr -= 0x3; - if (unlikely(max_pwr <= 0)) { - b43warn(dev->wl, - "Invalid max-TX-power value in SPROM.\n"); - max_pwr = 60; /* fake it */ - dev->dev->bus->sprom.maxpwr_bg = max_pwr; - } - - /*TODO: - max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) - where REG is the max power as per the regulatory domain - */ - - /* Get desired power (in Q5.2) */ - desired_pwr = INT_TO_Q52(phy->power_level); - /* And limit it. max_pwr already is Q5.2 */ - desired_pwr = clamp_val(desired_pwr, 0, max_pwr); - if (b43_debug(dev, B43_DBG_XMITPOWER)) { - b43dbg(dev->wl, - "Current TX power output: " Q52_FMT - " dBm, " "Desired TX power output: " - Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), - Q52_ARG(desired_pwr)); - } - - /* Calculate the adjustment delta. */ - pwr_adjust = desired_pwr - estimated_pwr; - - /* RF attenuation delta. */ - rfatt_delta = ((pwr_adjust + 7) / 8); - /* Lower attenuation => Bigger power output. Negate it. */ - rfatt_delta = -rfatt_delta; - - /* Baseband attenuation delta. */ - bbatt_delta = pwr_adjust / 2; - /* Lower attenuation => Bigger power output. Negate it. */ - bbatt_delta = -bbatt_delta; - /* RF att affects power level 4 times as much as - * Baseband attennuation. Subtract it. */ - bbatt_delta -= 4 * rfatt_delta; - - /* So do we finally need to adjust something? */ - if ((rfatt_delta == 0) && (bbatt_delta == 0)) - return; - - /* Calculate the new attenuation values. */ - bbatt = phy->bbatt.att; - bbatt += bbatt_delta; - rfatt = phy->rfatt.att; - rfatt += rfatt_delta; - - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - tx_control = phy->tx_control; - if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { - if (rfatt <= 1) { - if (tx_control == 0) { - tx_control = - B43_TXCTL_PA2DB | - B43_TXCTL_TXMIX; - rfatt += 2; - bbatt += 2; - } else if (dev->dev->bus->sprom. - boardflags_lo & - B43_BFL_PACTRL) { - bbatt += 4 * (rfatt - 2); - rfatt = 2; - } - } else if (rfatt > 4 && tx_control) { - tx_control = 0; - if (bbatt < 3) { - rfatt -= 3; - bbatt += 2; - } else { - rfatt -= 2; - bbatt -= 2; - } - } - } - /* Save the control values */ - phy->tx_control = tx_control; - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - phy->rfatt.att = rfatt; - phy->bbatt.att = bbatt; - - /* Adjust the hardware */ - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, - phy->tx_control); - b43_radio_unlock(dev); - b43_phy_unlock(dev); - break; - } - case B43_PHYTYPE_N: - b43_nphy_xmitpower(dev); - break; - default: - B43_WARN_ON(1); - } -} - -static inline s32 b43_tssi2dbm_ad(s32 num, s32 den) -{ - if (num < 0) - return num / den; - else - return (num + den / 2) / den; -} - -static inline - s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2) -{ - s32 m1, m2, f = 256, q, delta; - s8 i = 0; - - m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); - m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); - do { - if (i > 15) - return -EINVAL; - q = b43_tssi2dbm_ad(f * 4096 - - b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); - delta = abs(q - f); - f = q; - i++; - } while (delta >= 2); - entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); - return 0; -} - -/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ -int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - s16 pab0, pab1, pab2; - u8 idx; - s8 *dyn_tssi2dbm; - - if (phy->type == B43_PHYTYPE_A) { - pab0 = (s16) (dev->dev->bus->sprom.pa1b0); - pab1 = (s16) (dev->dev->bus->sprom.pa1b1); - pab2 = (s16) (dev->dev->bus->sprom.pa1b2); - } else { - pab0 = (s16) (dev->dev->bus->sprom.pa0b0); - pab1 = (s16) (dev->dev->bus->sprom.pa0b1); - pab2 = (s16) (dev->dev->bus->sprom.pa0b2); - } - - if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_b_table; - return 0; - } - - if (pab0 != 0 && pab1 != 0 && pab2 != 0 && - pab0 != -1 && pab1 != -1 && pab2 != -1) { - /* The pabX values are set in SPROM. Use them. */ - if (phy->type == B43_PHYTYPE_A) { - if ((s8) dev->dev->bus->sprom.itssi_a != 0 && - (s8) dev->dev->bus->sprom.itssi_a != -1) - phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.itssi_a); - else - phy->tgt_idle_tssi = 62; - } else { - if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && - (s8) dev->dev->bus->sprom.itssi_bg != -1) - phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.itssi_bg); - else - phy->tgt_idle_tssi = 62; - } - dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); - if (dyn_tssi2dbm == NULL) { - b43err(dev->wl, "Could not allocate memory " - "for tssi2dbm table\n"); - return -ENOMEM; - } - for (idx = 0; idx < 64; idx++) - if (b43_tssi2dbm_entry - (dyn_tssi2dbm, idx, pab0, pab1, pab2)) { - phy->tssi2dbm = NULL; - b43err(dev->wl, "Could not generate " - "tssi2dBm table\n"); - kfree(dyn_tssi2dbm); - return -ENODEV; - } - phy->tssi2dbm = dyn_tssi2dbm; - phy->dyn_tssi_tbl = 1; - } else { - /* pabX values not set in SPROM. */ - switch (phy->type) { - case B43_PHYTYPE_A: - /* APHY needs a generated table. */ - phy->tssi2dbm = NULL; - b43err(dev->wl, "Could not generate tssi2dBm " - "table (wrong SPROM info)!\n"); - return -ENODEV; - case B43_PHYTYPE_B: - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_b_table; - break; - case B43_PHYTYPE_G: - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_g_table; - break; - } - } - - return 0; -} - -int b43_phy_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - bool unsupported = 0; - int err = 0; - - switch (phy->type) { - case B43_PHYTYPE_A: - if (phy->rev == 2 || phy->rev == 3) - b43_phy_inita(dev); - else - unsupported = 1; - break; - case B43_PHYTYPE_G: - b43_phy_initg(dev); - break; - case B43_PHYTYPE_N: - err = b43_phy_initn(dev); - break; - default: - unsupported = 1; - } - if (unsupported) - b43err(dev->wl, "Unknown PHYTYPE found\n"); - - return err; -} - -void b43_set_rx_antenna(struct b43_wldev *dev, int antenna) -{ - struct b43_phy *phy = &dev->phy; - u64 hf; - u16 tmp; - int autodiv = 0; - - if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) - autodiv = 1; - - hf = b43_hf_read(dev); - hf &= ~B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); - - switch (phy->type) { - case B43_PHYTYPE_A: - case B43_PHYTYPE_G: - tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); - - if (autodiv) { - tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - if (antenna == B43_ANTENNA_AUTO0) - tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; - else - tmp |= B43_PHY_ANTDWELL_AUTODIV1; - b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); - } - if (phy->type == B43_PHYTYPE_G) { - tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT); - if (autodiv) - tmp |= B43_PHY_ANTWRSETT_ARXDIV; - else - tmp &= ~B43_PHY_ANTWRSETT_ARXDIV; - b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp); - if (phy->rev >= 2) { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= B43_PHY_OFDM61_10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - - tmp = - b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK); - tmp = (tmp & 0xFF00) | 0x15; - b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK, - tmp); - - if (phy->rev == 2) { - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); - } else { - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); - } - } - if (phy->rev >= 6) - b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); - } else { - if (phy->rev < 3) { - tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - tmp = (tmp & 0xFF00) | 0x24; - b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); - } else { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= 0x10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - if (phy->analog == 3) { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x1D); - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); - } else { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x3A); - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); - } - } - } - break; - case B43_PHYTYPE_B: - tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp); - break; - case B43_PHYTYPE_N: - b43_nphy_set_rxantenna(dev, antenna); - break; - default: - B43_WARN_ON(1); - } - - hf |= B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); -} - -/* Get the freq, as it has to be written to the device. */ -static inline u16 channel2freq_bg(u8 channel) -{ - B43_WARN_ON(!(channel >= 1 && channel <= 14)); - - return b43_radio_channel_codes_bg[channel - 1]; -} - -/* Get the freq, as it has to be written to the device. */ -static inline u16 channel2freq_a(u8 channel) -{ - B43_WARN_ON(channel > 200); - - return (5000 + 5 * channel); -} - -void b43_radio_lock(struct b43_wldev *dev) -{ - u32 macctl; - - macctl = b43_read32(dev, B43_MMIO_MACCTL); - B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK); - macctl |= B43_MACCTL_RADIOLOCK; - b43_write32(dev, B43_MMIO_MACCTL, macctl); - /* Commit the write and wait for the device - * to exit any radio register access. */ - b43_read32(dev, B43_MMIO_MACCTL); - udelay(10); -} - -void b43_radio_unlock(struct b43_wldev *dev) -{ - u32 macctl; - - /* Commit any write */ - b43_read16(dev, B43_MMIO_PHY_VER); - /* unlock */ - macctl = b43_read32(dev, B43_MMIO_MACCTL); - B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK)); - macctl &= ~B43_MACCTL_RADIOLOCK; - b43_write32(dev, B43_MMIO_MACCTL, macctl); -} - -u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) -{ - struct b43_phy *phy = &dev->phy; - - /* Offset 1 is a 32-bit register. */ - B43_WARN_ON(offset == 1); - - switch (phy->type) { - case B43_PHYTYPE_A: - offset |= 0x40; - break; - case B43_PHYTYPE_B: - if (phy->radio_ver == 0x2053) { - if (offset < 0x70) - offset += 0x80; - else if (offset < 0x80) - offset += 0x70; - } else if (phy->radio_ver == 0x2050) { - offset |= 0x80; - } else - B43_WARN_ON(1); - break; - case B43_PHYTYPE_G: - offset |= 0x80; - break; - case B43_PHYTYPE_N: - offset |= 0x100; - break; - case B43_PHYTYPE_LP: - /* No adjustment required. */ - break; - default: - B43_WARN_ON(1); - } - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); - return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); -} - -void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val) -{ - /* Offset 1 is a 32-bit register. */ - B43_WARN_ON(offset == 1); - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); - b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val); -} - -void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask) -{ - b43_radio_write16(dev, offset, - b43_radio_read16(dev, offset) & mask); -} - -void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set) -{ - b43_radio_write16(dev, offset, - b43_radio_read16(dev, offset) | set); -} - -void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) -{ - b43_radio_write16(dev, offset, - (b43_radio_read16(dev, offset) & mask) | set); -} - static void b43_set_all_gains(struct b43_wldev *dev, s16 first, s16 second, s16 third) { @@ -2134,108 +382,10 @@ static void b43_set_original_gains(struct b43_wldev *dev) b43_dummy_transmission(dev); } -/* Synthetic PU workaround */ -static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel) -{ - struct b43_phy *phy = &dev->phy; - - might_sleep(); - - if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) { - /* We do not need the workaround. */ - return; - } - - if (channel <= 10) { - b43_write16(dev, B43_MMIO_CHANNEL, - channel2freq_bg(channel + 4)); - } else { - b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1)); - } - msleep(1); - b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); -} - -u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel) -{ - struct b43_phy *phy = &dev->phy; - u8 ret = 0; - u16 saved, rssi, temp; - int i, j = 0; - - saved = b43_phy_read(dev, 0x0403); - b43_radio_selectchannel(dev, channel, 0); - b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); - if (phy->aci_hw_rssi) - rssi = b43_phy_read(dev, 0x048A) & 0x3F; - else - rssi = saved & 0x3F; - /* clamp temp to signed 5bit */ - if (rssi > 32) - rssi -= 64; - for (i = 0; i < 100; i++) { - temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F; - if (temp > 32) - temp -= 64; - if (temp < rssi) - j++; - if (j >= 20) - ret = 1; - } - b43_phy_write(dev, 0x0403, saved); - - return ret; -} - -u8 b43_radio_aci_scan(struct b43_wldev * dev) -{ - struct b43_phy *phy = &dev->phy; - u8 ret[13]; - unsigned int channel = phy->channel; - unsigned int i, j, start, end; - - if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) - return 0; - - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); - b43_set_all_gains(dev, 3, 8, 1); - - start = (channel - 5 > 0) ? channel - 5 : 1; - end = (channel + 5 < 14) ? channel + 5 : 13; - - for (i = start; i <= end; i++) { - if (abs(channel - i) > 2) - ret[i - 1] = b43_radio_aci_detect(dev, i); - } - b43_radio_selectchannel(dev, channel, 0); - b43_phy_write(dev, 0x0802, - (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003); - b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); - b43_set_original_gains(dev); - for (i = 0; i < 13; i++) { - if (!ret[i]) - continue; - end = (i + 5 < 13) ? i + 5 : 13; - for (j = i; j < end; j++) - ret[j] = 1; - } - b43_radio_unlock(dev); - b43_phy_unlock(dev); - - return ret[channel - 1]; -} - /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) { b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); - mmiowb(); b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); } @@ -2267,17 +417,17 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ void b43_nrssi_mem_update(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; s16 i, delta; s32 tmp; - delta = 0x1F - phy->nrssi[0]; + delta = 0x1F - gphy->nrssi[0]; for (i = 0; i < 64; i++) { - tmp = (i - delta) * phy->nrssislope; + tmp = (i - delta) * gphy->nrssislope; tmp /= 0x10000; tmp += 0x3A; tmp = clamp_val(tmp, 0, 0x3F); - phy->nrssi_lt[i] = tmp; + gphy->nrssi_lt[i] = tmp; } } @@ -2442,347 +592,230 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev) void b43_calc_nrssi_slope(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; u16 backup[18] = { 0 }; u16 tmp; s16 nrssi0, nrssi1; - switch (phy->type) { - case B43_PHYTYPE_B: - backup[0] = b43_radio_read16(dev, 0x007A); - backup[1] = b43_radio_read16(dev, 0x0052); - backup[2] = b43_radio_read16(dev, 0x0043); - backup[3] = b43_phy_read(dev, 0x0030); - backup[4] = b43_phy_read(dev, 0x0026); - backup[5] = b43_phy_read(dev, 0x0015); - backup[6] = b43_phy_read(dev, 0x002A); - backup[7] = b43_phy_read(dev, 0x0020); - backup[8] = b43_phy_read(dev, 0x005A); - backup[9] = b43_phy_read(dev, 0x0059); - backup[10] = b43_phy_read(dev, 0x0058); - backup[11] = b43_read16(dev, 0x03E2); - backup[12] = b43_read16(dev, 0x03E6); - backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); - - tmp = b43_radio_read16(dev, 0x007A); - tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; - b43_radio_write16(dev, 0x007A, tmp); - b43_phy_write(dev, 0x0030, 0x00FF); - b43_write16(dev, 0x03EC, 0x7F7F); - b43_phy_write(dev, 0x0026, 0x0000); - b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020); - b43_phy_write(dev, 0x002A, 0x08A3); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0080); + B43_WARN_ON(phy->type != B43_PHYTYPE_G); - nrssi0 = (s16) b43_phy_read(dev, 0x0027); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x007F); - if (phy->rev >= 2) { - b43_write16(dev, 0x03E6, 0x0040); - } else if (phy->rev == 0) { - b43_write16(dev, 0x03E6, 0x0122); - } else { - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, - B43_MMIO_CHANNEL_EXT) & 0x2000); - } - b43_phy_write(dev, 0x0020, 0x3F3F); - b43_phy_write(dev, 0x0015, 0xF330); - b43_radio_write16(dev, 0x005A, 0x0060); - b43_radio_write16(dev, 0x0043, - b43_radio_read16(dev, 0x0043) & 0x00F0); - b43_phy_write(dev, 0x005A, 0x0480); - b43_phy_write(dev, 0x0059, 0x0810); - b43_phy_write(dev, 0x0058, 0x000D); - udelay(20); - - nrssi1 = (s16) b43_phy_read(dev, 0x0027); - b43_phy_write(dev, 0x0030, backup[3]); - b43_radio_write16(dev, 0x007A, backup[0]); - b43_write16(dev, 0x03E2, backup[11]); - b43_phy_write(dev, 0x0026, backup[4]); - b43_phy_write(dev, 0x0015, backup[5]); - b43_phy_write(dev, 0x002A, backup[6]); - b43_synth_pu_workaround(dev, phy->channel); - if (phy->rev != 0) - b43_write16(dev, 0x03F4, backup[13]); - - b43_phy_write(dev, 0x0020, backup[7]); - b43_phy_write(dev, 0x005A, backup[8]); - b43_phy_write(dev, 0x0059, backup[9]); - b43_phy_write(dev, 0x0058, backup[10]); - b43_radio_write16(dev, 0x0052, backup[1]); - b43_radio_write16(dev, 0x0043, backup[2]); - - if (nrssi0 == nrssi1) - phy->nrssislope = 0x00010000; - else - phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); - - if (nrssi0 <= -4) { - phy->nrssi[0] = nrssi0; - phy->nrssi[1] = nrssi1; - } - break; - case B43_PHYTYPE_G: - if (phy->radio_rev >= 9) - return; - if (phy->radio_rev == 8) - b43_calc_nrssi_offset(dev); + if (phy->radio_rev >= 9) + return; + if (phy->radio_rev == 8) + b43_calc_nrssi_offset(dev); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); - backup[7] = b43_read16(dev, 0x03E2); - b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); - backup[0] = b43_radio_read16(dev, 0x007A); - backup[1] = b43_radio_read16(dev, 0x0052); - backup[2] = b43_radio_read16(dev, 0x0043); - backup[3] = b43_phy_read(dev, 0x0015); - backup[4] = b43_phy_read(dev, 0x005A); - backup[5] = b43_phy_read(dev, 0x0059); - backup[6] = b43_phy_read(dev, 0x0058); - backup[8] = b43_read16(dev, 0x03E6); - backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); - if (phy->rev >= 3) { - backup[10] = b43_phy_read(dev, 0x002E); - backup[11] = b43_phy_read(dev, 0x002F); - backup[12] = b43_phy_read(dev, 0x080F); - backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL); - backup[14] = b43_phy_read(dev, 0x0801); - backup[15] = b43_phy_read(dev, 0x0060); - backup[16] = b43_phy_read(dev, 0x0014); - backup[17] = b43_phy_read(dev, 0x0478); - b43_phy_write(dev, 0x002E, 0); - b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0); - switch (phy->rev) { - case 4: - case 6: - case 7: - b43_phy_write(dev, 0x0478, - b43_phy_read(dev, 0x0478) - | 0x0100); - b43_phy_write(dev, 0x0801, - b43_phy_read(dev, 0x0801) - | 0x0040); - break; - case 3: - case 5: - b43_phy_write(dev, 0x0801, - b43_phy_read(dev, 0x0801) - & 0xFFBF); - break; - } - b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + backup[7] = b43_read16(dev, 0x03E2); + b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); + backup[0] = b43_radio_read16(dev, 0x007A); + backup[1] = b43_radio_read16(dev, 0x0052); + backup[2] = b43_radio_read16(dev, 0x0043); + backup[3] = b43_phy_read(dev, 0x0015); + backup[4] = b43_phy_read(dev, 0x005A); + backup[5] = b43_phy_read(dev, 0x0059); + backup[6] = b43_phy_read(dev, 0x0058); + backup[8] = b43_read16(dev, 0x03E6); + backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = b43_phy_read(dev, 0x002E); + backup[11] = b43_phy_read(dev, 0x002F); + backup[12] = b43_phy_read(dev, 0x080F); + backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL); + backup[14] = b43_phy_read(dev, 0x0801); + backup[15] = b43_phy_read(dev, 0x0060); + backup[16] = b43_phy_read(dev, 0x0014); + backup[17] = b43_phy_read(dev, 0x0478); + b43_phy_write(dev, 0x002E, 0); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: + case 6: + case 7: + b43_phy_write(dev, 0x0478, + b43_phy_read(dev, 0x0478) + | 0x0100); + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) | 0x0040); - b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) - | 0x0200); - } - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0070); - b43_set_all_gains(dev, 0, 8, 0); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x00F7); - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0811, - (b43_phy_read(dev, 0x0811) & 0xFFCF) | - 0x0030); - b43_phy_write(dev, 0x0812, - (b43_phy_read(dev, 0x0812) & 0xFFCF) | - 0x0010); + break; + case 3: + case 5: + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) + & 0xFFBF); + break; } - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0080); - udelay(20); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) + | 0x0040); + b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) + | 0x0200); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0070); + b43_set_all_gains(dev, 0, 8, 0); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x00F7); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0030); + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0010); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0080); + udelay(20); - nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (nrssi0 >= 0x0020) - nrssi0 -= 0x0040; + nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x007F); - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) - & 0xFF9F) | 0x0040); - } - - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, B43_MMIO_CHANNEL_EXT) - | 0x2000); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x000F); - b43_phy_write(dev, 0x0015, 0xF330); - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0812, - (b43_phy_read(dev, 0x0812) & 0xFFCF) | - 0x0020); - b43_phy_write(dev, 0x0811, - (b43_phy_read(dev, 0x0811) & 0xFFCF) | - 0x0020); - } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) + & 0xFF9F) | 0x0040); + } - b43_set_all_gains(dev, 3, 0, 1); - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x0043, 0x001F); - } else { - tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F; - b43_radio_write16(dev, 0x0052, tmp | 0x0060); - tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0; - b43_radio_write16(dev, 0x0043, tmp | 0x0009); - } - b43_phy_write(dev, 0x005A, 0x0480); - b43_phy_write(dev, 0x0059, 0x0810); - b43_phy_write(dev, 0x0058, 0x000D); - udelay(20); - nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (nrssi1 >= 0x0020) - nrssi1 -= 0x0040; - if (nrssi0 == nrssi1) - phy->nrssislope = 0x00010000; - else - phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); - if (nrssi0 >= -4) { - phy->nrssi[0] = nrssi1; - phy->nrssi[1] = nrssi0; - } - if (phy->rev >= 3) { - b43_phy_write(dev, 0x002E, backup[10]); - b43_phy_write(dev, 0x002F, backup[11]); - b43_phy_write(dev, 0x080F, backup[12]); - b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); - } - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0812, - b43_phy_read(dev, 0x0812) & 0xFFCF); - b43_phy_write(dev, 0x0811, - b43_phy_read(dev, 0x0811) & 0xFFCF); - } + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | 0x2000); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x000F); + b43_phy_write(dev, 0x0015, 0xF330); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0020); + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0020); + } - b43_radio_write16(dev, 0x007A, backup[0]); - b43_radio_write16(dev, 0x0052, backup[1]); - b43_radio_write16(dev, 0x0043, backup[2]); - b43_write16(dev, 0x03E2, backup[7]); - b43_write16(dev, 0x03E6, backup[8]); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]); - b43_phy_write(dev, 0x0015, backup[3]); - b43_phy_write(dev, 0x005A, backup[4]); - b43_phy_write(dev, 0x0059, backup[5]); - b43_phy_write(dev, 0x0058, backup[6]); - b43_synth_pu_workaround(dev, phy->channel); - b43_phy_write(dev, 0x0802, - b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002)); - b43_set_original_gains(dev); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); - if (phy->rev >= 3) { - b43_phy_write(dev, 0x0801, backup[14]); - b43_phy_write(dev, 0x0060, backup[15]); - b43_phy_write(dev, 0x0014, backup[16]); - b43_phy_write(dev, 0x0478, backup[17]); - } - b43_nrssi_mem_update(dev); - b43_calc_nrssi_threshold(dev); - break; - default: - B43_WARN_ON(1); + b43_set_all_gains(dev, 3, 0, 1); + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x0043, 0x001F); + } else { + tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F; + b43_radio_write16(dev, 0x0052, tmp | 0x0060); + tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0; + b43_radio_write16(dev, 0x0043, tmp | 0x0009); + } + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + gphy->nrssislope = 0x00010000; + else + gphy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + gphy->nrssi[0] = nrssi1; + gphy->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + b43_phy_write(dev, 0x002E, backup[10]); + b43_phy_write(dev, 0x002F, backup[11]); + b43_phy_write(dev, 0x080F, backup[12]); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); } + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + b43_phy_read(dev, 0x0812) & 0xFFCF); + b43_phy_write(dev, 0x0811, + b43_phy_read(dev, 0x0811) & 0xFFCF); + } + + b43_radio_write16(dev, 0x007A, backup[0]); + b43_radio_write16(dev, 0x0052, backup[1]); + b43_radio_write16(dev, 0x0043, backup[2]); + b43_write16(dev, 0x03E2, backup[7]); + b43_write16(dev, 0x03E6, backup[8]); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]); + b43_phy_write(dev, 0x0015, backup[3]); + b43_phy_write(dev, 0x005A, backup[4]); + b43_phy_write(dev, 0x0059, backup[5]); + b43_phy_write(dev, 0x0058, backup[6]); + b43_synth_pu_workaround(dev, phy->channel); + b43_phy_write(dev, 0x0802, + b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002)); + b43_set_original_gains(dev); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + if (phy->rev >= 3) { + b43_phy_write(dev, 0x0801, backup[14]); + b43_phy_write(dev, 0x0060, backup[15]); + b43_phy_write(dev, 0x0014, backup[16]); + b43_phy_write(dev, 0x0478, backup[17]); + } + b43_nrssi_mem_update(dev); + b43_calc_nrssi_threshold(dev); } -void b43_calc_nrssi_threshold(struct b43_wldev *dev) +static void b43_calc_nrssi_threshold(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - s32 threshold; + struct b43_phy_g *gphy = phy->g; s32 a, b; s16 tmp16; u16 tmp_u16; - switch (phy->type) { - case B43_PHYTYPE_B:{ - if (phy->radio_ver != 0x2050) - return; - if (! - (dev->dev->bus->sprom. - boardflags_lo & B43_BFL_RSSI)) - return; - - if (phy->radio_rev >= 6) { - threshold = - (phy->nrssi[1] - phy->nrssi[0]) * 32; - threshold += 20 * (phy->nrssi[0] + 1); - threshold /= 40; - } else - threshold = phy->nrssi[1] - 5; - - threshold = clamp_val(threshold, 0, 0x3E); - b43_phy_read(dev, 0x0020); /* dummy read */ - b43_phy_write(dev, 0x0020, - (((u16) threshold) << 8) | 0x001C); - - if (phy->radio_rev >= 6) { - b43_phy_write(dev, 0x0087, 0x0E0D); - b43_phy_write(dev, 0x0086, 0x0C0B); - b43_phy_write(dev, 0x0085, 0x0A09); - b43_phy_write(dev, 0x0084, 0x0808); - b43_phy_write(dev, 0x0083, 0x0808); - b43_phy_write(dev, 0x0082, 0x0604); - b43_phy_write(dev, 0x0081, 0x0302); - b43_phy_write(dev, 0x0080, 0x0100); - } - break; + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + if (!phy->gmode || + !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { + tmp16 = b43_nrssi_hw_read(dev, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x09EB); + } else { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x0AED); } - case B43_PHYTYPE_G: - if (!phy->gmode || - !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { - tmp16 = b43_nrssi_hw_read(dev, 0x20); - if (tmp16 >= 0x20) - tmp16 -= 0x40; - if (tmp16 < 3) { - b43_phy_write(dev, 0x048A, - (b43_phy_read(dev, 0x048A) - & 0xF000) | 0x09EB); - } else { - b43_phy_write(dev, 0x048A, - (b43_phy_read(dev, 0x048A) - & 0xF000) | 0x0AED); - } + } else { + if (gphy->interfmode == B43_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!gphy->aci_wlan_automatic && gphy->aci_enable) { + a = 0x13; + b = 0x12; } else { - if (phy->interfmode == B43_INTERFMODE_NONWLAN) { - a = 0xE; - b = 0xA; - } else if (!phy->aci_wlan_automatic && phy->aci_enable) { - a = 0x13; - b = 0x12; - } else { - a = 0xE; - b = 0x11; - } - - a = a * (phy->nrssi[1] - phy->nrssi[0]); - a += (phy->nrssi[0] << 6); - if (a < 32) - a += 31; - else - a += 32; - a = a >> 6; - a = clamp_val(a, -31, 31); - - b = b * (phy->nrssi[1] - phy->nrssi[0]); - b += (phy->nrssi[0] << 6); - if (b < 32) - b += 31; - else - b += 32; - b = b >> 6; - b = clamp_val(b, -31, 31); - - tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; - tmp_u16 |= ((u32) b & 0x0000003F); - tmp_u16 |= (((u32) a & 0x0000003F) << 6); - b43_phy_write(dev, 0x048A, tmp_u16); + a = 0xE; + b = 0x11; } - break; - default: - B43_WARN_ON(1); + + a = a * (gphy->nrssi[1] - gphy->nrssi[0]); + a += (gphy->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; + a = clamp_val(a, -31, 31); + + b = b * (gphy->nrssi[1] - gphy->nrssi[0]); + b += (gphy->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; + b = clamp_val(b, -31, 31); + + tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; + tmp_u16 |= ((u32) b & 0x0000003F); + tmp_u16 |= (((u32) a & 0x0000003F) << 6); + b43_phy_write(dev, 0x048A, tmp_u16); } } @@ -2860,9 +893,10 @@ static void b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; u16 tmp, flipped; size_t stackidx = 0; - u32 *stack = phy->interfstack; + u32 *stack = gphy->interfstack; switch (mode) { case B43_INTERFMODE_NONWLAN: @@ -2928,7 +962,7 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) if (b43_phy_read(dev, 0x0033) & 0x0800) break; - phy->aci_enable = 1; + gphy->aci_enable = 1; phy_stacksave(B43_PHY_RADIO_BITFIELD); phy_stacksave(B43_PHY_G_CRS); @@ -3064,7 +1098,8 @@ static void b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) { struct b43_phy *phy = &dev->phy; - u32 *stack = phy->interfstack; + struct b43_phy_g *gphy = phy->g; + u32 *stack = gphy->interfstack; switch (mode) { case B43_INTERFMODE_NONWLAN: @@ -3103,7 +1138,7 @@ b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) if (!(b43_phy_read(dev, 0x0033) & 0x0800)) break; - phy->aci_enable = 0; + gphy->aci_enable = 0; phy_stackrestore(B43_PHY_RADIO_BITFIELD); phy_stackrestore(B43_PHY_G_CRS); @@ -3153,47 +1188,6 @@ b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) #undef ofdmtab_stacksave #undef ofdmtab_stackrestore -int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode) -{ - struct b43_phy *phy = &dev->phy; - int currentmode; - - if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode)) - return -ENODEV; - - phy->aci_wlan_automatic = 0; - switch (mode) { - case B43_INTERFMODE_AUTOWLAN: - phy->aci_wlan_automatic = 1; - if (phy->aci_enable) - mode = B43_INTERFMODE_MANUALWLAN; - else - mode = B43_INTERFMODE_NONE; - break; - case B43_INTERFMODE_NONE: - case B43_INTERFMODE_NONWLAN: - case B43_INTERFMODE_MANUALWLAN: - break; - default: - return -EINVAL; - } - - currentmode = phy->interfmode; - if (currentmode == mode) - return 0; - if (currentmode != B43_INTERFMODE_NONE) - b43_radio_interference_mitigation_disable(dev, currentmode); - - if (mode == B43_INTERFMODE_NONE) { - phy->aci_enable = 0; - phy->aci_hw_rssi = 0; - } else - b43_radio_interference_mitigation_enable(dev, mode); - phy->interfmode = mode; - - return 0; -} - static u16 b43_radio_core_calibration_value(struct b43_wldev *dev) { u16 reg, index, ret; @@ -3219,13 +1213,14 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev, u16 phy_register, unsigned int lpd) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct ssb_sprom *sprom = &(dev->dev->bus->sprom); if (!phy->gmode) return 0; if (has_loopback_gain(phy)) { - int max_lb_gain = phy->max_lb_gain; + int max_lb_gain = gphy->max_lb_gain; u16 extlna; u16 i; @@ -3606,301 +1601,1682 @@ u16 b43_radio_init2050(struct b43_wldev *dev) return ret; } -void b43_radio_init2060(struct b43_wldev *dev) +static void b43_phy_initb5(struct b43_wldev *dev) { - int err; + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 offset, value; + u8 old_channel; - b43_radio_write16(dev, 0x0004, 0x00C0); - b43_radio_write16(dev, 0x0005, 0x0008); - b43_radio_write16(dev, 0x0009, 0x0040); - b43_radio_write16(dev, 0x0005, 0x00AA); - b43_radio_write16(dev, 0x0032, 0x008F); - b43_radio_write16(dev, 0x0006, 0x008F); - b43_radio_write16(dev, 0x0034, 0x008F); - b43_radio_write16(dev, 0x002C, 0x0007); - b43_radio_write16(dev, 0x0082, 0x0080); - b43_radio_write16(dev, 0x0080, 0x0000); - b43_radio_write16(dev, 0x003F, 0x00DA); - b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); - msleep(1); /* delay 400usec */ - - b43_radio_write16(dev, 0x0081, - (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); - msleep(1); /* delay 400usec */ - - b43_radio_write16(dev, 0x0005, - (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); - b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); - b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); - b43_radio_write16(dev, 0x0081, - (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); - b43_radio_write16(dev, 0x0005, - (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); - b43_phy_write(dev, 0x0063, 0xDDC6); - b43_phy_write(dev, 0x0069, 0x07BE); - b43_phy_write(dev, 0x006A, 0x0000); - - err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0); - B43_WARN_ON(err); + if (phy->analog == 1) { + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) + | 0x0050); + } + if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type != SSB_BOARD_BU4306)) { + value = 0x2120; + for (offset = 0x00A8; offset < 0x00C7; offset++) { + b43_phy_write(dev, offset, value); + value += 0x202; + } + } + b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF) + | 0x0700); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x0038, 0x0667); - msleep(1); + if (phy->gmode || phy->rev >= 2) { + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) + | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) + | 0x0004); + } + b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); + + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + + b43_phy_write(dev, 0x001C, 0x186A); + + b43_phy_write(dev, 0x0013, + (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900); + b43_phy_write(dev, 0x0035, + (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064); + b43_phy_write(dev, 0x005D, + (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); + } + + if (dev->bad_frames_preempt) { + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, + B43_PHY_RADIO_BITFIELD) | (1 << 11)); + } + + if (phy->analog == 1) { + b43_phy_write(dev, 0x0026, 0xCE00); + b43_phy_write(dev, 0x0021, 0x3763); + b43_phy_write(dev, 0x0022, 0x1BC3); + b43_phy_write(dev, 0x0023, 0x06F9); + b43_phy_write(dev, 0x0024, 0x037E); + } else + b43_phy_write(dev, 0x0026, 0xCC00); + b43_phy_write(dev, 0x0030, 0x00C6); + b43_write16(dev, 0x03EC, 0x3F22); + + if (phy->analog == 1) + b43_phy_write(dev, 0x0020, 0x3E1C); + else + b43_phy_write(dev, 0x0020, 0x301C); + + if (phy->analog == 0) + b43_write16(dev, 0x03E4, 0x3000); + + old_channel = phy->channel; + /* Force to channel 7, even if not supported. */ + b43_gphy_channel_switch(dev, 7, 0); + + if (phy->radio_ver != 0x2050) { + b43_radio_write16(dev, 0x0075, 0x0080); + b43_radio_write16(dev, 0x0079, 0x0081); + } + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x005A, 0x0070); + } + + b43_radio_write16(dev, 0x005B, 0x007B); + b43_radio_write16(dev, 0x005C, 0x00B0); + + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007); + + b43_gphy_channel_switch(dev, old_channel, 0); + + b43_phy_write(dev, 0x0014, 0x0080); + b43_phy_write(dev, 0x0032, 0x00CA); + b43_phy_write(dev, 0x002A, 0x88A3); + + b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control); + + if (phy->radio_ver == 0x2050) + b43_radio_write16(dev, 0x005D, 0x000D); + + b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); } -static inline u16 freq_r3A_value(u16 frequency) +static void b43_phy_initb6(struct b43_wldev *dev) { - u16 value; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 offset, val; + u8 old_channel; + + b43_phy_write(dev, 0x003E, 0x817A); + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) | 0x0058)); + if (phy->radio_rev == 4 || phy->radio_rev == 5) { + b43_radio_write16(dev, 0x51, 0x37); + b43_radio_write16(dev, 0x52, 0x70); + b43_radio_write16(dev, 0x53, 0xB3); + b43_radio_write16(dev, 0x54, 0x9B); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x88); + b43_radio_write16(dev, 0x5D, 0x88); + b43_radio_write16(dev, 0x5E, 0x88); + b43_radio_write16(dev, 0x7D, 0x88); + b43_hf_write(dev, b43_hf_read(dev) + | B43_HF_TSSIRPSMW); + } + B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */ + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x51, 0); + b43_radio_write16(dev, 0x52, 0x40); + b43_radio_write16(dev, 0x53, 0xB7); + b43_radio_write16(dev, 0x54, 0x98); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x6B); + b43_radio_write16(dev, 0x5C, 0x0F); + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) { + b43_radio_write16(dev, 0x5D, 0xFA); + b43_radio_write16(dev, 0x5E, 0xD8); + } else { + b43_radio_write16(dev, 0x5D, 0xF5); + b43_radio_write16(dev, 0x5E, 0xB8); + } + b43_radio_write16(dev, 0x0073, 0x0003); + b43_radio_write16(dev, 0x007D, 0x00A8); + b43_radio_write16(dev, 0x007C, 0x0001); + b43_radio_write16(dev, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + b43_phy_write(dev, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == B43_PHYTYPE_G) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) | 0x0004); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + b43_phy_write(dev, 0x5B, 0); + b43_phy_write(dev, 0x5C, 0); + } + + old_channel = phy->channel; + if (old_channel >= 8) + b43_gphy_channel_switch(dev, 1, 0); + else + b43_gphy_channel_switch(dev, 13, 0); + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + udelay(40); + if (phy->radio_rev < 6 || phy->radio_rev == 8) { + b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C) + | 0x0002)); + b43_radio_write16(dev, 0x50, 0x20); + } + if (phy->radio_rev <= 2) { + b43_radio_write16(dev, 0x7C, 0x20); + b43_radio_write16(dev, 0x5A, 0x70); + b43_radio_write16(dev, 0x5B, 0x7B); + b43_radio_write16(dev, 0x5C, 0xB0); + } + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007); + + b43_gphy_channel_switch(dev, old_channel, 0); - if (frequency < 5091) - value = 0x0040; - else if (frequency < 5321) - value = 0x0000; - else if (frequency < 5806) - value = 0x0080; + b43_phy_write(dev, 0x0014, 0x0200); + if (phy->radio_rev >= 6) + b43_phy_write(dev, 0x2A, 0x88C2); else - value = 0x0040; + b43_phy_write(dev, 0x2A, 0x8AC0); + b43_phy_write(dev, 0x0038, 0x0668); + b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control); + if (phy->radio_rev <= 5) { + b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D) + & 0xFF80) | 0x0003); + } + if (phy->radio_rev <= 2) + b43_radio_write16(dev, 0x005D, 0x000D); - return value; + if (phy->analog == 4) { + b43_write16(dev, 0x3E4, 9); + b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61) + & 0x0FFF); + } else { + b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) + | 0x0004); + } + if (phy->type == B43_PHYTYPE_B) + B43_WARN_ON(1); + else if (phy->type == B43_PHYTYPE_G) + b43_write16(dev, 0x03E6, 0x0); } -void b43_radio_set_tx_iq(struct b43_wldev *dev) +static void b43_calc_loopback_gain(struct b43_wldev *dev) { - static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; - static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; - u16 tmp = b43_radio_read16(dev, 0x001E); - int i, j; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 backup_phy[16] = { 0 }; + u16 backup_radio[3]; + u16 backup_bband; + u16 i, j, loop_i_max; + u16 trsw_rx; + u16 loop1_outer_done, loop1_inner_done; - for (i = 0; i < 5; i++) { - for (j = 0; j < 5; j++) { - if (tmp == (data_high[i] << 4 | data_low[j])) { - b43_phy_write(dev, 0x0069, - (i - j) << 8 | 0x00C0); - return; + backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0); + backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); + backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER); + backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); + backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + } + backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A)); + backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59)); + backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58)); + backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A)); + backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03)); + backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); + backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); + backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B)); + backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); + backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + backup_bband = gphy->bbatt.att; + backup_radio[0] = b43_radio_read16(dev, 0x52); + backup_radio[1] = b43_radio_read16(dev, 0x43); + backup_radio[2] = b43_radio_read16(dev, 0x7A); + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, + b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFE); + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFD); + } + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xFFCF) | 0x10); + + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); + + b43_phy_write(dev, B43_PHY_CCK(0x0A), + b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFB); + } + b43_phy_write(dev, B43_PHY_CCK(0x03), + (b43_phy_read(dev, B43_PHY_CCK(0x03)) + & 0xFF9F) | 0x40); + + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, 0x000F); + } else { + b43_radio_write16(dev, 0x52, 0); + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | 0x9); + } + b43_gphy_set_baseband_attenuation(dev, 11); + + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); + b43_phy_write(dev, B43_PHY_LO_CTL, 0); + + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) + & 0xFFC0) | 0x01); + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) + & 0xC0FF) | 0x800); + + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); + + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { + if (phy->rev >= 7) { + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) + | 0x0800); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x8000); + } + } + b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A) + & 0x00F7); + + j = 0; + loop_i_max = (phy->radio_rev == 8) ? 15 : 9; + for (i = 0; i < loop_i_max; i++) { + for (j = 0; j < 16; j++) { + b43_radio_write16(dev, 0x43, i); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop1; + } + } + exit_loop1: + loop1_outer_done = i; + loop1_inner_done = j; + if (j >= 8) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x30); + trsw_rx = 0x1B; + for (j = j - 8; j < 16; j++) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + trsw_rx -= 3; + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop2; + } + } else + trsw_rx = 0x18; + exit_loop2: + + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); + } + b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]); + b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]); + b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]); + b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]); + b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]); + b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); + b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); + b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]); + b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); + + b43_gphy_set_baseband_attenuation(dev, backup_bband); + + b43_radio_write16(dev, 0x52, backup_radio[0]); + b43_radio_write16(dev, 0x43, backup_radio[1]); + b43_radio_write16(dev, 0x7A, backup_radio[2]); + + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003); + udelay(10); + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]); + b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]); + b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]); + + gphy->max_lb_gain = + ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11; + gphy->trsw_rx_gain = trsw_rx * 2; +} + +static void b43_hardware_pctl_early_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!b43_has_hardware_pctl(dev)) { + b43_phy_write(dev, 0x047A, 0xC111); + return; + } + + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF); + b43_phy_write(dev, 0x002F, 0x0202); + b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002); + b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + | 0x8000); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + } else { + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0200); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + & 0x7FFF); + b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F) + & 0xFFFE); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + } +} + +/* Hardware power control for G-PHY */ +static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + + if (!b43_has_hardware_pctl(dev)) { + /* No hardware power control */ + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL); + return; + } + + b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0) + | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); + b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00) + | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); + b43_gphy_tssi_power_lt_init(dev); + b43_gphy_gain_lt_init(dev); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF); + b43_phy_write(dev, 0x0014, 0x0000); + + B43_WARN_ON(phy->rev < 6); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + | 0x0800); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + & 0xFEFF); + b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) + & 0xFFBF); + + b43_gphy_dc_lt_init(dev, 1); + + /* Enable hardware pctl in firmware. */ + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); +} + +/* Intialize B/G PHY power control */ +static void b43_phy_init_pctl(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_rfatt old_rfatt; + struct b43_bbatt old_bbatt; + u8 old_tx_control = 0; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) + return; + + b43_phy_write(dev, 0x0028, 0x8018); + + /* This does something with the Analog... */ + b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0) + & 0xFFDF); + + if (!phy->gmode) + return; + b43_hardware_pctl_early_init(dev); + if (gphy->cur_idle_tssi == 0) { + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + (b43_radio_read16(dev, 0x0076) + & 0x00F7) | 0x0084); + } else { + struct b43_rfatt rfatt; + struct b43_bbatt bbatt; + + memcpy(&old_rfatt, &gphy->rfatt, sizeof(old_rfatt)); + memcpy(&old_bbatt, &gphy->bbatt, sizeof(old_bbatt)); + old_tx_control = gphy->tx_control; + + bbatt.att = 11; + if (phy->radio_rev == 8) { + rfatt.att = 15; + rfatt.with_padmix = 1; + } else { + rfatt.att = 9; + rfatt.with_padmix = 0; } + b43_set_txpower_g(dev, &bbatt, &rfatt, 0); + } + b43_dummy_transmission(dev); + gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); + if (B43_DEBUG) { + /* Current-Idle-TSSI sanity check. */ + if (abs(gphy->cur_idle_tssi - gphy->tgt_idle_tssi) >= 20) { + b43dbg(dev->wl, + "!WARNING! Idle-TSSI phy->cur_idle_tssi " + "measuring failed. (cur=%d, tgt=%d). Disabling TX power " + "adjustment.\n", gphy->cur_idle_tssi, + gphy->tgt_idle_tssi); + gphy->cur_idle_tssi = 0; + } + } + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + b43_radio_read16(dev, 0x0076) + & 0xFF7B); + } else { + b43_set_txpower_g(dev, &old_bbatt, + &old_rfatt, old_tx_control); } } + b43_hardware_pctl_init_gphy(dev); + b43_shm_clear_tssi(dev); } -int b43_radio_selectchannel(struct b43_wldev *dev, - u8 channel, int synthetic_pu_workaround) +static void b43_phy_initg(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - u16 r8, tmp; - u16 freq; - u16 channelcookie, savedcookie; - int err = 0; - - if (channel == 0xFF) { - switch (phy->type) { - case B43_PHYTYPE_A: - channel = B43_DEFAULT_CHANNEL_A; - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - channel = B43_DEFAULT_CHANNEL_BG; - break; - case B43_PHYTYPE_N: - //FIXME check if we are on 2.4GHz or 5GHz and set a default channel. - channel = 1; - break; - default: - B43_WARN_ON(1); + struct b43_phy_g *gphy = phy->g; + u16 tmp; + + if (phy->rev == 1) + b43_phy_initb5(dev); + else + b43_phy_initb6(dev); + + if (phy->rev >= 2 || phy->gmode) + b43_phy_inita(dev); + + if (phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_ANALOGOVER, 0); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0); + } + if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_RFOVER, 0); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->rev > 5) { + b43_phy_write(dev, B43_PHY_RFOVER, 0x400); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->gmode || phy->rev >= 2) { + tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM); + tmp &= B43_PHYVER_VERSION; + if (tmp == 3 || tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); } + if (tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xCC), + (b43_phy_read(dev, B43_PHY_OFDM(0xCC)) + & 0x00FF) | 0x1F00); + } + } + if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) + b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); + if (phy->radio_rev == 8) { + b43_phy_write(dev, B43_PHY_EXTG(0x01), + b43_phy_read(dev, B43_PHY_EXTG(0x01)) + | 0x80); + b43_phy_write(dev, B43_PHY_OFDM(0x3E), + b43_phy_read(dev, B43_PHY_OFDM(0x3E)) + | 0x4); + } + if (has_loopback_gain(phy)) + b43_calc_loopback_gain(dev); + + if (phy->radio_rev != 8) { + if (gphy->initval == 0xFFFF) + gphy->initval = b43_radio_init2050(dev); + else + b43_radio_write16(dev, 0x0078, gphy->initval); + } + b43_lo_g_init(dev); + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFF00) + | gphy->lo_control->tx_bias | gphy-> + lo_control->tx_magn); + } else { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFFF0) + | gphy->lo_control->tx_bias); + } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_CCK(0x36), + (b43_phy_read(dev, B43_PHY_CCK(0x36)) + & 0x0FFF) | (gphy->lo_control-> + tx_bias << 12)); + } + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); + else + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); + if (phy->rev < 2) + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); + else + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); + if (phy->gmode || phy->rev >= 2) { + b43_lo_g_adjust(dev); + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); } - /* First we set the channel radio code to prevent the - * firmware from sending ghost packets. - */ - channelcookie = channel; - if (0 /*FIXME on 5Ghz */) - channelcookie |= 0x100; - //FIXME set 40Mhz flag if required - savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); - - switch (phy->type) { - case B43_PHYTYPE_A: - if (channel > 200) { - err = -EINVAL; - goto out; + if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the clamp_val() in nrssi_hw_update()) + */ + b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? + b43_calc_nrssi_threshold(dev); + } else if (phy->gmode || phy->rev >= 2) { + if (gphy->nrssi[0] == -1000) { + B43_WARN_ON(gphy->nrssi[1] != -1000); + b43_calc_nrssi_slope(dev); + } else + b43_calc_nrssi_threshold(dev); + } + if (phy->radio_rev == 8) + b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230); + b43_phy_init_pctl(dev); + /* FIXME: The spec says in the following if, the 0 should be replaced + 'if OFDM may not be used in the current locale' + but OFDM is legal everywhere */ + if ((dev->dev->bus->chip_id == 0x4306 + && dev->dev->bus->chip_package == 2) || 0) { + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0xBFFF); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), + b43_phy_read(dev, B43_PHY_OFDM(0xC3)) + & 0x7FFF); + } +} + +void b43_gphy_channel_switch(struct b43_wldev *dev, + unsigned int channel, + bool synthetic_pu_workaround) +{ + if (synthetic_pu_workaround) + b43_synth_pu_workaround(dev, channel); + + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); + + if (channel == 14) { + if (dev->dev->bus->sprom.country_code == + SSB_SPROM1CCODE_JAPAN) + b43_hf_write(dev, + b43_hf_read(dev) & ~B43_HF_ACPR); + else + b43_hf_write(dev, + b43_hf_read(dev) | B43_HF_ACPR); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | (1 << 11)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + & 0xF7BF); + } +} + +static void default_baseband_attenuation(struct b43_wldev *dev, + struct b43_bbatt *bb) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) + bb->att = 0; + else + bb->att = 2; +} + +static void default_radio_attenuation(struct b43_wldev *dev, + struct b43_rfatt *rf) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + rf->with_padmix = 0; + + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BCM4309G) { + if (bus->boardinfo.rev < 0x43) { + rf->att = 2; + return; + } else if (bus->boardinfo.rev < 0x51) { + rf->att = 3; + return; } - freq = channel2freq_a(channel); - - r8 = b43_radio_read16(dev, 0x0008); - b43_write16(dev, 0x03F0, freq); - b43_radio_write16(dev, 0x0008, r8); - - //TODO: write max channel TX power? to Radio 0x2D - tmp = b43_radio_read16(dev, 0x002E); - tmp &= 0x0080; - //TODO: OR tmp with the Power out estimation for this channel? - b43_radio_write16(dev, 0x002E, tmp); - - if (freq >= 4920 && freq <= 5500) { - /* - * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; - * = (freq * 0.025862069 - */ - r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ + } + + if (phy->type == B43_PHYTYPE_A) { + rf->att = 0x60; + return; + } + + switch (phy->radio_ver) { + case 0x2053: + switch (phy->radio_rev) { + case 1: + rf->att = 6; + return; } - b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) - & 0x000F) | (r8 << 4)); - b43_radio_write16(dev, 0x002A, (r8 << 4)); - b43_radio_write16(dev, 0x002B, (r8 << 4)); - b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) - & 0x00F0) | (r8 << 4)); - b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) - & 0xFF0F) | 0x00B0); - b43_radio_write16(dev, 0x0035, 0x00AA); - b43_radio_write16(dev, 0x0036, 0x0085); - b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) - & 0xFF20) | - freq_r3A_value(freq)); - b43_radio_write16(dev, 0x003D, - b43_radio_read16(dev, 0x003D) & 0x00FF); - b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) - & 0xFF7F) | 0x0080); - b43_radio_write16(dev, 0x0035, - b43_radio_read16(dev, 0x0035) & 0xFFEF); - b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) - & 0xFFEF) | 0x0010); - b43_radio_set_tx_iq(dev); - //TODO: TSSI2dbm workaround - b43_phy_xmitpower(dev); //FIXME correct? break; - case B43_PHYTYPE_G: - if ((channel < 1) || (channel > 14)) { - err = -EINVAL; - goto out; + case 0x2050: + switch (phy->radio_rev) { + case 0: + rf->att = 5; + return; + case 1: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 3; + else + rf->att = 1; + } else { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 7; + else + rf->att = 6; + } + return; + case 2: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 5; + else if (bus->chip_id == 0x4320) + rf->att = 4; + else + rf->att = 3; + } else + rf->att = 6; + return; + case 3: + rf->att = 5; + return; + case 4: + case 5: + rf->att = 1; + return; + case 6: + case 7: + rf->att = 5; + return; + case 8: + rf->att = 0xA; + rf->with_padmix = 1; + return; + case 9: + default: + rf->att = 5; + return; } + } + rf->att = 5; +} - if (synthetic_pu_workaround) - b43_synth_pu_workaround(dev, channel); +static u16 default_tx_control(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; - b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); + if (phy->radio_ver != 0x2050) + return 0; + if (phy->radio_rev == 1) + return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX; + if (phy->radio_rev < 6) + return B43_TXCTL_PA2DB; + if (phy->radio_rev == 8) + return B43_TXCTL_TXMIX; + return 0; +} - if (channel == 14) { - if (dev->dev->bus->sprom.country_code == - SSB_SPROM1CCODE_JAPAN) - b43_hf_write(dev, - b43_hf_read(dev) & ~B43_HF_ACPR); - else - b43_hf_write(dev, - b43_hf_read(dev) | B43_HF_ACPR); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, B43_MMIO_CHANNEL_EXT) - | (1 << 11)); - } else { - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, B43_MMIO_CHANNEL_EXT) - & 0xF7BF); +static u8 b43_gphy_aci_detect(struct b43_wldev *dev, u8 channel) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u8 ret = 0; + u16 saved, rssi, temp; + int i, j = 0; + + saved = b43_phy_read(dev, 0x0403); + b43_switch_channel(dev, channel); + b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); + if (gphy->aci_hw_rssi) + rssi = b43_phy_read(dev, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0; i < 100; i++) { + temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + b43_phy_write(dev, 0x0403, saved); + + return ret; +} + +static u8 b43_gphy_aci_scan(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u8 ret[13]; + unsigned int channel = phy->channel; + unsigned int i, j, start, end; + + if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + b43_phy_lock(dev); + b43_radio_lock(dev); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_set_all_gains(dev, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i - 1] = b43_gphy_aci_detect(dev, i); + } + b43_switch_channel(dev, channel); + b43_phy_write(dev, 0x0802, + (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003); + b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + b43_set_original_gains(dev); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + b43_radio_unlock(dev); + b43_phy_unlock(dev); + + return ret[channel - 1]; +} + +static s32 b43_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num / den; + else + return (num + den / 2) / den; +} + +static s8 b43_tssi2dbm_entry(s8 entry[], u8 index, + s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1, m2, f = 256, q, delta; + s8 i = 0; + + m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = b43_tssi2dbm_ad(f * 4096 - + b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; +} + +u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev, + s16 pab0, s16 pab1, s16 pab2) +{ + unsigned int i; + u8 *tab; + int err; + + tab = kmalloc(64, GFP_KERNEL); + if (!tab) { + b43err(dev->wl, "Could not allocate memory " + "for tssi2dbm table\n"); + return NULL; + } + for (i = 0; i < 64; i++) { + err = b43_tssi2dbm_entry(tab, i, pab0, pab1, pab2); + if (err) { + b43err(dev->wl, "Could not generate " + "tssi2dBm table\n"); + kfree(tab); + return NULL; } - break; - case B43_PHYTYPE_N: - err = b43_nphy_selectchannel(dev, channel); - if (err) - goto out; - break; - default: - B43_WARN_ON(1); } - phy->channel = channel; - /* Wait for the radio to tune to the channel and stabilize. */ - msleep(8); -out: - if (err) { - b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_CHAN, savedcookie); + return tab; +} + +/* Initialise the TSSI->dBm lookup table */ +static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + s16 pab0, pab1, pab2; + + pab0 = (s16) (dev->dev->bus->sprom.pa0b0); + pab1 = (s16) (dev->dev->bus->sprom.pa0b1); + pab2 = (s16) (dev->dev->bus->sprom.pa0b2); + + B43_WARN_ON((dev->dev->bus->chip_id == 0x4301) && + (phy->radio_ver != 0x2050)); /* Not supported anymore */ + + gphy->dyn_tssi_tbl = 0; + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && + (s8) dev->dev->bus->sprom.itssi_bg != -1) { + gphy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.itssi_bg); + } else + gphy->tgt_idle_tssi = 62; + gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0, + pab1, pab2); + if (!gphy->tssi2dbm) + return -ENOMEM; + gphy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + gphy->tgt_idle_tssi = 52; + gphy->tssi2dbm = b43_tssi2dbm_g_table; } + + return 0; +} + +static int b43_gphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy; + struct b43_txpower_lo_control *lo; + int err; + + gphy = kzalloc(sizeof(*gphy), GFP_KERNEL); + if (!gphy) { + err = -ENOMEM; + goto error; + } + dev->phy.g = gphy; + + lo = kzalloc(sizeof(*lo), GFP_KERNEL); + if (!lo) { + err = -ENOMEM; + goto err_free_gphy; + } + gphy->lo_control = lo; + + err = b43_gphy_init_tssi2dbm_table(dev); + if (err) + goto err_free_lo; + + return 0; + +err_free_lo: + kfree(lo); +err_free_gphy: + kfree(gphy); +error: return err; } -void b43_radio_turn_on(struct b43_wldev *dev) +static void b43_gphy_op_prepare_structs(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - int err; - u8 channel; + struct b43_phy_g *gphy = phy->g; + const void *tssi2dbm; + int tgt_idle_tssi; + struct b43_txpower_lo_control *lo; + unsigned int i; + + /* tssi2dbm table is constant, so it is initialized at alloc time. + * Save a copy of the pointer. */ + tssi2dbm = gphy->tssi2dbm; + tgt_idle_tssi = gphy->tgt_idle_tssi; + /* Save the LO pointer. */ + lo = gphy->lo_control; + + /* Zero out the whole PHY structure. */ + memset(gphy, 0, sizeof(*gphy)); + + /* Restore pointers. */ + gphy->tssi2dbm = tssi2dbm; + gphy->tgt_idle_tssi = tgt_idle_tssi; + gphy->lo_control = lo; + + memset(gphy->minlowsig, 0xFF, sizeof(gphy->minlowsig)); + + /* NRSSI */ + for (i = 0; i < ARRAY_SIZE(gphy->nrssi); i++) + gphy->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(gphy->nrssi_lt); i++) + gphy->nrssi_lt[i] = i; + + gphy->lofcal = 0xFFFF; + gphy->initval = 0xFFFF; + + gphy->interfmode = B43_INTERFMODE_NONE; + + /* OFDM-table address caching. */ + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; + + gphy->average_tssi = 0xFF; + + /* Local Osciallator structure */ + lo->tx_bias = 0xFF; + INIT_LIST_HEAD(&lo->calib_list); +} + +static void b43_gphy_op_free(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + + kfree(gphy->lo_control); + + if (gphy->dyn_tssi_tbl) + kfree(gphy->tssi2dbm); + gphy->dyn_tssi_tbl = 0; + gphy->tssi2dbm = NULL; + + kfree(gphy); + dev->phy.g = NULL; +} + +static int b43_gphy_op_prepare_hardware(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + default_baseband_attenuation(dev, &gphy->bbatt); + default_radio_attenuation(dev, &gphy->rfatt); + gphy->tx_control = (default_tx_control(dev) << 4); + generate_rfatt_list(dev, &lo->rfatt_list); + generate_bbatt_list(dev, &lo->bbatt_list); + + /* Commit previous writes */ + b43_read32(dev, B43_MMIO_MACCTL); + + if (phy->rev == 1) { + /* Workaround: Temporarly disable gmode through the early init + * phase, as the gmode stuff is not needed for phy rev 1 */ + phy->gmode = 0; + b43_wireless_core_reset(dev, 0); + b43_phy_initg(dev); + phy->gmode = 1; + b43_wireless_core_reset(dev, B43_TMSLOW_GMODE); + } + + return 0; +} + +static int b43_gphy_op_init(struct b43_wldev *dev) +{ + b43_phy_initg(dev); + + return 0; +} + +static void b43_gphy_op_exit(struct b43_wldev *dev) +{ + b43_lo_g_cleanup(dev); +} + +static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* G-PHY needs 0x80 for read access. */ + reg |= 0x80; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev) +{ + return (dev->phy.rev >= 6); +} + +static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + unsigned int channel; might_sleep(); - if (phy->radio_on) - return; + if (state == RFKILL_STATE_UNBLOCKED) { + /* Turn radio ON */ + if (phy->radio_on) + return; - switch (phy->type) { - case B43_PHYTYPE_A: - b43_radio_write16(dev, 0x0004, 0x00C0); - b43_radio_write16(dev, 0x0005, 0x0008); - b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7); - b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7); - b43_radio_init2060(dev); - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: b43_phy_write(dev, 0x0015, 0x8000); b43_phy_write(dev, 0x0015, 0xCC00); b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); - if (phy->radio_off_context.valid) { + if (gphy->radio_off_context.valid) { /* Restore the RFover values. */ b43_phy_write(dev, B43_PHY_RFOVER, - phy->radio_off_context.rfover); + gphy->radio_off_context.rfover); b43_phy_write(dev, B43_PHY_RFOVERVAL, - phy->radio_off_context.rfoverval); - phy->radio_off_context.valid = 0; + gphy->radio_off_context.rfoverval); + gphy->radio_off_context.valid = 0; } channel = phy->channel; - err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1); - err |= b43_radio_selectchannel(dev, channel, 0); - B43_WARN_ON(err); - break; - case B43_PHYTYPE_N: - b43_nphy_radio_turn_on(dev); - break; - default: - B43_WARN_ON(1); + b43_gphy_channel_switch(dev, 6, 1); + b43_gphy_channel_switch(dev, channel, 0); + } else { + /* Turn radio OFF */ + u16 rfover, rfoverval; + + rfover = b43_phy_read(dev, B43_PHY_RFOVER); + rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + gphy->radio_off_context.rfover = rfover; + gphy->radio_off_context.rfoverval = rfoverval; + gphy->radio_off_context.valid = 1; + b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); } - phy->radio_on = 1; } -void b43_radio_turn_off(struct b43_wldev *dev, bool force) +static int b43_gphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if ((new_channel < 1) || (new_channel > 14)) + return -EINVAL; + b43_gphy_channel_switch(dev, new_channel, 0); + + return 0; +} + +static unsigned int b43_gphy_op_get_default_chan(struct b43_wldev *dev) +{ + return 1; /* Default to channel 1 */ +} + +static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) { struct b43_phy *phy = &dev->phy; + u64 hf; + u16 tmp; + int autodiv = 0; - if (!phy->radio_on && !force) - return; + if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) + autodiv = 1; + + hf = b43_hf_read(dev); + hf &= ~B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); + + tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + + if (autodiv) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + if (antenna == B43_ANTENNA_AUTO0) + tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; + else + tmp |= B43_PHY_ANTDWELL_AUTODIV1; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } + tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT); + if (autodiv) + tmp |= B43_PHY_ANTWRSETT_ARXDIV; + else + tmp &= ~B43_PHY_ANTWRSETT_ARXDIV; + b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp); + if (phy->rev >= 2) { + tmp = b43_phy_read(dev, B43_PHY_OFDM61); + tmp |= B43_PHY_OFDM61_10; + b43_phy_write(dev, B43_PHY_OFDM61, tmp); + + tmp = + b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK); + tmp = (tmp & 0xFF00) | 0x15; + b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK, + tmp); + + if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_ADIVRELATED, + 8); + } else { + tmp = + b43_phy_read(dev, + B43_PHY_ADIVRELATED); + tmp = (tmp & 0xFF00) | 8; + b43_phy_write(dev, B43_PHY_ADIVRELATED, + tmp); + } + } + if (phy->rev >= 6) + b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); + + hf |= B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); +} - switch (phy->type) { - case B43_PHYTYPE_N: - b43_nphy_radio_turn_off(dev); +static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev, + enum b43_interference_mitigation mode) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + int currentmode; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + if ((phy->rev == 0) || (!phy->gmode)) + return -ENODEV; + + gphy->aci_wlan_automatic = 0; + switch (mode) { + case B43_INTERFMODE_AUTOWLAN: + gphy->aci_wlan_automatic = 1; + if (gphy->aci_enable) + mode = B43_INTERFMODE_MANUALWLAN; + else + mode = B43_INTERFMODE_NONE; break; - case B43_PHYTYPE_A: - b43_radio_write16(dev, 0x0004, 0x00FF); - b43_radio_write16(dev, 0x0005, 0x00FB); - b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008); - b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); + case B43_INTERFMODE_NONE: + case B43_INTERFMODE_NONWLAN: + case B43_INTERFMODE_MANUALWLAN: break; - case B43_PHYTYPE_G: { - u16 rfover, rfoverval; + default: + return -EINVAL; + } - rfover = b43_phy_read(dev, B43_PHY_RFOVER); - rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); - if (!force) { - phy->radio_off_context.rfover = rfover; - phy->radio_off_context.rfoverval = rfoverval; - phy->radio_off_context.valid = 1; + currentmode = gphy->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != B43_INTERFMODE_NONE) + b43_radio_interference_mitigation_disable(dev, currentmode); + + if (mode == B43_INTERFMODE_NONE) { + gphy->aci_enable = 0; + gphy->aci_hw_rssi = 0; + } else + b43_radio_interference_mitigation_enable(dev, mode); + gphy->interfmode = mode; + + return 0; +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 b43_gphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) +{ + struct b43_phy_g *gphy = dev->phy.g; + s8 dbm; + s32 tmp; + + tmp = (gphy->tgt_idle_tssi - gphy->cur_idle_tssi + tssi); + tmp = clamp_val(tmp, 0x00, 0x3F); + dbm = gphy->tssi2dbm[tmp]; + + return dbm; +} + +static void b43_put_attenuation_into_ranges(struct b43_wldev *dev, + int *_bbatt, int *_rfatt) +{ + int rfatt = *_rfatt; + int bbatt = *_bbatt; + struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; + + /* Get baseband and radio attenuation values into their permitted ranges. + * Radio attenuation affects power level 4 times as much as baseband. */ + + /* Range constants */ + const int rf_min = lo->rfatt_list.min_val; + const int rf_max = lo->rfatt_list.max_val; + const int bb_min = lo->bbatt_list.min_val; + const int bb_max = lo->bbatt_list.max_val; + + while (1) { + if (rfatt > rf_max && bbatt > bb_max - 4) + break; /* Can not get it into ranges */ + if (rfatt < rf_min && bbatt < bb_min + 4) + break; /* Can not get it into ranges */ + if (bbatt > bb_max && rfatt > rf_max - 1) + break; /* Can not get it into ranges */ + if (bbatt < bb_min && rfatt < rf_min + 1) + break; /* Can not get it into ranges */ + + if (bbatt > bb_max) { + bbatt -= 4; + rfatt += 1; + continue; + } + if (bbatt < bb_min) { + bbatt += 4; + rfatt -= 1; + continue; + } + if (rfatt > rf_max) { + rfatt -= 1; + bbatt += 4; + continue; + } + if (rfatt < rf_min) { + rfatt += 1; + bbatt -= 4; + continue; } - b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); - b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); break; } - default: - B43_WARN_ON(1); + + *_rfatt = clamp_val(rfatt, rf_min, rf_max); + *_bbatt = clamp_val(bbatt, bb_min, bb_max); +} + +static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + int rfatt, bbatt; + u8 tx_control; + + spin_lock_irq(&dev->wl->irq_lock); + + /* Calculate the new attenuation values. */ + bbatt = gphy->bbatt.att; + bbatt += gphy->bbatt_delta; + rfatt = gphy->rfatt.att; + rfatt += gphy->rfatt_delta; + + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + tx_control = gphy->tx_control; + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { + if (rfatt <= 1) { + if (tx_control == 0) { + tx_control = + B43_TXCTL_PA2DB | + B43_TXCTL_TXMIX; + rfatt += 2; + bbatt += 2; + } else if (dev->dev->bus->sprom. + boardflags_lo & + B43_BFL_PACTRL) { + bbatt += 4 * (rfatt - 2); + rfatt = 2; + } + } else if (rfatt > 4 && tx_control) { + tx_control = 0; + if (bbatt < 3) { + rfatt -= 3; + bbatt += 2; + } else { + rfatt -= 2; + bbatt -= 2; + } + } } - phy->radio_on = 0; + /* Save the control values */ + gphy->tx_control = tx_control; + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + gphy->rfatt.att = rfatt; + gphy->bbatt.att = bbatt; + + /* We drop the lock early, so we can sleep during hardware + * adjustment. Possible races with op_recalc_txpower are harmless, + * as we will be called once again in case we raced. */ + spin_unlock_irq(&dev->wl->irq_lock); + + if (b43_debug(dev, B43_DBG_XMITPOWER)) + b43dbg(dev->wl, "Adjusting TX power\n"); + + /* Adjust the hardware */ + b43_phy_lock(dev); + b43_radio_lock(dev); + b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, + gphy->tx_control); + b43_radio_unlock(dev); + b43_phy_unlock(dev); } + +static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + unsigned int average_tssi; + int cck_result, ofdm_result; + int estimated_pwr, desired_pwr, pwr_adjust; + int rfatt_delta, bbatt_delta; + unsigned int max_pwr; + + /* First get the average TSSI */ + cck_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_CCK); + ofdm_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_OFDM_G); + if ((cck_result < 0) && (ofdm_result < 0)) { + /* No TSSI information available */ + if (!ignore_tssi) + goto no_adjustment_needed; + cck_result = 0; + ofdm_result = 0; + } + if (cck_result < 0) + average_tssi = ofdm_result; + else if (ofdm_result < 0) + average_tssi = cck_result; + else + average_tssi = (cck_result + ofdm_result) / 2; + /* Merge the average with the stored value. */ + if (likely(gphy->average_tssi != 0xFF)) + average_tssi = (average_tssi + gphy->average_tssi) / 2; + gphy->average_tssi = average_tssi; + B43_WARN_ON(average_tssi >= B43_TSSI_MAX); + + /* Estimate the TX power emission based on the TSSI */ + estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi); + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + max_pwr = dev->dev->bus->sprom.maxpwr_bg; + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + max_pwr -= 3; /* minus 0.75 */ + if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) { + b43warn(dev->wl, + "Invalid max-TX-power value in SPROM.\n"); + max_pwr = INT_TO_Q52(20); /* fake it */ + dev->dev->bus->sprom.maxpwr_bg = max_pwr; + } + + /* Get desired power (in Q5.2) */ + if (phy->desired_txpower < 0) + desired_pwr = INT_TO_Q52(0); + else + desired_pwr = INT_TO_Q52(phy->desired_txpower); + /* And limit it. max_pwr already is Q5.2 */ + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, + "[TX power] current = " Q52_FMT + " dBm, desired = " Q52_FMT + " dBm, max = " Q52_FMT "\n", + Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr), + Q52_ARG(max_pwr)); + } + + /* Calculate the adjustment delta. */ + pwr_adjust = desired_pwr - estimated_pwr; + if (pwr_adjust == 0) + goto no_adjustment_needed; + + /* RF attenuation delta. */ + rfatt_delta = ((pwr_adjust + 7) / 8); + /* Lower attenuation => Bigger power output. Negate it. */ + rfatt_delta = -rfatt_delta; + + /* Baseband attenuation delta. */ + bbatt_delta = pwr_adjust / 2; + /* Lower attenuation => Bigger power output. Negate it. */ + bbatt_delta = -bbatt_delta; + /* RF att affects power level 4 times as much as + * Baseband attennuation. Subtract it. */ + bbatt_delta -= 4 * rfatt_delta; + + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + int dbm = pwr_adjust < 0 ? -pwr_adjust : pwr_adjust; + b43dbg(dev->wl, + "[TX power deltas] %s" Q52_FMT " dBm => " + "bbatt-delta = %d, rfatt-delta = %d\n", + (pwr_adjust < 0 ? "-" : ""), Q52_ARG(dbm), + bbatt_delta, rfatt_delta); + } + /* So do we finally need to adjust something in hardware? */ + if ((rfatt_delta == 0) && (bbatt_delta == 0)) + goto no_adjustment_needed; + + /* Save the deltas for later when we adjust the power. */ + gphy->bbatt_delta = bbatt_delta; + gphy->rfatt_delta = rfatt_delta; + + /* We need to adjust the TX power on the device. */ + return B43_TXPWR_RES_NEED_ADJUST; + +no_adjustment_needed: + return B43_TXPWR_RES_DONE; +} + +static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + + //TODO: update_aci_moving_average + if (gphy->aci_enable && gphy->aci_wlan_automatic) { + b43_mac_suspend(dev); + if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) { + if (0 /*TODO: bunch of conditions */ ) { + phy->ops->interf_mitigation(dev, + B43_INTERFMODE_MANUALWLAN); + } + } else if (0 /*TODO*/) { + if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev)) + phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE); + } + b43_mac_enable(dev); + } else if (gphy->interfmode == B43_INTERFMODE_NONWLAN && + phy->rev == 1) { + //TODO: implement rev1 workaround + } + b43_lo_g_maintanance_work(dev); +} + +static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) + return; + + b43_mac_suspend(dev); + b43_calc_nrssi_slope(dev); + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { + u8 old_chan = phy->channel; + + /* VCO Calibration */ + if (old_chan >= 8) + b43_switch_channel(dev, 1); + else + b43_switch_channel(dev, 13); + b43_switch_channel(dev, old_chan); + } + b43_mac_enable(dev); +} + +const struct b43_phy_operations b43_phyops_g = { + .allocate = b43_gphy_op_allocate, + .free = b43_gphy_op_free, + .prepare_structs = b43_gphy_op_prepare_structs, + .prepare_hardware = b43_gphy_op_prepare_hardware, + .init = b43_gphy_op_init, + .exit = b43_gphy_op_exit, + .phy_read = b43_gphy_op_read, + .phy_write = b43_gphy_op_write, + .radio_read = b43_gphy_op_radio_read, + .radio_write = b43_gphy_op_radio_write, + .supports_hwpctl = b43_gphy_op_supports_hwpctl, + .software_rfkill = b43_gphy_op_software_rfkill, + .switch_analog = b43_phyop_switch_analog_generic, + .switch_channel = b43_gphy_op_switch_channel, + .get_default_chan = b43_gphy_op_get_default_chan, + .set_rx_antenna = b43_gphy_op_set_rx_antenna, + .interf_mitigation = b43_gphy_op_interf_mitigation, + .recalc_txpower = b43_gphy_op_recalc_txpower, + .adjust_txpower = b43_gphy_op_adjust_txpower, + .pwork_15sec = b43_gphy_op_pwork_15sec, + .pwork_60sec = b43_gphy_op_pwork_60sec, +}; diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h new file mode 100644 index 00000000000..718947fd41a --- /dev/null +++ b/drivers/net/wireless/b43/phy_g.h @@ -0,0 +1,209 @@ +#ifndef LINUX_B43_PHY_G_H_ +#define LINUX_B43_PHY_G_H_ + +/* OFDM PHY registers are defined in the A-PHY header. */ +#include "phy_a.h" + +/* CCK (B) PHY Registers */ +#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */ +#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */ +#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */ +#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ +#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ +#define B43_PHY_PGACTL_UNKNOWN 0xEFA0 +#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */ +#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */ +#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */ +#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */ +#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35) +#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */ +#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */ +#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */ + +/* Extended G-PHY Registers */ +#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ +#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */ +#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ +#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ +#define B43_PHY_GTABNR_SHIFT 10 +#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */ +#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */ +#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */ +#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */ +#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */ +#define B43_PHY_RFOVERVAL_EXTLNA 0x8000 +#define B43_PHY_RFOVERVAL_LNA 0x7000 +#define B43_PHY_RFOVERVAL_LNA_SHIFT 12 +#define B43_PHY_RFOVERVAL_PGA 0x0F00 +#define B43_PHY_RFOVERVAL_PGA_SHIFT 8 +#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */ +#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0 +#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */ +#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */ +#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */ +#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */ +#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */ + + +/*** G-PHY table numbers */ +#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset)) +#define B43_GTAB_NRSSI B43_GTAB(0x00, 0) +#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120) +#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298) + +u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); +void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); + + +/* Returns the boolean whether "TX Magnification" is enabled. */ +#define has_tx_magnification(phy) \ + (((phy)->rev >= 2) && \ + ((phy)->radio_ver == 0x2050) && \ + ((phy)->radio_rev == 8)) +/* Card uses the loopback gain stuff */ +#define has_loopback_gain(phy) \ + (((phy)->rev > 1) || ((phy)->gmode)) + +/* Radio Attenuation (RF Attenuation) */ +struct b43_rfatt { + u8 att; /* Attenuation value */ + bool with_padmix; /* Flag, PAD Mixer enabled. */ +}; +struct b43_rfatt_list { + /* Attenuation values list */ + const struct b43_rfatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* Returns true, if the values are the same. */ +static inline bool b43_compare_rfatt(const struct b43_rfatt *a, + const struct b43_rfatt *b) +{ + return ((a->att == b->att) && + (a->with_padmix == b->with_padmix)); +} + +/* Baseband Attenuation */ +struct b43_bbatt { + u8 att; /* Attenuation value */ +}; +struct b43_bbatt_list { + /* Attenuation values list */ + const struct b43_bbatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* Returns true, if the values are the same. */ +static inline bool b43_compare_bbatt(const struct b43_bbatt *a, + const struct b43_bbatt *b) +{ + return (a->att == b->att); +} + +/* tx_control bits. */ +#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ +#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ +#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */ + +struct b43_txpower_lo_control; + +struct b43_phy_g { + /* ACI (adjacent channel interference) flags. */ + bool aci_enable; + bool aci_wlan_automatic; + bool aci_hw_rssi; + + /* Radio switched on/off */ + bool radio_on; + struct { + /* Values saved when turning the radio off. + * They are needed when turning it on again. */ + bool valid; + u16 rfover; + u16 rfoverval; + } radio_off_context; + + u16 minlowsig[2]; + u16 minlowsigpos[2]; + + /* Pointer to the table used to convert a + * TSSI value to dBm-Q5.2 */ + const s8 *tssi2dbm; + /* tssi2dbm is kmalloc()ed. Only used for free()ing. */ + bool dyn_tssi_tbl; + /* Target idle TSSI */ + int tgt_idle_tssi; + /* Current idle TSSI */ + int cur_idle_tssi; + /* The current average TSSI. + * Needs irq_lock, as it's updated in the IRQ path. */ + u8 average_tssi; + /* Current TX power level attenuation control values */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + u8 tx_control; /* B43_TXCTL_XXX */ + /* The calculated attenuation deltas that are used later + * when adjusting the actual power output. */ + int bbatt_delta; + int rfatt_delta; + + /* LocalOscillator control values. */ + struct b43_txpower_lo_control *lo_control; + /* Values from b43_calc_loopback_gain() */ + s16 max_lb_gain; /* Maximum Loopback gain in hdB */ + s16 trsw_rx_gain; /* TRSW RX gain in hdB */ + s16 lna_lod_gain; /* LNA lod */ + s16 lna_gain; /* LNA */ + s16 pga_gain; /* PGA */ + + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define B43_INTERFSTACK_SIZE 26 + u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure + + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + u16 lofcal; + + u16 initval; //FIXME rename? + + /* The device does address auto increment for the OFDM tables. + * We cache the previously used address here and omit the address + * write on the next table access, if possible. */ + u16 ofdmtab_addr; /* The address currently set in hardware. */ + enum { /* The last data flow direction. */ + B43_OFDMTAB_DIRECTION_UNKNOWN = 0, + B43_OFDMTAB_DIRECTION_READ, + B43_OFDMTAB_DIRECTION_WRITE, + } ofdmtab_addr_direction; +}; + +void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation); +void b43_gphy_channel_switch(struct b43_wldev *dev, + unsigned int channel, + bool synthetic_pu_workaround); +u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev, + s16 pab0, s16 pab1, s16 pab2); + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_g; + +#endif /* LINUX_B43_PHY_G_H_ */ diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c new file mode 100644 index 00000000000..c5d9dc3667c --- /dev/null +++ b/drivers/net/wireless/b43/phy_lp.c @@ -0,0 +1,155 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11g LP-PHY driver + + Copyright (c) 2008 Michael Buesch <mb@bu3sch.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, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "phy_lp.h" +#include "phy_common.h" + + +static int b43_lpphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy; + + lpphy = kzalloc(sizeof(*lpphy), GFP_KERNEL); + if (!lpphy) + return -ENOMEM; + dev->phy.lp = lpphy; + + return 0; +} + +static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_lp *lpphy = phy->lp; + + memset(lpphy, 0, sizeof(*lpphy)); + + //TODO +} + +static void b43_lpphy_op_free(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + kfree(lpphy); + dev->phy.lp = NULL; +} + +static int b43_lpphy_op_init(struct b43_wldev *dev) +{ + //TODO + + return 0; +} + +static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* LP-PHY needs a special bit set for read access */ + if (dev->phy.rev < 2) { + if (reg != 0x4001) + reg |= 0x100; + } else + reg |= 0x200; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{ + //TODO +} + +static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + //TODO + return 0; +} + +static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) +{ + return 1; /* Default to channel 1 */ +} + +static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) +{ + //TODO +} + +static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev) +{ + //TODO +} + +static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{ + //TODO + return B43_TXPWR_RES_DONE; +} + + +const struct b43_phy_operations b43_phyops_lp = { + .allocate = b43_lpphy_op_allocate, + .free = b43_lpphy_op_free, + .prepare_structs = b43_lpphy_op_prepare_structs, + .init = b43_lpphy_op_init, + .phy_read = b43_lpphy_op_read, + .phy_write = b43_lpphy_op_write, + .radio_read = b43_lpphy_op_radio_read, + .radio_write = b43_lpphy_op_radio_write, + .software_rfkill = b43_lpphy_op_software_rfkill, + .switch_analog = b43_phyop_switch_analog_generic, + .switch_channel = b43_lpphy_op_switch_channel, + .get_default_chan = b43_lpphy_op_get_default_chan, + .set_rx_antenna = b43_lpphy_op_set_rx_antenna, + .recalc_txpower = b43_lpphy_op_recalc_txpower, + .adjust_txpower = b43_lpphy_op_adjust_txpower, +}; diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h new file mode 100644 index 00000000000..b0b5357abf9 --- /dev/null +++ b/drivers/net/wireless/b43/phy_lp.h @@ -0,0 +1,540 @@ +#ifndef LINUX_B43_PHY_LP_H_ +#define LINUX_B43_PHY_LP_H_ + +/* Definitions for the LP-PHY */ + + + + +#define B43_LP_RADIO(radio_reg) (radio_reg) +#define B43_LP_NORTH(radio_reg) B43_LP_RADIO(radio_reg) +#define B43_LP_SOUTH(radio_reg) B43_LP_RADIO((radio_reg) | 0x4000) + + +/*** Broadcom 2062 NORTH radio registers ***/ +#define B2062_N_COMM1 B43_LP_NORTH(0x000) /* Common 01 (north) */ +#define B2062_N_COMM2 B43_LP_NORTH(0x002) /* Common 02 (north) */ +#define B2062_N_COMM3 B43_LP_NORTH(0x003) /* Common 03 (north) */ +#define B2062_N_COMM4 B43_LP_NORTH(0x004) /* Common 04 (north) */ +#define B2062_N_COMM5 B43_LP_NORTH(0x005) /* Common 05 (north) */ +#define B2062_N_COMM6 B43_LP_NORTH(0x006) /* Common 06 (north) */ +#define B2062_N_COMM7 B43_LP_NORTH(0x007) /* Common 07 (north) */ +#define B2062_N_COMM8 B43_LP_NORTH(0x008) /* Common 08 (north) */ +#define B2062_N_COMM9 B43_LP_NORTH(0x009) /* Common 09 (north) */ +#define B2062_N_COMM10 B43_LP_NORTH(0x00A) /* Common 10 (north) */ +#define B2062_N_COMM11 B43_LP_NORTH(0x00B) /* Common 11 (north) */ +#define B2062_N_COMM12 B43_LP_NORTH(0x00C) /* Common 12 (north) */ +#define B2062_N_COMM13 B43_LP_NORTH(0x00D) /* Common 13 (north) */ +#define B2062_N_COMM14 B43_LP_NORTH(0x00E) /* Common 14 (north) */ +#define B2062_N_COMM15 B43_LP_NORTH(0x00F) /* Common 15 (north) */ +#define B2062_N_PDN_CTL0 B43_LP_NORTH(0x010) /* PDN Control 0 (north) */ +#define B2062_N_PDN_CTL1 B43_LP_NORTH(0x011) /* PDN Control 1 (north) */ +#define B2062_N_PDN_CTL2 B43_LP_NORTH(0x012) /* PDN Control 2 (north) */ +#define B2062_N_PDN_CTL3 B43_LP_NORTH(0x013) /* PDN Control 3 (north) */ +#define B2062_N_PDN_CTL4 B43_LP_NORTH(0x014) /* PDN Control 4 (north) */ +#define B2062_N_GEN_CTL0 B43_LP_NORTH(0x015) /* GEN Control 0 (north) */ +#define B2062_N_IQ_CALIB B43_LP_NORTH(0x016) /* IQ Calibration (north) */ +#define B2062_N_LGENC B43_LP_NORTH(0x017) /* LGENC (north) */ +#define B2062_N_LGENA_LPF B43_LP_NORTH(0x018) /* LGENA LPF (north) */ +#define B2062_N_LGENA_BIAS0 B43_LP_NORTH(0x019) /* LGENA Bias 0 (north) */ +#define B2062_N_LGNEA_BIAS1 B43_LP_NORTH(0x01A) /* LGNEA Bias 1 (north) */ +#define B2062_N_LGENA_CTL0 B43_LP_NORTH(0x01B) /* LGENA Control 0 (north) */ +#define B2062_N_LGENA_CTL1 B43_LP_NORTH(0x01C) /* LGENA Control 1 (north) */ +#define B2062_N_LGENA_CTL2 B43_LP_NORTH(0x01D) /* LGENA Control 2 (north) */ +#define B2062_N_LGENA_TUNE0 B43_LP_NORTH(0x01E) /* LGENA Tune 0 (north) */ +#define B2062_N_LGENA_TUNE1 B43_LP_NORTH(0x01F) /* LGENA Tune 1 (north) */ +#define B2062_N_LGENA_TUNE2 B43_LP_NORTH(0x020) /* LGENA Tune 2 (north) */ +#define B2062_N_LGENA_TUNE3 B43_LP_NORTH(0x021) /* LGENA Tune 3 (north) */ +#define B2062_N_LGENA_CTL3 B43_LP_NORTH(0x022) /* LGENA Control 3 (north) */ +#define B2062_N_LGENA_CTL4 B43_LP_NORTH(0x023) /* LGENA Control 4 (north) */ +#define B2062_N_LGENA_CTL5 B43_LP_NORTH(0x024) /* LGENA Control 5 (north) */ +#define B2062_N_LGENA_CTL6 B43_LP_NORTH(0x025) /* LGENA Control 6 (north) */ +#define B2062_N_LGENA_CTL7 B43_LP_NORTH(0x026) /* LGENA Control 7 (north) */ +#define B2062_N_RXA_CTL0 B43_LP_NORTH(0x027) /* RXA Control 0 (north) */ +#define B2062_N_RXA_CTL1 B43_LP_NORTH(0x028) /* RXA Control 1 (north) */ +#define B2062_N_RXA_CTL2 B43_LP_NORTH(0x029) /* RXA Control 2 (north) */ +#define B2062_N_RXA_CTL3 B43_LP_NORTH(0x02A) /* RXA Control 3 (north) */ +#define B2062_N_RXA_CTL4 B43_LP_NORTH(0x02B) /* RXA Control 4 (north) */ +#define B2062_N_RXA_CTL5 B43_LP_NORTH(0x02C) /* RXA Control 5 (north) */ +#define B2062_N_RXA_CTL6 B43_LP_NORTH(0x02D) /* RXA Control 6 (north) */ +#define B2062_N_RXA_CTL7 B43_LP_NORTH(0x02E) /* RXA Control 7 (north) */ +#define B2062_N_RXBB_CTL0 B43_LP_NORTH(0x02F) /* RXBB Control 0 (north) */ +#define B2062_N_RXBB_CTL1 B43_LP_NORTH(0x030) /* RXBB Control 1 (north) */ +#define B2062_N_RXBB_CTL2 B43_LP_NORTH(0x031) /* RXBB Control 2 (north) */ +#define B2062_N_RXBB_GAIN0 B43_LP_NORTH(0x032) /* RXBB Gain 0 (north) */ +#define B2062_N_RXBB_GAIN1 B43_LP_NORTH(0x033) /* RXBB Gain 1 (north) */ +#define B2062_N_RXBB_GAIN2 B43_LP_NORTH(0x034) /* RXBB Gain 2 (north) */ +#define B2062_N_RXBB_GAIN3 B43_LP_NORTH(0x035) /* RXBB Gain 3 (north) */ +#define B2062_N_RXBB_RSSI0 B43_LP_NORTH(0x036) /* RXBB RSSI 0 (north) */ +#define B2062_N_RXBB_RSSI1 B43_LP_NORTH(0x037) /* RXBB RSSI 1 (north) */ +#define B2062_N_RXBB_CALIB0 B43_LP_NORTH(0x038) /* RXBB Calibration0 (north) */ +#define B2062_N_RXBB_CALIB1 B43_LP_NORTH(0x039) /* RXBB Calibration1 (north) */ +#define B2062_N_RXBB_CALIB2 B43_LP_NORTH(0x03A) /* RXBB Calibration2 (north) */ +#define B2062_N_RXBB_BIAS0 B43_LP_NORTH(0x03B) /* RXBB Bias 0 (north) */ +#define B2062_N_RXBB_BIAS1 B43_LP_NORTH(0x03C) /* RXBB Bias 1 (north) */ +#define B2062_N_RXBB_BIAS2 B43_LP_NORTH(0x03D) /* RXBB Bias 2 (north) */ +#define B2062_N_RXBB_BIAS3 B43_LP_NORTH(0x03E) /* RXBB Bias 3 (north) */ +#define B2062_N_RXBB_BIAS4 B43_LP_NORTH(0x03F) /* RXBB Bias 4 (north) */ +#define B2062_N_RXBB_BIAS5 B43_LP_NORTH(0x040) /* RXBB Bias 5 (north) */ +#define B2062_N_RXBB_RSSI2 B43_LP_NORTH(0x041) /* RXBB RSSI 2 (north) */ +#define B2062_N_RXBB_RSSI3 B43_LP_NORTH(0x042) /* RXBB RSSI 3 (north) */ +#define B2062_N_RXBB_RSSI4 B43_LP_NORTH(0x043) /* RXBB RSSI 4 (north) */ +#define B2062_N_RXBB_RSSI5 B43_LP_NORTH(0x044) /* RXBB RSSI 5 (north) */ +#define B2062_N_TX_CTL0 B43_LP_NORTH(0x045) /* TX Control 0 (north) */ +#define B2062_N_TX_CTL1 B43_LP_NORTH(0x046) /* TX Control 1 (north) */ +#define B2062_N_TX_CTL2 B43_LP_NORTH(0x047) /* TX Control 2 (north) */ +#define B2062_N_TX_CTL3 B43_LP_NORTH(0x048) /* TX Control 3 (north) */ +#define B2062_N_TX_CTL4 B43_LP_NORTH(0x049) /* TX Control 4 (north) */ +#define B2062_N_TX_CTL5 B43_LP_NORTH(0x04A) /* TX Control 5 (north) */ +#define B2062_N_TX_CTL6 B43_LP_NORTH(0x04B) /* TX Control 6 (north) */ +#define B2062_N_TX_CTL7 B43_LP_NORTH(0x04C) /* TX Control 7 (north) */ +#define B2062_N_TX_CTL8 B43_LP_NORTH(0x04D) /* TX Control 8 (north) */ +#define B2062_N_TX_CTL9 B43_LP_NORTH(0x04E) /* TX Control 9 (north) */ +#define B2062_N_TX_CTL_A B43_LP_NORTH(0x04F) /* TX Control A (north) */ +#define B2062_N_TX_GC2G B43_LP_NORTH(0x050) /* TX GC2G (north) */ +#define B2062_N_TX_GC5G B43_LP_NORTH(0x051) /* TX GC5G (north) */ +#define B2062_N_TX_TUNE B43_LP_NORTH(0x052) /* TX Tune (north) */ +#define B2062_N_TX_PAD B43_LP_NORTH(0x053) /* TX PAD (north) */ +#define B2062_N_TX_PGA B43_LP_NORTH(0x054) /* TX PGA (north) */ +#define B2062_N_TX_PADAUX B43_LP_NORTH(0x055) /* TX PADAUX (north) */ +#define B2062_N_TX_PGAAUX B43_LP_NORTH(0x056) /* TX PGAAUX (north) */ +#define B2062_N_TSSI_CTL0 B43_LP_NORTH(0x057) /* TSSI Control 0 (north) */ +#define B2062_N_TSSI_CTL1 B43_LP_NORTH(0x058) /* TSSI Control 1 (north) */ +#define B2062_N_TSSI_CTL2 B43_LP_NORTH(0x059) /* TSSI Control 2 (north) */ +#define B2062_N_IQ_CALIB_CTL0 B43_LP_NORTH(0x05A) /* IQ Calibration Control 0 (north) */ +#define B2062_N_IQ_CALIB_CTL1 B43_LP_NORTH(0x05B) /* IQ Calibration Control 1 (north) */ +#define B2062_N_IQ_CALIB_CTL2 B43_LP_NORTH(0x05C) /* IQ Calibration Control 2 (north) */ +#define B2062_N_CALIB_TS B43_LP_NORTH(0x05D) /* Calibration TS (north) */ +#define B2062_N_CALIB_CTL0 B43_LP_NORTH(0x05E) /* Calibration Control 0 (north) */ +#define B2062_N_CALIB_CTL1 B43_LP_NORTH(0x05F) /* Calibration Control 1 (north) */ +#define B2062_N_CALIB_CTL2 B43_LP_NORTH(0x060) /* Calibration Control 2 (north) */ +#define B2062_N_CALIB_CTL3 B43_LP_NORTH(0x061) /* Calibration Control 3 (north) */ +#define B2062_N_CALIB_CTL4 B43_LP_NORTH(0x062) /* Calibration Control 4 (north) */ +#define B2062_N_CALIB_DBG0 B43_LP_NORTH(0x063) /* Calibration Debug 0 (north) */ +#define B2062_N_CALIB_DBG1 B43_LP_NORTH(0x064) /* Calibration Debug 1 (north) */ +#define B2062_N_CALIB_DBG2 B43_LP_NORTH(0x065) /* Calibration Debug 2 (north) */ +#define B2062_N_CALIB_DBG3 B43_LP_NORTH(0x066) /* Calibration Debug 3 (north) */ +#define B2062_N_PSENSE_CTL0 B43_LP_NORTH(0x069) /* PSENSE Control 0 (north) */ +#define B2062_N_PSENSE_CTL1 B43_LP_NORTH(0x06A) /* PSENSE Control 1 (north) */ +#define B2062_N_PSENSE_CTL2 B43_LP_NORTH(0x06B) /* PSENSE Control 2 (north) */ +#define B2062_N_TEST_BUF0 B43_LP_NORTH(0x06C) /* TEST BUF0 (north) */ + +/*** Broadcom 2062 SOUTH radio registers ***/ +#define B2062_S_COMM1 B43_LP_SOUTH(0x000) /* Common 01 (south) */ +#define B2062_S_RADIO_ID_CODE B43_LP_SOUTH(0x001) /* Radio ID code (south) */ +#define B2062_S_COMM2 B43_LP_SOUTH(0x002) /* Common 02 (south) */ +#define B2062_S_COMM3 B43_LP_SOUTH(0x003) /* Common 03 (south) */ +#define B2062_S_COMM4 B43_LP_SOUTH(0x004) /* Common 04 (south) */ +#define B2062_S_COMM5 B43_LP_SOUTH(0x005) /* Common 05 (south) */ +#define B2062_S_COMM6 B43_LP_SOUTH(0x006) /* Common 06 (south) */ +#define B2062_S_COMM7 B43_LP_SOUTH(0x007) /* Common 07 (south) */ +#define B2062_S_COMM8 B43_LP_SOUTH(0x008) /* Common 08 (south) */ +#define B2062_S_COMM9 B43_LP_SOUTH(0x009) /* Common 09 (south) */ +#define B2062_S_COMM10 B43_LP_SOUTH(0x00A) /* Common 10 (south) */ +#define B2062_S_COMM11 B43_LP_SOUTH(0x00B) /* Common 11 (south) */ +#define B2062_S_COMM12 B43_LP_SOUTH(0x00C) /* Common 12 (south) */ +#define B2062_S_COMM13 B43_LP_SOUTH(0x00D) /* Common 13 (south) */ +#define B2062_S_COMM14 B43_LP_SOUTH(0x00E) /* Common 14 (south) */ +#define B2062_S_COMM15 B43_LP_SOUTH(0x00F) /* Common 15 (south) */ +#define B2062_S_PDS_CTL0 B43_LP_SOUTH(0x010) /* PDS Control 0 (south) */ +#define B2062_S_PDS_CTL1 B43_LP_SOUTH(0x011) /* PDS Control 1 (south) */ +#define B2062_S_PDS_CTL2 B43_LP_SOUTH(0x012) /* PDS Control 2 (south) */ +#define B2062_S_PDS_CTL3 B43_LP_SOUTH(0x013) /* PDS Control 3 (south) */ +#define B2062_S_BG_CTL0 B43_LP_SOUTH(0x014) /* BG Control 0 (south) */ +#define B2062_S_BG_CTL1 B43_LP_SOUTH(0x015) /* BG Control 1 (south) */ +#define B2062_S_BG_CTL2 B43_LP_SOUTH(0x016) /* BG Control 2 (south) */ +#define B2062_S_LGENG_CTL0 B43_LP_SOUTH(0x017) /* LGENG Control 00 (south) */ +#define B2062_S_LGENG_CTL1 B43_LP_SOUTH(0x018) /* LGENG Control 01 (south) */ +#define B2062_S_LGENG_CTL2 B43_LP_SOUTH(0x019) /* LGENG Control 02 (south) */ +#define B2062_S_LGENG_CTL3 B43_LP_SOUTH(0x01A) /* LGENG Control 03 (south) */ +#define B2062_S_LGENG_CTL4 B43_LP_SOUTH(0x01B) /* LGENG Control 04 (south) */ +#define B2062_S_LGENG_CTL5 B43_LP_SOUTH(0x01C) /* LGENG Control 05 (south) */ +#define B2062_S_LGENG_CTL6 B43_LP_SOUTH(0x01D) /* LGENG Control 06 (south) */ +#define B2062_S_LGENG_CTL7 B43_LP_SOUTH(0x01E) /* LGENG Control 07 (south) */ +#define B2062_S_LGENG_CTL8 B43_LP_SOUTH(0x01F) /* LGENG Control 08 (south) */ +#define B2062_S_LGENG_CTL9 B43_LP_SOUTH(0x020) /* LGENG Control 09 (south) */ +#define B2062_S_LGENG_CTL10 B43_LP_SOUTH(0x021) /* LGENG Control 10 (south) */ +#define B2062_S_LGENG_CTL11 B43_LP_SOUTH(0x022) /* LGENG Control 11 (south) */ +#define B2062_S_REFPLL_CTL0 B43_LP_SOUTH(0x023) /* REFPLL Control 00 (south) */ +#define B2062_S_REFPLL_CTL1 B43_LP_SOUTH(0x024) /* REFPLL Control 01 (south) */ +#define B2062_S_REFPLL_CTL2 B43_LP_SOUTH(0x025) /* REFPLL Control 02 (south) */ +#define B2062_S_REFPLL_CTL3 B43_LP_SOUTH(0x026) /* REFPLL Control 03 (south) */ +#define B2062_S_REFPLL_CTL4 B43_LP_SOUTH(0x027) /* REFPLL Control 04 (south) */ +#define B2062_S_REFPLL_CTL5 B43_LP_SOUTH(0x028) /* REFPLL Control 05 (south) */ +#define B2062_S_REFPLL_CTL6 B43_LP_SOUTH(0x029) /* REFPLL Control 06 (south) */ +#define B2062_S_REFPLL_CTL7 B43_LP_SOUTH(0x02A) /* REFPLL Control 07 (south) */ +#define B2062_S_REFPLL_CTL8 B43_LP_SOUTH(0x02B) /* REFPLL Control 08 (south) */ +#define B2062_S_REFPLL_CTL9 B43_LP_SOUTH(0x02C) /* REFPLL Control 09 (south) */ +#define B2062_S_REFPLL_CTL10 B43_LP_SOUTH(0x02D) /* REFPLL Control 10 (south) */ +#define B2062_S_REFPLL_CTL11 B43_LP_SOUTH(0x02E) /* REFPLL Control 11 (south) */ +#define B2062_S_REFPLL_CTL12 B43_LP_SOUTH(0x02F) /* REFPLL Control 12 (south) */ +#define B2062_S_REFPLL_CTL13 B43_LP_SOUTH(0x030) /* REFPLL Control 13 (south) */ +#define B2062_S_REFPLL_CTL14 B43_LP_SOUTH(0x031) /* REFPLL Control 14 (south) */ +#define B2062_S_REFPLL_CTL15 B43_LP_SOUTH(0x032) /* REFPLL Control 15 (south) */ +#define B2062_S_REFPLL_CTL16 B43_LP_SOUTH(0x033) /* REFPLL Control 16 (south) */ +#define B2062_S_RFPLL_CTL0 B43_LP_SOUTH(0x034) /* RFPLL Control 00 (south) */ +#define B2062_S_RFPLL_CTL1 B43_LP_SOUTH(0x035) /* RFPLL Control 01 (south) */ +#define B2062_S_RFPLL_CTL2 B43_LP_SOUTH(0x036) /* RFPLL Control 02 (south) */ +#define B2062_S_RFPLL_CTL3 B43_LP_SOUTH(0x037) /* RFPLL Control 03 (south) */ +#define B2062_S_RFPLL_CTL4 B43_LP_SOUTH(0x038) /* RFPLL Control 04 (south) */ +#define B2062_S_RFPLL_CTL5 B43_LP_SOUTH(0x039) /* RFPLL Control 05 (south) */ +#define B2062_S_RFPLL_CTL6 B43_LP_SOUTH(0x03A) /* RFPLL Control 06 (south) */ +#define B2062_S_RFPLL_CTL7 B43_LP_SOUTH(0x03B) /* RFPLL Control 07 (south) */ +#define B2062_S_RFPLL_CTL8 B43_LP_SOUTH(0x03C) /* RFPLL Control 08 (south) */ +#define B2062_S_RFPLL_CTL9 B43_LP_SOUTH(0x03D) /* RFPLL Control 09 (south) */ +#define B2062_S_RFPLL_CTL10 B43_LP_SOUTH(0x03E) /* RFPLL Control 10 (south) */ +#define B2062_S_RFPLL_CTL11 B43_LP_SOUTH(0x03F) /* RFPLL Control 11 (south) */ +#define B2062_S_RFPLL_CTL12 B43_LP_SOUTH(0x040) /* RFPLL Control 12 (south) */ +#define B2062_S_RFPLL_CTL13 B43_LP_SOUTH(0x041) /* RFPLL Control 13 (south) */ +#define B2062_S_RFPLL_CTL14 B43_LP_SOUTH(0x042) /* RFPLL Control 14 (south) */ +#define B2062_S_RFPLL_CTL15 B43_LP_SOUTH(0x043) /* RFPLL Control 15 (south) */ +#define B2062_S_RFPLL_CTL16 B43_LP_SOUTH(0x044) /* RFPLL Control 16 (south) */ +#define B2062_S_RFPLL_CTL17 B43_LP_SOUTH(0x045) /* RFPLL Control 17 (south) */ +#define B2062_S_RFPLL_CTL18 B43_LP_SOUTH(0x046) /* RFPLL Control 18 (south) */ +#define B2062_S_RFPLL_CTL19 B43_LP_SOUTH(0x047) /* RFPLL Control 19 (south) */ +#define B2062_S_RFPLL_CTL20 B43_LP_SOUTH(0x048) /* RFPLL Control 20 (south) */ +#define B2062_S_RFPLL_CTL21 B43_LP_SOUTH(0x049) /* RFPLL Control 21 (south) */ +#define B2062_S_RFPLL_CTL22 B43_LP_SOUTH(0x04A) /* RFPLL Control 22 (south) */ +#define B2062_S_RFPLL_CTL23 B43_LP_SOUTH(0x04B) /* RFPLL Control 23 (south) */ +#define B2062_S_RFPLL_CTL24 B43_LP_SOUTH(0x04C) /* RFPLL Control 24 (south) */ +#define B2062_S_RFPLL_CTL25 B43_LP_SOUTH(0x04D) /* RFPLL Control 25 (south) */ +#define B2062_S_RFPLL_CTL26 B43_LP_SOUTH(0x04E) /* RFPLL Control 26 (south) */ +#define B2062_S_RFPLL_CTL27 B43_LP_SOUTH(0x04F) /* RFPLL Control 27 (south) */ +#define B2062_S_RFPLL_CTL28 B43_LP_SOUTH(0x050) /* RFPLL Control 28 (south) */ +#define B2062_S_RFPLL_CTL29 B43_LP_SOUTH(0x051) /* RFPLL Control 29 (south) */ +#define B2062_S_RFPLL_CTL30 B43_LP_SOUTH(0x052) /* RFPLL Control 30 (south) */ +#define B2062_S_RFPLL_CTL31 B43_LP_SOUTH(0x053) /* RFPLL Control 31 (south) */ +#define B2062_S_RFPLL_CTL32 B43_LP_SOUTH(0x054) /* RFPLL Control 32 (south) */ +#define B2062_S_RFPLL_CTL33 B43_LP_SOUTH(0x055) /* RFPLL Control 33 (south) */ +#define B2062_S_RFPLL_CTL34 B43_LP_SOUTH(0x056) /* RFPLL Control 34 (south) */ +#define B2062_S_RXG_CNT0 B43_LP_SOUTH(0x057) /* RXG Counter 00 (south) */ +#define B2062_S_RXG_CNT1 B43_LP_SOUTH(0x058) /* RXG Counter 01 (south) */ +#define B2062_S_RXG_CNT2 B43_LP_SOUTH(0x059) /* RXG Counter 02 (south) */ +#define B2062_S_RXG_CNT3 B43_LP_SOUTH(0x05A) /* RXG Counter 03 (south) */ +#define B2062_S_RXG_CNT4 B43_LP_SOUTH(0x05B) /* RXG Counter 04 (south) */ +#define B2062_S_RXG_CNT5 B43_LP_SOUTH(0x05C) /* RXG Counter 05 (south) */ +#define B2062_S_RXG_CNT6 B43_LP_SOUTH(0x05D) /* RXG Counter 06 (south) */ +#define B2062_S_RXG_CNT7 B43_LP_SOUTH(0x05E) /* RXG Counter 07 (south) */ +#define B2062_S_RXG_CNT8 B43_LP_SOUTH(0x05F) /* RXG Counter 08 (south) */ +#define B2062_S_RXG_CNT9 B43_LP_SOUTH(0x060) /* RXG Counter 09 (south) */ +#define B2062_S_RXG_CNT10 B43_LP_SOUTH(0x061) /* RXG Counter 10 (south) */ +#define B2062_S_RXG_CNT11 B43_LP_SOUTH(0x062) /* RXG Counter 11 (south) */ +#define B2062_S_RXG_CNT12 B43_LP_SOUTH(0x063) /* RXG Counter 12 (south) */ +#define B2062_S_RXG_CNT13 B43_LP_SOUTH(0x064) /* RXG Counter 13 (south) */ +#define B2062_S_RXG_CNT14 B43_LP_SOUTH(0x065) /* RXG Counter 14 (south) */ +#define B2062_S_RXG_CNT15 B43_LP_SOUTH(0x066) /* RXG Counter 15 (south) */ +#define B2062_S_RXG_CNT16 B43_LP_SOUTH(0x067) /* RXG Counter 16 (south) */ +#define B2062_S_RXG_CNT17 B43_LP_SOUTH(0x068) /* RXG Counter 17 (south) */ + + + +/*** Broadcom 2063 radio registers ***/ +#define B2063_RADIO_ID_CODE B43_LP_RADIO(0x001) /* Radio ID code */ +#define B2063_COMM1 B43_LP_RADIO(0x000) /* Common 01 */ +#define B2063_COMM2 B43_LP_RADIO(0x002) /* Common 02 */ +#define B2063_COMM3 B43_LP_RADIO(0x003) /* Common 03 */ +#define B2063_COMM4 B43_LP_RADIO(0x004) /* Common 04 */ +#define B2063_COMM5 B43_LP_RADIO(0x005) /* Common 05 */ +#define B2063_COMM6 B43_LP_RADIO(0x006) /* Common 06 */ +#define B2063_COMM7 B43_LP_RADIO(0x007) /* Common 07 */ +#define B2063_COMM8 B43_LP_RADIO(0x008) /* Common 08 */ +#define B2063_COMM9 B43_LP_RADIO(0x009) /* Common 09 */ +#define B2063_COMM10 B43_LP_RADIO(0x00A) /* Common 10 */ +#define B2063_COMM11 B43_LP_RADIO(0x00B) /* Common 11 */ +#define B2063_COMM12 B43_LP_RADIO(0x00C) /* Common 12 */ +#define B2063_COMM13 B43_LP_RADIO(0x00D) /* Common 13 */ +#define B2063_COMM14 B43_LP_RADIO(0x00E) /* Common 14 */ +#define B2063_COMM15 B43_LP_RADIO(0x00F) /* Common 15 */ +#define B2063_COMM16 B43_LP_RADIO(0x010) /* Common 16 */ +#define B2063_COMM17 B43_LP_RADIO(0x011) /* Common 17 */ +#define B2063_COMM18 B43_LP_RADIO(0x012) /* Common 18 */ +#define B2063_COMM19 B43_LP_RADIO(0x013) /* Common 19 */ +#define B2063_COMM20 B43_LP_RADIO(0x014) /* Common 20 */ +#define B2063_COMM21 B43_LP_RADIO(0x015) /* Common 21 */ +#define B2063_COMM22 B43_LP_RADIO(0x016) /* Common 22 */ +#define B2063_COMM23 B43_LP_RADIO(0x017) /* Common 23 */ +#define B2063_COMM24 B43_LP_RADIO(0x018) /* Common 24 */ +#define B2063_PWR_SWITCH_CTL B43_LP_RADIO(0x019) /* POWER SWITCH Control */ +#define B2063_PLL_SP1 B43_LP_RADIO(0x01A) /* PLL SP 1 */ +#define B2063_PLL_SP2 B43_LP_RADIO(0x01B) /* PLL SP 2 */ +#define B2063_LOGEN_SP1 B43_LP_RADIO(0x01C) /* LOGEN SP 1 */ +#define B2063_LOGEN_SP2 B43_LP_RADIO(0x01D) /* LOGEN SP 2 */ +#define B2063_LOGEN_SP3 B43_LP_RADIO(0x01E) /* LOGEN SP 3 */ +#define B2063_LOGEN_SP4 B43_LP_RADIO(0x01F) /* LOGEN SP 4 */ +#define B2063_LOGEN_SP5 B43_LP_RADIO(0x020) /* LOGEN SP 5 */ +#define B2063_G_RX_SP1 B43_LP_RADIO(0x021) /* G RX SP 1 */ +#define B2063_G_RX_SP2 B43_LP_RADIO(0x022) /* G RX SP 2 */ +#define B2063_G_RX_SP3 B43_LP_RADIO(0x023) /* G RX SP 3 */ +#define B2063_G_RX_SP4 B43_LP_RADIO(0x024) /* G RX SP 4 */ +#define B2063_G_RX_SP5 B43_LP_RADIO(0x025) /* G RX SP 5 */ +#define B2063_G_RX_SP6 B43_LP_RADIO(0x026) /* G RX SP 6 */ +#define B2063_G_RX_SP7 B43_LP_RADIO(0x027) /* G RX SP 7 */ +#define B2063_G_RX_SP8 B43_LP_RADIO(0x028) /* G RX SP 8 */ +#define B2063_G_RX_SP9 B43_LP_RADIO(0x029) /* G RX SP 9 */ +#define B2063_G_RX_SP10 B43_LP_RADIO(0x02A) /* G RX SP 10 */ +#define B2063_G_RX_SP11 B43_LP_RADIO(0x02B) /* G RX SP 11 */ +#define B2063_A_RX_SP1 B43_LP_RADIO(0x02C) /* A RX SP 1 */ +#define B2063_A_RX_SP2 B43_LP_RADIO(0x02D) /* A RX SP 2 */ +#define B2063_A_RX_SP3 B43_LP_RADIO(0x02E) /* A RX SP 3 */ +#define B2063_A_RX_SP4 B43_LP_RADIO(0x02F) /* A RX SP 4 */ +#define B2063_A_RX_SP5 B43_LP_RADIO(0x030) /* A RX SP 5 */ +#define B2063_A_RX_SP6 B43_LP_RADIO(0x031) /* A RX SP 6 */ +#define B2063_A_RX_SP7 B43_LP_RADIO(0x032) /* A RX SP 7 */ +#define B2063_RX_BB_SP1 B43_LP_RADIO(0x033) /* RX BB SP 1 */ +#define B2063_RX_BB_SP2 B43_LP_RADIO(0x034) /* RX BB SP 2 */ +#define B2063_RX_BB_SP3 B43_LP_RADIO(0x035) /* RX BB SP 3 */ +#define B2063_RX_BB_SP4 B43_LP_RADIO(0x036) /* RX BB SP 4 */ +#define B2063_RX_BB_SP5 B43_LP_RADIO(0x037) /* RX BB SP 5 */ +#define B2063_RX_BB_SP6 B43_LP_RADIO(0x038) /* RX BB SP 6 */ +#define B2063_RX_BB_SP7 B43_LP_RADIO(0x039) /* RX BB SP 7 */ +#define B2063_RX_BB_SP8 B43_LP_RADIO(0x03A) /* RX BB SP 8 */ +#define B2063_TX_RF_SP1 B43_LP_RADIO(0x03B) /* TX RF SP 1 */ +#define B2063_TX_RF_SP2 B43_LP_RADIO(0x03C) /* TX RF SP 2 */ +#define B2063_TX_RF_SP3 B43_LP_RADIO(0x03D) /* TX RF SP 3 */ +#define B2063_TX_RF_SP4 B43_LP_RADIO(0x03E) /* TX RF SP 4 */ +#define B2063_TX_RF_SP5 B43_LP_RADIO(0x03F) /* TX RF SP 5 */ +#define B2063_TX_RF_SP6 B43_LP_RADIO(0x040) /* TX RF SP 6 */ +#define B2063_TX_RF_SP7 B43_LP_RADIO(0x041) /* TX RF SP 7 */ +#define B2063_TX_RF_SP8 B43_LP_RADIO(0x042) /* TX RF SP 8 */ +#define B2063_TX_RF_SP9 B43_LP_RADIO(0x043) /* TX RF SP 9 */ +#define B2063_TX_RF_SP10 B43_LP_RADIO(0x044) /* TX RF SP 10 */ +#define B2063_TX_RF_SP11 B43_LP_RADIO(0x045) /* TX RF SP 11 */ +#define B2063_TX_RF_SP12 B43_LP_RADIO(0x046) /* TX RF SP 12 */ +#define B2063_TX_RF_SP13 B43_LP_RADIO(0x047) /* TX RF SP 13 */ +#define B2063_TX_RF_SP14 B43_LP_RADIO(0x048) /* TX RF SP 14 */ +#define B2063_TX_RF_SP15 B43_LP_RADIO(0x049) /* TX RF SP 15 */ +#define B2063_TX_RF_SP16 B43_LP_RADIO(0x04A) /* TX RF SP 16 */ +#define B2063_TX_RF_SP17 B43_LP_RADIO(0x04B) /* TX RF SP 17 */ +#define B2063_PA_SP1 B43_LP_RADIO(0x04C) /* PA SP 1 */ +#define B2063_PA_SP2 B43_LP_RADIO(0x04D) /* PA SP 2 */ +#define B2063_PA_SP3 B43_LP_RADIO(0x04E) /* PA SP 3 */ +#define B2063_PA_SP4 B43_LP_RADIO(0x04F) /* PA SP 4 */ +#define B2063_PA_SP5 B43_LP_RADIO(0x050) /* PA SP 5 */ +#define B2063_PA_SP6 B43_LP_RADIO(0x051) /* PA SP 6 */ +#define B2063_PA_SP7 B43_LP_RADIO(0x052) /* PA SP 7 */ +#define B2063_TX_BB_SP1 B43_LP_RADIO(0x053) /* TX BB SP 1 */ +#define B2063_TX_BB_SP2 B43_LP_RADIO(0x054) /* TX BB SP 2 */ +#define B2063_TX_BB_SP3 B43_LP_RADIO(0x055) /* TX BB SP 3 */ +#define B2063_REG_SP1 B43_LP_RADIO(0x056) /* REG SP 1 */ +#define B2063_BANDGAP_CTL1 B43_LP_RADIO(0x057) /* BANDGAP Control 1 */ +#define B2063_BANDGAP_CTL2 B43_LP_RADIO(0x058) /* BANDGAP Control 2 */ +#define B2063_LPO_CTL1 B43_LP_RADIO(0x059) /* LPO Control 1 */ +#define B2063_RC_CALIB_CTL1 B43_LP_RADIO(0x05A) /* RC Calibration Control 1 */ +#define B2063_RC_CALIB_CTL2 B43_LP_RADIO(0x05B) /* RC Calibration Control 2 */ +#define B2063_RC_CALIB_CTL3 B43_LP_RADIO(0x05C) /* RC Calibration Control 3 */ +#define B2063_RC_CALIB_CTL4 B43_LP_RADIO(0x05D) /* RC Calibration Control 4 */ +#define B2063_RC_CALIB_CTL5 B43_LP_RADIO(0x05E) /* RC Calibration Control 5 */ +#define B2063_RC_CALIB_CTL6 B43_LP_RADIO(0x05F) /* RC Calibration Control 6 */ +#define B2063_RC_CALIB_CTL7 B43_LP_RADIO(0x060) /* RC Calibration Control 7 */ +#define B2063_RC_CALIB_CTL8 B43_LP_RADIO(0x061) /* RC Calibration Control 8 */ +#define B2063_RC_CALIB_CTL9 B43_LP_RADIO(0x062) /* RC Calibration Control 9 */ +#define B2063_RC_CALIB_CTL10 B43_LP_RADIO(0x063) /* RC Calibration Control 10 */ +#define B2063_PLL_JTAG_CALNRST B43_LP_RADIO(0x064) /* PLL JTAG CALNRST */ +#define B2063_PLL_JTAG_IN_PLL1 B43_LP_RADIO(0x065) /* PLL JTAG IN PLL 1 */ +#define B2063_PLL_JTAG_IN_PLL2 B43_LP_RADIO(0x066) /* PLL JTAG IN PLL 2 */ +#define B2063_PLL_JTAG_PLL_CP1 B43_LP_RADIO(0x067) /* PLL JTAG PLL CP 1 */ +#define B2063_PLL_JTAG_PLL_CP2 B43_LP_RADIO(0x068) /* PLL JTAG PLL CP 2 */ +#define B2063_PLL_JTAG_PLL_CP3 B43_LP_RADIO(0x069) /* PLL JTAG PLL CP 3 */ +#define B2063_PLL_JTAG_PLL_CP4 B43_LP_RADIO(0x06A) /* PLL JTAG PLL CP 4 */ +#define B2063_PLL_JTAG_PLL_CTL1 B43_LP_RADIO(0x06B) /* PLL JTAG PLL Control 1 */ +#define B2063_PLL_JTAG_PLL_LF1 B43_LP_RADIO(0x06C) /* PLL JTAG PLL LF 1 */ +#define B2063_PLL_JTAG_PLL_LF2 B43_LP_RADIO(0x06D) /* PLL JTAG PLL LF 2 */ +#define B2063_PLL_JTAG_PLL_LF3 B43_LP_RADIO(0x06E) /* PLL JTAG PLL LF 3 */ +#define B2063_PLL_JTAG_PLL_LF4 B43_LP_RADIO(0x06F) /* PLL JTAG PLL LF 4 */ +#define B2063_PLL_JTAG_PLL_SG1 B43_LP_RADIO(0x070) /* PLL JTAG PLL SG 1 */ +#define B2063_PLL_JTAG_PLL_SG2 B43_LP_RADIO(0x071) /* PLL JTAG PLL SG 2 */ +#define B2063_PLL_JTAG_PLL_SG3 B43_LP_RADIO(0x072) /* PLL JTAG PLL SG 3 */ +#define B2063_PLL_JTAG_PLL_SG4 B43_LP_RADIO(0x073) /* PLL JTAG PLL SG 4 */ +#define B2063_PLL_JTAG_PLL_SG5 B43_LP_RADIO(0x074) /* PLL JTAG PLL SG 5 */ +#define B2063_PLL_JTAG_PLL_VCO1 B43_LP_RADIO(0x075) /* PLL JTAG PLL VCO 1 */ +#define B2063_PLL_JTAG_PLL_VCO2 B43_LP_RADIO(0x076) /* PLL JTAG PLL VCO 2 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB1 B43_LP_RADIO(0x077) /* PLL JTAG PLL VCO Calibration 1 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB2 B43_LP_RADIO(0x078) /* PLL JTAG PLL VCO Calibration 2 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB3 B43_LP_RADIO(0x079) /* PLL JTAG PLL VCO Calibration 3 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB4 B43_LP_RADIO(0x07A) /* PLL JTAG PLL VCO Calibration 4 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB5 B43_LP_RADIO(0x07B) /* PLL JTAG PLL VCO Calibration 5 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB6 B43_LP_RADIO(0x07C) /* PLL JTAG PLL VCO Calibration 6 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB7 B43_LP_RADIO(0x07D) /* PLL JTAG PLL VCO Calibration 7 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB8 B43_LP_RADIO(0x07E) /* PLL JTAG PLL VCO Calibration 8 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB9 B43_LP_RADIO(0x07F) /* PLL JTAG PLL VCO Calibration 9 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB10 B43_LP_RADIO(0x080) /* PLL JTAG PLL VCO Calibration 10 */ +#define B2063_PLL_JTAG_PLL_XTAL_12 B43_LP_RADIO(0x081) /* PLL JTAG PLL XTAL 1 2 */ +#define B2063_PLL_JTAG_PLL_XTAL3 B43_LP_RADIO(0x082) /* PLL JTAG PLL XTAL 3 */ +#define B2063_LOGEN_ACL1 B43_LP_RADIO(0x083) /* LOGEN ACL 1 */ +#define B2063_LOGEN_ACL2 B43_LP_RADIO(0x084) /* LOGEN ACL 2 */ +#define B2063_LOGEN_ACL3 B43_LP_RADIO(0x085) /* LOGEN ACL 3 */ +#define B2063_LOGEN_ACL4 B43_LP_RADIO(0x086) /* LOGEN ACL 4 */ +#define B2063_LOGEN_ACL5 B43_LP_RADIO(0x087) /* LOGEN ACL 5 */ +#define B2063_LO_CALIB_INPUTS B43_LP_RADIO(0x088) /* LO Calibration INPUTS */ +#define B2063_LO_CALIB_CTL1 B43_LP_RADIO(0x089) /* LO Calibration Control 1 */ +#define B2063_LO_CALIB_CTL2 B43_LP_RADIO(0x08A) /* LO Calibration Control 2 */ +#define B2063_LO_CALIB_CTL3 B43_LP_RADIO(0x08B) /* LO Calibration Control 3 */ +#define B2063_LO_CALIB_WAITCNT B43_LP_RADIO(0x08C) /* LO Calibration WAITCNT */ +#define B2063_LO_CALIB_OVR1 B43_LP_RADIO(0x08D) /* LO Calibration OVR 1 */ +#define B2063_LO_CALIB_OVR2 B43_LP_RADIO(0x08E) /* LO Calibration OVR 2 */ +#define B2063_LO_CALIB_OVAL1 B43_LP_RADIO(0x08F) /* LO Calibration OVAL 1 */ +#define B2063_LO_CALIB_OVAL2 B43_LP_RADIO(0x090) /* LO Calibration OVAL 2 */ +#define B2063_LO_CALIB_OVAL3 B43_LP_RADIO(0x091) /* LO Calibration OVAL 3 */ +#define B2063_LO_CALIB_OVAL4 B43_LP_RADIO(0x092) /* LO Calibration OVAL 4 */ +#define B2063_LO_CALIB_OVAL5 B43_LP_RADIO(0x093) /* LO Calibration OVAL 5 */ +#define B2063_LO_CALIB_OVAL6 B43_LP_RADIO(0x094) /* LO Calibration OVAL 6 */ +#define B2063_LO_CALIB_OVAL7 B43_LP_RADIO(0x095) /* LO Calibration OVAL 7 */ +#define B2063_LO_CALIB_CALVLD1 B43_LP_RADIO(0x096) /* LO Calibration CALVLD 1 */ +#define B2063_LO_CALIB_CALVLD2 B43_LP_RADIO(0x097) /* LO Calibration CALVLD 2 */ +#define B2063_LO_CALIB_CVAL1 B43_LP_RADIO(0x098) /* LO Calibration CVAL 1 */ +#define B2063_LO_CALIB_CVAL2 B43_LP_RADIO(0x099) /* LO Calibration CVAL 2 */ +#define B2063_LO_CALIB_CVAL3 B43_LP_RADIO(0x09A) /* LO Calibration CVAL 3 */ +#define B2063_LO_CALIB_CVAL4 B43_LP_RADIO(0x09B) /* LO Calibration CVAL 4 */ +#define B2063_LO_CALIB_CVAL5 B43_LP_RADIO(0x09C) /* LO Calibration CVAL 5 */ +#define B2063_LO_CALIB_CVAL6 B43_LP_RADIO(0x09D) /* LO Calibration CVAL 6 */ +#define B2063_LO_CALIB_CVAL7 B43_LP_RADIO(0x09E) /* LO Calibration CVAL 7 */ +#define B2063_LOGEN_CALIB_EN B43_LP_RADIO(0x09F) /* LOGEN Calibration EN */ +#define B2063_LOGEN_PEAKDET1 B43_LP_RADIO(0x0A0) /* LOGEN PEAKDET 1 */ +#define B2063_LOGEN_RCCR1 B43_LP_RADIO(0x0A1) /* LOGEN RCCR 1 */ +#define B2063_LOGEN_VCOBUF1 B43_LP_RADIO(0x0A2) /* LOGEN VCOBUF 1 */ +#define B2063_LOGEN_MIXER1 B43_LP_RADIO(0x0A3) /* LOGEN MIXER 1 */ +#define B2063_LOGEN_MIXER2 B43_LP_RADIO(0x0A4) /* LOGEN MIXER 2 */ +#define B2063_LOGEN_BUF1 B43_LP_RADIO(0x0A5) /* LOGEN BUF 1 */ +#define B2063_LOGEN_BUF2 B43_LP_RADIO(0x0A6) /* LOGEN BUF 2 */ +#define B2063_LOGEN_DIV1 B43_LP_RADIO(0x0A7) /* LOGEN DIV 1 */ +#define B2063_LOGEN_DIV2 B43_LP_RADIO(0x0A8) /* LOGEN DIV 2 */ +#define B2063_LOGEN_DIV3 B43_LP_RADIO(0x0A9) /* LOGEN DIV 3 */ +#define B2063_LOGEN_CBUFRX1 B43_LP_RADIO(0x0AA) /* LOGEN CBUFRX 1 */ +#define B2063_LOGEN_CBUFRX2 B43_LP_RADIO(0x0AB) /* LOGEN CBUFRX 2 */ +#define B2063_LOGEN_CBUFTX1 B43_LP_RADIO(0x0AC) /* LOGEN CBUFTX 1 */ +#define B2063_LOGEN_CBUFTX2 B43_LP_RADIO(0x0AD) /* LOGEN CBUFTX 2 */ +#define B2063_LOGEN_IDAC1 B43_LP_RADIO(0x0AE) /* LOGEN IDAC 1 */ +#define B2063_LOGEN_SPARE1 B43_LP_RADIO(0x0AF) /* LOGEN SPARE 1 */ +#define B2063_LOGEN_SPARE2 B43_LP_RADIO(0x0B0) /* LOGEN SPARE 2 */ +#define B2063_LOGEN_SPARE3 B43_LP_RADIO(0x0B1) /* LOGEN SPARE 3 */ +#define B2063_G_RX_1ST1 B43_LP_RADIO(0x0B2) /* G RX 1ST 1 */ +#define B2063_G_RX_1ST2 B43_LP_RADIO(0x0B3) /* G RX 1ST 2 */ +#define B2063_G_RX_1ST3 B43_LP_RADIO(0x0B4) /* G RX 1ST 3 */ +#define B2063_G_RX_2ND1 B43_LP_RADIO(0x0B5) /* G RX 2ND 1 */ +#define B2063_G_RX_2ND2 B43_LP_RADIO(0x0B6) /* G RX 2ND 2 */ +#define B2063_G_RX_2ND3 B43_LP_RADIO(0x0B7) /* G RX 2ND 3 */ +#define B2063_G_RX_2ND4 B43_LP_RADIO(0x0B8) /* G RX 2ND 4 */ +#define B2063_G_RX_2ND5 B43_LP_RADIO(0x0B9) /* G RX 2ND 5 */ +#define B2063_G_RX_2ND6 B43_LP_RADIO(0x0BA) /* G RX 2ND 6 */ +#define B2063_G_RX_2ND7 B43_LP_RADIO(0x0BB) /* G RX 2ND 7 */ +#define B2063_G_RX_2ND8 B43_LP_RADIO(0x0BC) /* G RX 2ND 8 */ +#define B2063_G_RX_PS1 B43_LP_RADIO(0x0BD) /* G RX PS 1 */ +#define B2063_G_RX_PS2 B43_LP_RADIO(0x0BE) /* G RX PS 2 */ +#define B2063_G_RX_PS3 B43_LP_RADIO(0x0BF) /* G RX PS 3 */ +#define B2063_G_RX_PS4 B43_LP_RADIO(0x0C0) /* G RX PS 4 */ +#define B2063_G_RX_PS5 B43_LP_RADIO(0x0C1) /* G RX PS 5 */ +#define B2063_G_RX_MIX1 B43_LP_RADIO(0x0C2) /* G RX MIX 1 */ +#define B2063_G_RX_MIX2 B43_LP_RADIO(0x0C3) /* G RX MIX 2 */ +#define B2063_G_RX_MIX3 B43_LP_RADIO(0x0C4) /* G RX MIX 3 */ +#define B2063_G_RX_MIX4 B43_LP_RADIO(0x0C5) /* G RX MIX 4 */ +#define B2063_G_RX_MIX5 B43_LP_RADIO(0x0C6) /* G RX MIX 5 */ +#define B2063_G_RX_MIX6 B43_LP_RADIO(0x0C7) /* G RX MIX 6 */ +#define B2063_G_RX_MIX7 B43_LP_RADIO(0x0C8) /* G RX MIX 7 */ +#define B2063_G_RX_MIX8 B43_LP_RADIO(0x0C9) /* G RX MIX 8 */ +#define B2063_G_RX_PDET1 B43_LP_RADIO(0x0CA) /* G RX PDET 1 */ +#define B2063_G_RX_SPARES1 B43_LP_RADIO(0x0CB) /* G RX SPARES 1 */ +#define B2063_G_RX_SPARES2 B43_LP_RADIO(0x0CC) /* G RX SPARES 2 */ +#define B2063_G_RX_SPARES3 B43_LP_RADIO(0x0CD) /* G RX SPARES 3 */ +#define B2063_A_RX_1ST1 B43_LP_RADIO(0x0CE) /* A RX 1ST 1 */ +#define B2063_A_RX_1ST2 B43_LP_RADIO(0x0CF) /* A RX 1ST 2 */ +#define B2063_A_RX_1ST3 B43_LP_RADIO(0x0D0) /* A RX 1ST 3 */ +#define B2063_A_RX_1ST4 B43_LP_RADIO(0x0D1) /* A RX 1ST 4 */ +#define B2063_A_RX_1ST5 B43_LP_RADIO(0x0D2) /* A RX 1ST 5 */ +#define B2063_A_RX_2ND1 B43_LP_RADIO(0x0D3) /* A RX 2ND 1 */ +#define B2063_A_RX_2ND2 B43_LP_RADIO(0x0D4) /* A RX 2ND 2 */ +#define B2063_A_RX_2ND3 B43_LP_RADIO(0x0D5) /* A RX 2ND 3 */ +#define B2063_A_RX_2ND4 B43_LP_RADIO(0x0D6) /* A RX 2ND 4 */ +#define B2063_A_RX_2ND5 B43_LP_RADIO(0x0D7) /* A RX 2ND 5 */ +#define B2063_A_RX_2ND6 B43_LP_RADIO(0x0D8) /* A RX 2ND 6 */ +#define B2063_A_RX_2ND7 B43_LP_RADIO(0x0D9) /* A RX 2ND 7 */ +#define B2063_A_RX_PS1 B43_LP_RADIO(0x0DA) /* A RX PS 1 */ +#define B2063_A_RX_PS2 B43_LP_RADIO(0x0DB) /* A RX PS 2 */ +#define B2063_A_RX_PS3 B43_LP_RADIO(0x0DC) /* A RX PS 3 */ +#define B2063_A_RX_PS4 B43_LP_RADIO(0x0DD) /* A RX PS 4 */ +#define B2063_A_RX_PS5 B43_LP_RADIO(0x0DE) /* A RX PS 5 */ +#define B2063_A_RX_PS6 B43_LP_RADIO(0x0DF) /* A RX PS 6 */ +#define B2063_A_RX_MIX1 B43_LP_RADIO(0x0E0) /* A RX MIX 1 */ +#define B2063_A_RX_MIX2 B43_LP_RADIO(0x0E1) /* A RX MIX 2 */ +#define B2063_A_RX_MIX3 B43_LP_RADIO(0x0E2) /* A RX MIX 3 */ +#define B2063_A_RX_MIX4 B43_LP_RADIO(0x0E3) /* A RX MIX 4 */ +#define B2063_A_RX_MIX5 B43_LP_RADIO(0x0E4) /* A RX MIX 5 */ +#define B2063_A_RX_MIX6 B43_LP_RADIO(0x0E5) /* A RX MIX 6 */ +#define B2063_A_RX_MIX7 B43_LP_RADIO(0x0E6) /* A RX MIX 7 */ +#define B2063_A_RX_MIX8 B43_LP_RADIO(0x0E7) /* A RX MIX 8 */ +#define B2063_A_RX_PWRDET1 B43_LP_RADIO(0x0E8) /* A RX PWRDET 1 */ +#define B2063_A_RX_SPARE1 B43_LP_RADIO(0x0E9) /* A RX SPARE 1 */ +#define B2063_A_RX_SPARE2 B43_LP_RADIO(0x0EA) /* A RX SPARE 2 */ +#define B2063_A_RX_SPARE3 B43_LP_RADIO(0x0EB) /* A RX SPARE 3 */ +#define B2063_RX_TIA_CTL1 B43_LP_RADIO(0x0EC) /* RX TIA Control 1 */ +#define B2063_RX_TIA_CTL2 B43_LP_RADIO(0x0ED) /* RX TIA Control 2 */ +#define B2063_RX_TIA_CTL3 B43_LP_RADIO(0x0EE) /* RX TIA Control 3 */ +#define B2063_RX_TIA_CTL4 B43_LP_RADIO(0x0EF) /* RX TIA Control 4 */ +#define B2063_RX_TIA_CTL5 B43_LP_RADIO(0x0F0) /* RX TIA Control 5 */ +#define B2063_RX_TIA_CTL6 B43_LP_RADIO(0x0F1) /* RX TIA Control 6 */ +#define B2063_RX_BB_CTL1 B43_LP_RADIO(0x0F2) /* RX BB Control 1 */ +#define B2063_RX_BB_CTL2 B43_LP_RADIO(0x0F3) /* RX BB Control 2 */ +#define B2063_RX_BB_CTL3 B43_LP_RADIO(0x0F4) /* RX BB Control 3 */ +#define B2063_RX_BB_CTL4 B43_LP_RADIO(0x0F5) /* RX BB Control 4 */ +#define B2063_RX_BB_CTL5 B43_LP_RADIO(0x0F6) /* RX BB Control 5 */ +#define B2063_RX_BB_CTL6 B43_LP_RADIO(0x0F7) /* RX BB Control 6 */ +#define B2063_RX_BB_CTL7 B43_LP_RADIO(0x0F8) /* RX BB Control 7 */ +#define B2063_RX_BB_CTL8 B43_LP_RADIO(0x0F9) /* RX BB Control 8 */ +#define B2063_RX_BB_CTL9 B43_LP_RADIO(0x0FA) /* RX BB Control 9 */ +#define B2063_TX_RF_CTL1 B43_LP_RADIO(0x0FB) /* TX RF Control 1 */ +#define B2063_TX_RF_IDAC_LO_RF_I B43_LP_RADIO(0x0FC) /* TX RF IDAC LO RF I */ +#define B2063_TX_RF_IDAC_LO_RF_Q B43_LP_RADIO(0x0FD) /* TX RF IDAC LO RF Q */ +#define B2063_TX_RF_IDAC_LO_BB_I B43_LP_RADIO(0x0FE) /* TX RF IDAC LO BB I */ +#define B2063_TX_RF_IDAC_LO_BB_Q B43_LP_RADIO(0x0FF) /* TX RF IDAC LO BB Q */ +#define B2063_TX_RF_CTL2 B43_LP_RADIO(0x100) /* TX RF Control 2 */ +#define B2063_TX_RF_CTL3 B43_LP_RADIO(0x101) /* TX RF Control 3 */ +#define B2063_TX_RF_CTL4 B43_LP_RADIO(0x102) /* TX RF Control 4 */ +#define B2063_TX_RF_CTL5 B43_LP_RADIO(0x103) /* TX RF Control 5 */ +#define B2063_TX_RF_CTL6 B43_LP_RADIO(0x104) /* TX RF Control 6 */ +#define B2063_TX_RF_CTL7 B43_LP_RADIO(0x105) /* TX RF Control 7 */ +#define B2063_TX_RF_CTL8 B43_LP_RADIO(0x106) /* TX RF Control 8 */ +#define B2063_TX_RF_CTL9 B43_LP_RADIO(0x107) /* TX RF Control 9 */ +#define B2063_TX_RF_CTL10 B43_LP_RADIO(0x108) /* TX RF Control 10 */ +#define B2063_TX_RF_CTL14 B43_LP_RADIO(0x109) /* TX RF Control 14 */ +#define B2063_TX_RF_CTL15 B43_LP_RADIO(0x10A) /* TX RF Control 15 */ +#define B2063_PA_CTL1 B43_LP_RADIO(0x10B) /* PA Control 1 */ +#define B2063_PA_CTL2 B43_LP_RADIO(0x10C) /* PA Control 2 */ +#define B2063_PA_CTL3 B43_LP_RADIO(0x10D) /* PA Control 3 */ +#define B2063_PA_CTL4 B43_LP_RADIO(0x10E) /* PA Control 4 */ +#define B2063_PA_CTL5 B43_LP_RADIO(0x10F) /* PA Control 5 */ +#define B2063_PA_CTL6 B43_LP_RADIO(0x110) /* PA Control 6 */ +#define B2063_PA_CTL7 B43_LP_RADIO(0x111) /* PA Control 7 */ +#define B2063_PA_CTL8 B43_LP_RADIO(0x112) /* PA Control 8 */ +#define B2063_PA_CTL9 B43_LP_RADIO(0x113) /* PA Control 9 */ +#define B2063_PA_CTL10 B43_LP_RADIO(0x114) /* PA Control 10 */ +#define B2063_PA_CTL11 B43_LP_RADIO(0x115) /* PA Control 11 */ +#define B2063_PA_CTL12 B43_LP_RADIO(0x116) /* PA Control 12 */ +#define B2063_PA_CTL13 B43_LP_RADIO(0x117) /* PA Control 13 */ +#define B2063_TX_BB_CTL1 B43_LP_RADIO(0x118) /* TX BB Control 1 */ +#define B2063_TX_BB_CTL2 B43_LP_RADIO(0x119) /* TX BB Control 2 */ +#define B2063_TX_BB_CTL3 B43_LP_RADIO(0x11A) /* TX BB Control 3 */ +#define B2063_TX_BB_CTL4 B43_LP_RADIO(0x11B) /* TX BB Control 4 */ +#define B2063_GPIO_CTL1 B43_LP_RADIO(0x11C) /* GPIO Control 1 */ +#define B2063_VREG_CTL1 B43_LP_RADIO(0x11D) /* VREG Control 1 */ +#define B2063_AMUX_CTL1 B43_LP_RADIO(0x11E) /* AMUX Control 1 */ +#define B2063_IQ_CALIB_GVAR B43_LP_RADIO(0x11F) /* IQ Calibration GVAR */ +#define B2063_IQ_CALIB_CTL1 B43_LP_RADIO(0x120) /* IQ Calibration Control 1 */ +#define B2063_IQ_CALIB_CTL2 B43_LP_RADIO(0x121) /* IQ Calibration Control 2 */ +#define B2063_TEMPSENSE_CTL1 B43_LP_RADIO(0x122) /* TEMPSENSE Control 1 */ +#define B2063_TEMPSENSE_CTL2 B43_LP_RADIO(0x123) /* TEMPSENSE Control 2 */ +#define B2063_TX_RX_LOOPBACK1 B43_LP_RADIO(0x124) /* TX/RX LOOPBACK 1 */ +#define B2063_TX_RX_LOOPBACK2 B43_LP_RADIO(0x125) /* TX/RX LOOPBACK 2 */ +#define B2063_EXT_TSSI_CTL1 B43_LP_RADIO(0x126) /* EXT TSSI Control 1 */ +#define B2063_EXT_TSSI_CTL2 B43_LP_RADIO(0x127) /* EXT TSSI Control 2 */ +#define B2063_AFE_CTL B43_LP_RADIO(0x128) /* AFE Control */ + + + +struct b43_phy_lp { + //TODO +}; + + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_lp; + +#endif /* LINUX_B43_PHY_LP_H_ */ diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/phy_n.c index 644eed993be..8bcfda5f3f0 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -26,7 +26,7 @@ #include <linux/types.h> #include "b43.h" -#include "nphy.h" +#include "phy_n.h" #include "tables_nphy.h" @@ -34,10 +34,16 @@ void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO } -void b43_nphy_xmitpower(struct b43_wldev *dev) +static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev) {//TODO } +static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{//TODO + return B43_TXPWR_RES_DONE; +} + static void b43_chantab_radio_upload(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry *e) { @@ -81,9 +87,8 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) //TODO } -/* Tune the hardware to a new channel. Don't call this directly. - * Use b43_radio_selectchannel() */ -int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) +/* Tune the hardware to a new channel. */ +static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel) { const struct b43_nphy_channeltab_entry *tabent; @@ -162,7 +167,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) msleep(1); b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); msleep(1); - b43_radio_selectchannel(dev, dev->phy.channel, 0); + nphy_channel_switch(dev, dev->phy.channel); b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9); b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9); b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83); @@ -484,3 +489,140 @@ int b43_phy_initn(struct b43_wldev *dev) b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); return 0; } + +static int b43_nphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy; + + nphy = kzalloc(sizeof(*nphy), GFP_KERNEL); + if (!nphy) + return -ENOMEM; + dev->phy.n = nphy; + + return 0; +} + +static void b43_nphy_op_prepare_structs(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = phy->n; + + memset(nphy, 0, sizeof(*nphy)); + + //TODO init struct b43_phy_n +} + +static void b43_nphy_op_free(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = phy->n; + + kfree(nphy); + phy->n = NULL; +} + +static int b43_nphy_op_init(struct b43_wldev *dev) +{ + return b43_phy_initn(dev); +} + +static inline void check_phyreg(struct b43_wldev *dev, u16 offset) +{ +#if B43_DEBUG + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { + /* OFDM registers are onnly available on A/G-PHYs */ + b43err(dev->wl, "Invalid OFDM PHY access at " + "0x%04X on N-PHY\n", offset); + dump_stack(); + } + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { + /* Ext-G registers are only available on G-PHYs */ + b43err(dev->wl, "Invalid EXT-G PHY access at " + "0x%04X on N-PHY\n", offset); + dump_stack(); + } +#endif /* B43_DEBUG */ +} + +static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg) +{ + check_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + check_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* N-PHY needs 0x100 for read access */ + reg |= 0x100; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{//TODO +} + +static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on) +{ + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, + on ? 0 : 0x7FFF); +} + +static int b43_nphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if ((new_channel < 1) || (new_channel > 14)) + return -EINVAL; + } else { + if (new_channel > 200) + return -EINVAL; + } + + return nphy_channel_switch(dev, new_channel); +} + +static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 1; + return 36; +} + +const struct b43_phy_operations b43_phyops_n = { + .allocate = b43_nphy_op_allocate, + .free = b43_nphy_op_free, + .prepare_structs = b43_nphy_op_prepare_structs, + .init = b43_nphy_op_init, + .phy_read = b43_nphy_op_read, + .phy_write = b43_nphy_op_write, + .radio_read = b43_nphy_op_radio_read, + .radio_write = b43_nphy_op_radio_write, + .software_rfkill = b43_nphy_op_software_rfkill, + .switch_analog = b43_nphy_op_switch_analog, + .switch_channel = b43_nphy_op_switch_channel, + .get_default_chan = b43_nphy_op_get_default_chan, + .recalc_txpower = b43_nphy_op_recalc_txpower, + .adjust_txpower = b43_nphy_op_adjust_txpower, +}; diff --git a/drivers/net/wireless/b43/nphy.h b/drivers/net/wireless/b43/phy_n.h index faf46b9cbf1..1749aef4147 100644 --- a/drivers/net/wireless/b43/nphy.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -1,7 +1,7 @@ #ifndef B43_NPHY_H_ #define B43_NPHY_H_ -#include "phy.h" +#include "phy_common.h" /* N-PHY registers. */ @@ -919,54 +919,12 @@ struct b43_wldev; +struct b43_phy_n { + //TODO lots of missing stuff +}; -#ifdef CONFIG_B43_NPHY -/* N-PHY support enabled */ -int b43_phy_initn(struct b43_wldev *dev); +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_n; -void b43_nphy_radio_turn_on(struct b43_wldev *dev); -void b43_nphy_radio_turn_off(struct b43_wldev *dev); - -int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel); - -void b43_nphy_xmitpower(struct b43_wldev *dev); -void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna); - - -#else /* CONFIG_B43_NPHY */ -/* N-PHY support disabled */ - - -static inline -int b43_phy_initn(struct b43_wldev *dev) -{ - return -EOPNOTSUPP; -} - -static inline -void b43_nphy_radio_turn_on(struct b43_wldev *dev) -{ -} -static inline -void b43_nphy_radio_turn_off(struct b43_wldev *dev) -{ -} - -static inline -int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) -{ - return -ENOSYS; -} - -static inline -void b43_nphy_xmitpower(struct b43_wldev *dev) -{ -} -static inline -void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) -{ -} - -#endif /* CONFIG_B43_NPHY */ #endif /* B43_NPHY_H_ */ diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index fec5645944a..713753781f4 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -24,6 +24,7 @@ #include "rfkill.h" #include "b43.h" +#include "phy_common.h" #include <linux/kmod.h> @@ -43,23 +44,6 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) return 0; } -/* Update the rfkill state */ -static void b43_rfkill_update_state(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (!dev->radio_hw_enable) { - rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED; - return; - } - - if (!dev->phy.radio_on) - rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED; - else - rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; - -} - /* The poll callback for the hardware button. */ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) { @@ -77,7 +61,6 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; report_change = 1; - b43_rfkill_update_state(dev); b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); } @@ -114,11 +97,11 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) goto out_unlock; } if (!dev->phy.radio_on) - b43_radio_turn_on(dev); + b43_software_rfkill(dev, state); break; case RFKILL_STATE_SOFT_BLOCKED: if (dev->phy.radio_on) - b43_radio_turn_off(dev, 0); + b43_software_rfkill(dev, state); break; default: b43warn(wl, "Received unexpected rfkill state %d.\n", state); @@ -187,6 +170,11 @@ void b43_rfkill_init(struct b43_wldev *dev) "The built-in radio LED will not work.\n"); #endif /* CONFIG_RFKILL_INPUT */ +#if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE) + b43warn(wl, "The rfkill-input subsystem is not available. " + "The built-in radio LED will not work.\n"); +#endif + err = input_register_polled_device(rfk->poll_dev); if (err) goto err_unreg_rfk; diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index 275095b8cbe..5adaa3692d7 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -29,7 +29,7 @@ #include "b43.h" #include "sysfs.h" #include "main.h" -#include "phy.h" +#include "phy_common.h" #define GENERIC_FILESIZE 64 @@ -59,7 +59,12 @@ static ssize_t b43_attr_interfmode_show(struct device *dev, mutex_lock(&wldev->wl->mutex); - switch (wldev->phy.interfmode) { + if (wldev->phy.type != B43_PHYTYPE_G) { + mutex_unlock(&wldev->wl->mutex); + return -ENOSYS; + } + + switch (wldev->phy.g->interfmode) { case B43_INTERFMODE_NONE: count = snprintf(buf, PAGE_SIZE, @@ -117,11 +122,15 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, mutex_lock(&wldev->wl->mutex); spin_lock_irqsave(&wldev->wl->irq_lock, flags); - err = b43_radio_set_interference_mitigation(wldev, mode); - if (err) { - b43err(wldev->wl, "Interference Mitigation not " - "supported by device\n"); - } + if (wldev->phy.ops->interf_mitigation) { + err = wldev->phy.ops->interf_mitigation(wldev, mode); + if (err) { + b43err(wldev->wl, "Interference Mitigation not " + "supported by device\n"); + } + } else + err = -ENOSYS; + mmiowb(); spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); mutex_unlock(&wldev->wl->mutex); diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c index 3f5ea06bf13..1ef9a6463ec 100644 --- a/drivers/net/wireless/b43/tables.c +++ b/drivers/net/wireless/b43/tables.c @@ -27,7 +27,8 @@ #include "b43.h" #include "tables.h" -#include "phy.h" +#include "phy_g.h" + const u32 b43_tab_rotor[] = { 0xFEB93FFD, 0xFEC63FFD, /* 0 */ @@ -377,17 +378,17 @@ static inline void assert_sizes(void) u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; return b43_phy_read(dev, B43_PHY_OTABLEI); @@ -398,34 +399,34 @@ u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, u16 offset, u16 value) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; b43_phy_write(dev, B43_PHY_OTABLEI, value); } u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u32 ret; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; ret = b43_phy_read(dev, B43_PHY_OTABLEQ); ret <<= 16; ret |= b43_phy_read(dev, B43_PHY_OTABLEI); @@ -436,17 +437,17 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, u16 offset, u32 value) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; b43_phy_write(dev, B43_PHY_OTABLEI, value); b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16)); diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 2aa57551786..4e233631554 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -24,8 +24,8 @@ #include "b43.h" #include "tables_nphy.h" -#include "phy.h" -#include "nphy.h" +#include "phy_common.h" +#include "phy_n.h" struct b2055_inittab_entry { diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index daa94211f83..0c0fb15abb9 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -27,7 +27,7 @@ #include "b43.h" #include "main.h" #include "tables.h" -#include "phy.h" +#include "phy_common.h" #include "wa.h" static void b43_wa_papd(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 9dda8169f7c..2fabcf8f047 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -28,7 +28,7 @@ */ #include "xmit.h" -#include "phy.h" +#include "phy_common.h" #include "dma.h" #include "pio.h" @@ -208,7 +208,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, txrate = ieee80211_get_tx_rate(dev->wl->hw, info); rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate; + fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : txrate; rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); @@ -252,7 +252,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* Hardware appends ICV. */ - plcp_fragment_len += info->control.icv_len; + plcp_fragment_len += info->control.hw_key->icv_len; key_idx = b43_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & @@ -260,7 +260,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_hdrlen(fctl); - iv_len = min((size_t) info->control.iv_len, + iv_len = min((size_t) info->control.hw_key->iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } @@ -431,6 +431,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, int adjust_2053, int adjust_2050) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; s32 tmp; switch (phy->radio_ver) { @@ -450,7 +451,8 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, boardflags_lo & B43_BFL_RSSI) { if (in_rssi > 63) in_rssi = 63; - tmp = phy->nrssi_lt[in_rssi]; + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + tmp = gphy->nrssi_lt[in_rssi]; tmp = 31 - tmp; tmp *= -131; tmp /= 128; @@ -678,6 +680,8 @@ void b43_handle_txstatus(struct b43_wldev *dev, b43_pio_handle_txstatus(dev, status); else b43_dma_handle_txstatus(dev, status); + + b43_phy_txpower_check(dev, 0); } /* Fill out the mac80211 TXstatus report based on the b43-specific diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 1cb77db5c29..c66d57560e7 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -888,13 +888,13 @@ generate_new: static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev) { - if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) { /* TODO: PS TBTT */ } else { if (1/*FIXME: the last PSpoll frame was sent successfully */) b43legacy_power_saving_ctl_bits(dev, -1, -1); } - if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) dev->dfq_valid = 1; } @@ -1201,7 +1201,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) struct b43legacy_wl *wl = dev->wl; u32 cmd; - if (!b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) return; /* This is the bottom half of the asynchronous beacon update. */ @@ -1936,9 +1936,9 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev) ctl &= ~B43legacy_MACCTL_BEACPROMISC; ctl |= B43legacy_MACCTL_INFRA; - if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) ctl |= B43legacy_MACCTL_AP; - else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) ctl &= ~B43legacy_MACCTL_INFRA; if (wl->filter_flags & FIF_CONTROL) @@ -2646,7 +2646,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, b43legacy_mgmtframe_txantenna(dev, antenna_tx); /* Update templates for AP mode. */ - if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) b43legacy_set_beacon_int(dev, conf->beacon_int); @@ -2733,12 +2733,12 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw, else memset(wl->bssid, 0, ETH_ALEN); if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { - if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43legacy_WARN_ON(vif->type != IEEE80211_IF_TYPE_AP); + if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) { + B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP); b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->changed & IEEE80211_IFCC_BEACON) b43legacy_update_templates(wl); - } else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) { + } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { if (conf->changed & IEEE80211_IFCC_BEACON) b43legacy_update_templates(wl); } @@ -3020,7 +3020,7 @@ static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev, bool idle) { u16 pu_delay = 1050; - if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle) + if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle) pu_delay = 500; if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8)) pu_delay = max(pu_delay, (u16)2400); @@ -3035,7 +3035,7 @@ static void b43legacy_set_pretbtt(struct b43legacy_wldev *dev) u16 pretbtt; /* The time value is in microseconds. */ - if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) pretbtt = 2; else pretbtt = 250; @@ -3259,10 +3259,10 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ - if (conf->type != IEEE80211_IF_TYPE_AP && - conf->type != IEEE80211_IF_TYPE_STA && - conf->type != IEEE80211_IF_TYPE_WDS && - conf->type != IEEE80211_IF_TYPE_IBSS) + if (conf->type != NL80211_IFTYPE_AP && + conf->type != NL80211_IFTYPE_STATION && + conf->type != NL80211_IFTYPE_WDS && + conf->type != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; mutex_lock(&wl->mutex); @@ -3403,7 +3403,7 @@ out_unlock: } static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, - int aid, int set) + struct ieee80211_sta *sta, bool set) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); unsigned long flags; @@ -3704,7 +3704,13 @@ static int b43legacy_wireless_init(struct ssb_device *dev) hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_WDS) | + BIT(NL80211_IFTYPE_ADHOC); hw->queues = 1; /* FIXME: hardware has more queues */ + hw->max_altrates = 1; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 768cccb9b1b..4c9442b16f3 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -103,7 +103,7 @@ void b43legacy_phy_lock(struct b43legacy_wldev *dev) if (dev->dev->id.revision < 3) { b43legacy_mac_suspend(dev); } else { - if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) b43legacy_power_saving_ctl_bits(dev, -1, 1); } } @@ -118,7 +118,7 @@ void b43legacy_phy_unlock(struct b43legacy_wldev *dev) if (dev->dev->id.revision < 3) { b43legacy_mac_enable(dev); } else { - if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) b43legacy_power_saving_ctl_bits(dev, -1, -1); } } @@ -595,12 +595,14 @@ static void b43legacy_phy_initb5(struct b43legacy_wldev *dev) 0x0035) & 0xFFC0) | 0x0064); b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); + b43legacy_phy_write(dev, 0x5B, 0x0000); + b43legacy_phy_write(dev, 0x5C, 0x0000); } if (dev->bad_frames_preempt) b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, b43legacy_phy_read(dev, - B43legacy_PHY_RADIO_BITFIELD) | (1 << 11)); + B43legacy_PHY_RADIO_BITFIELD) | (1 << 12)); if (phy->analog == 1) { b43legacy_phy_write(dev, 0x0026, 0xCE00); @@ -753,7 +755,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) b43legacy_radio_write16(dev, 0x0050, 0x0020); } if (phy->radio_rev <= 2) { - b43legacy_radio_write16(dev, 0x007C, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0020); b43legacy_radio_write16(dev, 0x005A, 0x0070); b43legacy_radio_write16(dev, 0x005B, 0x007B); b43legacy_radio_write16(dev, 0x005C, 0x00B0); @@ -771,7 +773,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x002A, 0x8AC0); b43legacy_phy_write(dev, 0x0038, 0x0668); b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); - if (phy->radio_rev <= 5) + if (phy->radio_rev == 4 || phy->radio_rev == 5) b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, 0x005D) & 0xFF80) | 0x0003); if (phy->radio_rev <= 2) @@ -1010,7 +1012,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) b43legacy_phy_initb5(dev); else b43legacy_phy_initb6(dev); - if (phy->rev >= 2 || phy->gmode) + if (phy->rev >= 2 && phy->gmode) b43legacy_phy_inita(dev); if (phy->rev >= 2) { @@ -1025,18 +1027,22 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0811, 0x0400); b43legacy_phy_write(dev, 0x0015, 0x00C0); } - if (phy->rev >= 2 || phy->gmode) { + if (phy->gmode) { tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF; - if (tmp == 3 || tmp == 5) { + if (tmp == 3) { + b43legacy_phy_write(dev, 0x04C2, 0x1816); + b43legacy_phy_write(dev, 0x04C3, 0x8606); + } + if (tmp == 4 || tmp == 5) { b43legacy_phy_write(dev, 0x04C2, 0x1816); b43legacy_phy_write(dev, 0x04C3, 0x8006); - if (tmp == 5) - b43legacy_phy_write(dev, 0x04CC, - (b43legacy_phy_read(dev, - 0x04CC) & 0x00FF) | - 0x1F00); + b43legacy_phy_write(dev, 0x04CC, + (b43legacy_phy_read(dev, + 0x04CC) & 0x00FF) | + 0x1F00); } - b43legacy_phy_write(dev, 0x047E, 0x0078); + if (phy->rev >= 2) + b43legacy_phy_write(dev, 0x047E, 0x0078); } if (phy->radio_rev == 8) { b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801) @@ -1078,7 +1084,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) else b43legacy_phy_write(dev, 0x002F, 0x0202); } - if (phy->gmode || phy->rev >= 2) { + if (phy->gmode) { b43legacy_phy_lo_adjust(dev, 0); b43legacy_phy_write(dev, 0x080F, 0x8078); } diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index 476add97e97..b32bf6a94f1 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -44,23 +44,6 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) return 0; } -/* Update the rfkill state */ -static void b43legacy_rfkill_update_state(struct b43legacy_wldev *dev) -{ - struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - - if (!dev->radio_hw_enable) { - rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED; - return; - } - - if (!dev->phy.radio_on) - rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED; - else - rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; - -} - /* The poll callback for the hardware button. */ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) { @@ -78,7 +61,6 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; report_change = 1; - b43legacy_rfkill_update_state(dev); b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); } diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 68e1f8c7872..65e83378160 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -193,7 +193,6 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, { const struct ieee80211_hdr *wlhdr; int use_encryption = !!info->control.hw_key; - u16 fctl; u8 rate; struct ieee80211_rate *rate_fb; int rate_ofdm; @@ -204,7 +203,6 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct ieee80211_rate *tx_rate; wlhdr = (const struct ieee80211_hdr *)fragment_data; - fctl = le16_to_cpu(wlhdr->frame_control); memset(txhdr, 0, sizeof(*txhdr)); @@ -212,7 +210,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, rate = tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate; + rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : tx_rate; rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; @@ -245,7 +243,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, if (key->enabled) { /* Hardware appends ICV. */ - plcp_fragment_len += info->control.icv_len; + plcp_fragment_len += info->control.hw_key->icv_len; key_idx = b43legacy_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & @@ -253,8 +251,8 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, mac_ctl |= (key->algorithm << B43legacy_TX4_MAC_KEYALG_SHIFT) & B43legacy_TX4_MAC_KEYALG; - wlhdr_len = ieee80211_get_hdrlen(fctl); - iv_len = min((size_t)info->control.iv_len, + wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control); + iv_len = min((size_t)info->control.hw_key->iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); } else { @@ -626,7 +624,7 @@ void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev, tmp = hw->count; status.frame_count = (tmp >> 4); status.rts_count = (tmp & 0x0F); - tmp = hw->flags; + tmp = hw->flags << 1; status.supp_reason = ((tmp & 0x1C) >> 2); status.pm_indicated = !!(tmp & 0x80); status.intermediate = !!(tmp & 0x40); diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index 29d39105f5b..bfa375369df 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -87,7 +87,8 @@ MODULE_LICENSE("Dual MPL/GPL"); Callable from any context. */ -static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0) +static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0, + u16 param1, u16 param2) { int k = CMD_BUSY_TIMEOUT; u16 reg; @@ -103,8 +104,8 @@ static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0) return -EBUSY; } - hermes_write_regn(hw, PARAM2, 0); - hermes_write_regn(hw, PARAM1, 0); + hermes_write_regn(hw, PARAM2, param2); + hermes_write_regn(hw, PARAM1, param1); hermes_write_regn(hw, PARAM0, param0); hermes_write_regn(hw, CMD, cmd); @@ -115,16 +116,72 @@ static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0) * Function definitions */ +/* For doing cmds that wipe the magic constant in SWSUPPORT0 */ +int hermes_doicmd_wait(hermes_t *hw, u16 cmd, + u16 parm0, u16 parm1, u16 parm2, + struct hermes_response *resp) +{ + int err = 0; + int k; + u16 status, reg; + + err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2); + if (err) + return err; + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_INIT_TIMEOUT; + while ((!(reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); + + if (!hermes_present(hw)) { + DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (!(reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ %p: " + "Timeout waiting for card to reset (reg=0x%04x)!\n", + hw->iobase, reg); + err = -ETIMEDOUT; + goto out; + } + + status = hermes_read_regn(hw, STATUS); + if (resp) { + resp->status = status; + resp->resp0 = hermes_read_regn(hw, RESP0); + resp->resp1 = hermes_read_regn(hw, RESP1); + resp->resp2 = hermes_read_regn(hw, RESP2); + } + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + if (status & HERMES_STATUS_RESULT) + err = -EIO; +out: + return err; +} +EXPORT_SYMBOL(hermes_doicmd_wait); + void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing) { hw->iobase = address; hw->reg_spacing = reg_spacing; hw->inten = 0x0; } +EXPORT_SYMBOL(hermes_struct_init); int hermes_init(hermes_t *hw) { - u16 status, reg; + u16 reg; int err = 0; int k; @@ -162,45 +219,11 @@ int hermes_init(hermes_t *hw) /* We don't use hermes_docmd_wait here, because the reset wipes the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_INIT_TIMEOUT; - while ( (! (reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - - if (! hermes_present(hw)) { - DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for card to reset (reg=0x%04x)!\n", - hw->iobase, reg); - err = -ETIMEDOUT; - goto out; - } + err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL); - status = hermes_read_regn(hw, STATUS); - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - if (status & HERMES_STATUS_RESULT) - err = -EIO; - - out: return err; } +EXPORT_SYMBOL(hermes_init); /* Issue a command to the chip, and (busy!) wait for it to * complete. @@ -216,7 +239,7 @@ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, u16 reg; u16 status; - err = hermes_issue_cmd(hw, cmd, parm0); + err = hermes_issue_cmd(hw, cmd, parm0, 0, 0); if (err) { if (! hermes_present(hw)) { if (net_ratelimit()) @@ -271,6 +294,7 @@ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, out: return err; } +EXPORT_SYMBOL(hermes_docmd_wait); int hermes_allocate(hermes_t *hw, u16 size, u16 *fid) { @@ -313,7 +337,7 @@ int hermes_allocate(hermes_t *hw, u16 size, u16 *fid) return 0; } - +EXPORT_SYMBOL(hermes_allocate); /* Set up a BAP to read a particular chunk of data from card's internal buffer. * @@ -397,6 +421,7 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, out: return err; } +EXPORT_SYMBOL(hermes_bap_pread); /* Write a block of data to the chip's buffer, via the * BAP. Synchronization/serialization is the caller's problem. @@ -422,6 +447,7 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, out: return err; } +EXPORT_SYMBOL(hermes_bap_pwrite); /* Read a Length-Type-Value record from the card. * @@ -463,7 +489,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, if (rtype != rid) printk(KERN_WARNING "hermes @ %p: %s(): " "rid (0x%04x) does not match type (0x%04x)\n", - hw->iobase, __FUNCTION__, rid, rtype); + hw->iobase, __func__, rid, rtype); if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize) printk(KERN_WARNING "hermes @ %p: " "Truncating LTV record from %d to %d bytes. " @@ -475,6 +501,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, return 0; } +EXPORT_SYMBOL(hermes_read_ltv); int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, u16 length, const void *value) @@ -497,20 +524,11 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, hermes_write_bytes(hw, dreg, value, count << 1); - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, rid, NULL); return err; } - -EXPORT_SYMBOL(hermes_struct_init); -EXPORT_SYMBOL(hermes_init); -EXPORT_SYMBOL(hermes_docmd_wait); -EXPORT_SYMBOL(hermes_allocate); - -EXPORT_SYMBOL(hermes_bap_pread); -EXPORT_SYMBOL(hermes_bap_pwrite); -EXPORT_SYMBOL(hermes_read_ltv); EXPORT_SYMBOL(hermes_write_ltv); static int __init init_hermes(void) diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 8e3f0e3edb5..8b13c8fef3d 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -179,17 +179,23 @@ #define HERMES_802_11_OFFSET (14) #define HERMES_802_3_OFFSET (14+32) #define HERMES_802_2_OFFSET (14+32+14) +#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2) #define HERMES_RXSTAT_ERR (0x0003) #define HERMES_RXSTAT_BADCRC (0x0001) #define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) +#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */ #define HERMES_RXSTAT_MACPORT (0x0700) #define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */ +#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */ #define HERMES_RXSTAT_MSGTYPE (0xE000) #define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ #define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ #define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ +/* Shift amount for key ID in RXSTAT and TXCTRL */ +#define HERMES_MIC_KEY_ID_SHIFT 11 + struct hermes_tx_descriptor { __le16 status; __le16 reserved1; @@ -208,6 +214,8 @@ struct hermes_tx_descriptor { #define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ #define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ #define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ +#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */ +#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */ #define HERMES_TXCTRL_ALT_RTRY (0x0020) /* Inquiry constants and data types */ @@ -302,6 +310,40 @@ union hermes_scan_info { struct symbol_scan_apinfo s; }; +/* Extended scan struct for HERMES_INQ_CHANNELINFO. + * wl_lkm calls this an ACS scan (Automatic Channel Select). + * Keep out of union hermes_scan_info because it is much bigger than + * the older scan structures. */ +struct agere_ext_scan_info { + __le16 reserved0; + + u8 noise; + u8 level; + u8 rx_flow; + u8 rate; + __le16 reserved1[2]; + + __le16 frame_control; + __le16 dur_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 sequence; + u8 addr4[ETH_ALEN]; + + __le16 data_length; + + /* Next 3 fields do not get filled in. */ + u8 daddr[ETH_ALEN]; + u8 saddr[ETH_ALEN]; + __le16 len_type; + + __le64 timestamp; + __le16 beacon_interval; + __le16 capabilities; + u8 data[316]; +} __attribute__ ((packed)); + #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) #define HERMES_LINKSTATUS_CONNECTED (0x0001) #define HERMES_LINKSTATUS_DISCONNECTED (0x0002) @@ -353,6 +395,9 @@ void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing); int hermes_init(hermes_t *hw); int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, struct hermes_response *resp); +int hermes_doicmd_wait(hermes_t *hw, u16 cmd, + u16 parm0, u16 parm1, u16 parm2, + struct hermes_response *resp); int hermes_allocate(hermes_t *hw, u16 size, u16 *fid); int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/hermes_dld.c new file mode 100644 index 00000000000..d8c626e61a3 --- /dev/null +++ b/drivers/net/wireless/hermes_dld.c @@ -0,0 +1,730 @@ +/* + * Hermes download helper driver. + * + * This could be entirely merged into hermes.c. + * + * I'm keeping it separate to minimise the amount of merging between + * kernel upgrades. It also means the memory overhead for drivers that + * don't need firmware download low. + * + * This driver: + * - is capable of writing to the volatile area of the hermes device + * - is currently not capable of writing to non-volatile areas + * - provide helpers to identify and update plugin data + * - is not capable of interpreting a fw image directly. That is up to + * the main card driver. + * - deals with Hermes I devices. It can probably be modified to deal + * with Hermes II devices + * + * Copyright (C) 2007, David Kilroy + * + * Plug data code slightly modified from spectrum_cs driver + * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org> + * Portions based on information in wl_lkm_718 Agere driver + * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include "hermes.h" +#include "hermes_dld.h" + +MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset"); +MODULE_AUTHOR("David Kilroy <kilroyd@gmail.com>"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define PFX "hermes_dld: " + +/* + * AUX port access. To unlock the AUX port write the access keys to the + * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL + * register. Then read it and make sure it's HERMES_AUX_ENABLED. + */ +#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ +#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ +#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ +#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */ + +#define HERMES_AUX_PW0 0xFE01 +#define HERMES_AUX_PW1 0xDC23 +#define HERMES_AUX_PW2 0xBA45 + +/* HERMES_CMD_DOWNLD */ +#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD) +#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD) +#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD) +#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD) + +/* End markers used in dblocks */ +#define PDI_END 0x00000000 /* End of PDA */ +#define BLOCK_END 0xFFFFFFFF /* Last image block */ +#define TEXT_END 0x1A /* End of text header */ + +/* + * PDA == Production Data Area + * + * In principle, the max. size of the PDA is is 4096 words. Currently, + * however, only about 500 bytes of this area are used. + * + * Some USB implementations can't handle sizes in excess of 1016. Note + * that PDA is not actually used in those USB environments, but may be + * retrieved by common code. + */ +#define MAX_PDA_SIZE 1000 + +/* Limit the amout we try to download in a single shot. + * Size is in bytes. + */ +#define MAX_DL_SIZE 1024 +#define LIMIT_PROGRAM_SIZE 0 + +/* + * The following structures have little-endian fields denoted by + * the leading underscore. Don't access them directly - use inline + * functions defined below. + */ + +/* + * The binary image to be downloaded consists of series of data blocks. + * Each block has the following structure. + */ +struct dblock { + __le32 addr; /* adapter address where to write the block */ + __le16 len; /* length of the data only, in bytes */ + char data[0]; /* data to be written */ +} __attribute__ ((packed)); + +/* + * Plug Data References are located in in the image after the last data + * block. They refer to areas in the adapter memory where the plug data + * items with matching ID should be written. + */ +struct pdr { + __le32 id; /* record ID */ + __le32 addr; /* adapter address where to write the data */ + __le32 len; /* expected length of the data, in bytes */ + char next[0]; /* next PDR starts here */ +} __attribute__ ((packed)); + +/* + * Plug Data Items are located in the EEPROM read from the adapter by + * primary firmware. They refer to the device-specific data that should + * be plugged into the secondary firmware. + */ +struct pdi { + __le16 len; /* length of ID and data, in words */ + __le16 id; /* record ID */ + char data[0]; /* plug data */ +} __attribute__ ((packed)); + +/*** FW data block access functions ***/ + +static inline u32 +dblock_addr(const struct dblock *blk) +{ + return le32_to_cpu(blk->addr); +} + +static inline u32 +dblock_len(const struct dblock *blk) +{ + return le16_to_cpu(blk->len); +} + +/*** PDR Access functions ***/ + +static inline u32 +pdr_id(const struct pdr *pdr) +{ + return le32_to_cpu(pdr->id); +} + +static inline u32 +pdr_addr(const struct pdr *pdr) +{ + return le32_to_cpu(pdr->addr); +} + +static inline u32 +pdr_len(const struct pdr *pdr) +{ + return le32_to_cpu(pdr->len); +} + +/*** PDI Access functions ***/ + +static inline u32 +pdi_id(const struct pdi *pdi) +{ + return le16_to_cpu(pdi->id); +} + +/* Return length of the data only, in bytes */ +static inline u32 +pdi_len(const struct pdi *pdi) +{ + return 2 * (le16_to_cpu(pdi->len) - 1); +} + +/*** Hermes AUX control ***/ + +static inline void +hermes_aux_setaddr(hermes_t *hw, u32 addr) +{ + hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); + hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); +} + +static inline int +hermes_aux_control(hermes_t *hw, int enabled) +{ + int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED; + int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE; + int i; + + /* Already open? */ + if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state) + return 0; + + hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); + hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); + hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); + hermes_write_reg(hw, HERMES_CONTROL, action); + + for (i = 0; i < 20; i++) { + udelay(10); + if (hermes_read_reg(hw, HERMES_CONTROL) == + desired_state) + return 0; + } + + return -EBUSY; +} + +/*** Plug Data Functions ***/ + +/* + * Scan PDR for the record with the specified RECORD_ID. + * If it's not found, return NULL. + */ +static struct pdr * +hermes_find_pdr(struct pdr *first_pdr, u32 record_id) +{ + struct pdr *pdr = first_pdr; + void *end = (void *)first_pdr + MAX_PDA_SIZE; + + while (((void *)pdr < end) && + (pdr_id(pdr) != PDI_END)) { + /* + * PDR area is currently not terminated by PDI_END. + * It's followed by CRC records, which have the type + * field where PDR has length. The type can be 0 or 1. + */ + if (pdr_len(pdr) < 2) + return NULL; + + /* If the record ID matches, we are done */ + if (pdr_id(pdr) == record_id) + return pdr; + + pdr = (struct pdr *) pdr->next; + } + return NULL; +} + +/* Scan production data items for a particular entry */ +static struct pdi * +hermes_find_pdi(struct pdi *first_pdi, u32 record_id) +{ + struct pdi *pdi = first_pdi; + + while (pdi_id(pdi) != PDI_END) { + + /* If the record ID matches, we are done */ + if (pdi_id(pdi) == record_id) + return pdi; + + pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; + } + return NULL; +} + +/* Process one Plug Data Item - find corresponding PDR and plug it */ +static int +hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) +{ + struct pdr *pdr; + + /* Find the PDR corresponding to this PDI */ + pdr = hermes_find_pdr(first_pdr, pdi_id(pdi)); + + /* No match is found, safe to ignore */ + if (!pdr) + return 0; + + /* Lengths of the data in PDI and PDR must match */ + if (pdi_len(pdi) != pdr_len(pdr)) + return -EINVAL; + + /* do the actual plugging */ + hermes_aux_setaddr(hw, pdr_addr(pdr)); + hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi)); + + return 0; +} + +/* Read PDA from the adapter */ +int hermes_read_pda(hermes_t *hw, + __le16 *pda, + u32 pda_addr, + u16 pda_len, + int use_eeprom) /* can we get this into hw? */ +{ + int ret; + u16 pda_size; + u16 data_len = pda_len; + __le16 *data = pda; + + if (use_eeprom) { + /* PDA of spectrum symbol is in eeprom */ + + /* Issue command to read EEPROM */ + ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); + if (ret) + return ret; + } else { + /* wl_lkm does not include PDA size in the PDA area. + * We will pad the information into pda, so other routines + * don't have to be modified */ + pda[0] = cpu_to_le16(pda_len - 2); + /* Includes CFG_PROD_DATA but not itself */ + pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ + data_len = pda_len - 4; + data = pda + 2; + } + + /* Open auxiliary port */ + ret = hermes_aux_control(hw, 1); + printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret); + if (ret) + return ret; + + /* read PDA from EEPROM */ + hermes_aux_setaddr(hw, pda_addr); + hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2); + + /* Close aux port */ + ret = hermes_aux_control(hw, 0); + printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret); + + /* Check PDA length */ + pda_size = le16_to_cpu(pda[0]); + printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n", + pda_size, pda_len); + if (pda_size > pda_len) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(hermes_read_pda); + +/* Parse PDA and write the records into the adapter + * + * Attempt to write every records that is in the specified pda + * which also has a valid production data record for the firmware. + */ +int hermes_apply_pda(hermes_t *hw, + const char *first_pdr, + const __le16 *pda) +{ + int ret; + const struct pdi *pdi; + struct pdr *pdr; + + pdr = (struct pdr *) first_pdr; + + /* Go through every PDI and plug them into the adapter */ + pdi = (const struct pdi *) (pda + 2); + while (pdi_id(pdi) != PDI_END) { + ret = hermes_plug_pdi(hw, pdr, pdi); + if (ret) + return ret; + + /* Increment to the next PDI */ + pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)]; + } + return 0; +} +EXPORT_SYMBOL(hermes_apply_pda); + +/* Identify the total number of bytes in all blocks + * including the header data. + */ +size_t +hermes_blocks_length(const char *first_block) +{ + const struct dblock *blk = (const struct dblock *) first_block; + int total_len = 0; + int len; + + /* Skip all blocks to locate Plug Data References + * (Spectrum CS) */ + while (dblock_addr(blk) != BLOCK_END) { + len = dblock_len(blk); + total_len += sizeof(*blk) + len; + blk = (struct dblock *) &blk->data[len]; + } + + return total_len; +} +EXPORT_SYMBOL(hermes_blocks_length); + +/*** Hermes programming ***/ + +/* About to start programming data (Hermes I) + * offset is the entry point + * + * Spectrum_cs' Symbol fw does not require this + * wl_lkm Agere fw does + * Don't know about intersil + */ +int hermesi_program_init(hermes_t *hw, u32 offset) +{ + int err; + + /* Disable interrupts?*/ + /*hw->inten = 0x0;*/ + /*hermes_write_regn(hw, INTEN, 0);*/ + /*hermes_set_irqmask(hw, 0);*/ + + /* Acknowledge any outstanding command */ + hermes_write_regn(hw, EVACK, 0xFFFF); + + /* Using doicmd_wait rather than docmd_wait */ + err = hermes_doicmd_wait(hw, + 0x0100 | HERMES_CMD_INIT, + 0, 0, 0, NULL); + if (err) + return err; + + err = hermes_doicmd_wait(hw, + 0x0000 | HERMES_CMD_INIT, + 0, 0, 0, NULL); + if (err) + return err; + + err = hermes_aux_control(hw, 1); + printk(KERN_DEBUG PFX "AUX enable returned %d\n", err); + + if (err) + return err; + + printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset); + err = hermes_doicmd_wait(hw, + HERMES_PROGRAM_ENABLE_VOLATILE, + offset & 0xFFFFu, + offset >> 16, + 0, + NULL); + printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n", + err); + + return err; +} +EXPORT_SYMBOL(hermesi_program_init); + +/* Done programming data (Hermes I) + * + * Spectrum_cs' Symbol fw does not require this + * wl_lkm Agere fw does + * Don't know about intersil + */ +int hermesi_program_end(hermes_t *hw) +{ + struct hermes_response resp; + int rc = 0; + int err; + + rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); + + printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, " + "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", + rc, resp.resp0, resp.resp1, resp.resp2); + + if ((rc == 0) && + ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) + rc = -EIO; + + err = hermes_aux_control(hw, 0); + printk(KERN_DEBUG PFX "AUX disable returned %d\n", err); + + /* Acknowledge any outstanding command */ + hermes_write_regn(hw, EVACK, 0xFFFF); + + /* Reinitialise, ignoring return */ + (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT, + 0, 0, 0, NULL); + + return rc ? rc : err; +} +EXPORT_SYMBOL(hermesi_program_end); + +/* Program the data blocks */ +int hermes_program(hermes_t *hw, const char *first_block, const char *end) +{ + const struct dblock *blk; + u32 blkaddr; + u32 blklen; +#if LIMIT_PROGRAM_SIZE + u32 addr; + u32 len; +#endif + + blk = (const struct dblock *) first_block; + + if ((const char *) blk > (end - sizeof(*blk))) + return -EIO; + + blkaddr = dblock_addr(blk); + blklen = dblock_len(blk); + + while ((blkaddr != BLOCK_END) && + (((const char *) blk + blklen) <= end)) { + printk(KERN_DEBUG PFX + "Programming block of length %d to address 0x%08x\n", + blklen, blkaddr); + +#if !LIMIT_PROGRAM_SIZE + /* wl_lkm driver splits this into writes of 2000 bytes */ + hermes_aux_setaddr(hw, blkaddr); + hermes_write_bytes(hw, HERMES_AUXDATA, blk->data, + blklen); +#else + len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE; + addr = blkaddr; + + while (addr < (blkaddr + blklen)) { + printk(KERN_DEBUG PFX + "Programming subblock of length %d " + "to address 0x%08x. Data @ %p\n", + len, addr, &blk->data[addr - blkaddr]); + + hermes_aux_setaddr(hw, addr); + hermes_write_bytes(hw, HERMES_AUXDATA, + &blk->data[addr - blkaddr], + len); + + addr += len; + len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ? + (blkaddr + blklen - addr) : MAX_DL_SIZE; + } +#endif + blk = (const struct dblock *) &blk->data[blklen]; + + if ((const char *) blk > (end - sizeof(*blk))) + return -EIO; + + blkaddr = dblock_addr(blk); + blklen = dblock_len(blk); + } + return 0; +} +EXPORT_SYMBOL(hermes_program); + +static int __init init_hermes_dld(void) +{ + return 0; +} + +static void __exit exit_hermes_dld(void) +{ +} + +module_init(init_hermes_dld); +module_exit(exit_hermes_dld); + +/*** Default plugging data for Hermes I ***/ +/* Values from wl_lkm_718/hcf/dhf.c */ + +#define DEFINE_DEFAULT_PDR(pid, length, data) \ +static const struct { \ + __le16 len; \ + __le16 id; \ + u8 val[length]; \ +} __attribute__ ((packed)) default_pdr_data_##pid = { \ + __constant_cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ + sizeof(__le16)) - 1), \ + __constant_cpu_to_le16(pid), \ + data \ +} + +#define DEFAULT_PDR(pid) default_pdr_data_##pid + +/* HWIF Compatiblity */ +DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00"); + +/* PPPPSign */ +DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00"); + +/* PPPPProf */ +DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00"); + +/* Antenna diversity */ +DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F"); + +/* Modem VCO band Set-up */ +DEFINE_DEFAULT_PDR(0x0160, 28, + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00"); + +/* Modem Rx Gain Table Values */ +DEFINE_DEFAULT_PDR(0x0161, 256, + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3E\01\x3E\x01\x3D\x01" + "\x3D\x01\x3C\01\x3C\x01\x3B\x01" + "\x3B\x01\x3A\01\x3A\x01\x39\x01" + "\x39\x01\x38\01\x38\x01\x37\x01" + "\x37\x01\x36\01\x36\x01\x35\x01" + "\x35\x01\x34\01\x34\x01\x33\x01" + "\x33\x01\x32\x01\x32\x01\x31\x01" + "\x31\x01\x30\x01\x30\x01\x7B\x01" + "\x7B\x01\x7A\x01\x7A\x01\x79\x01" + "\x79\x01\x78\x01\x78\x01\x77\x01" + "\x77\x01\x76\x01\x76\x01\x75\x01" + "\x75\x01\x74\x01\x74\x01\x73\x01" + "\x73\x01\x72\x01\x72\x01\x71\x01" + "\x71\x01\x70\x01\x70\x01\x68\x01" + "\x68\x01\x67\x01\x67\x01\x66\x01" + "\x66\x01\x65\x01\x65\x01\x57\x01" + "\x57\x01\x56\x01\x56\x01\x55\x01" + "\x55\x01\x54\x01\x54\x01\x53\x01" + "\x53\x01\x52\x01\x52\x01\x51\x01" + "\x51\x01\x50\x01\x50\x01\x48\x01" + "\x48\x01\x47\x01\x47\x01\x46\x01" + "\x46\x01\x45\x01\x45\x01\x44\x01" + "\x44\x01\x43\x01\x43\x01\x42\x01" + "\x42\x01\x41\x01\x41\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01"); + +/* Write PDA according to certain rules. + * + * For every production data record, look for a previous setting in + * the pda, and use that. + * + * For certain records, use defaults if they are not found in pda. + */ +int hermes_apply_pda_with_defaults(hermes_t *hw, + const char *first_pdr, + const __le16 *pda) +{ + const struct pdr *pdr = (const struct pdr *) first_pdr; + struct pdi *first_pdi = (struct pdi *) &pda[2]; + struct pdi *pdi; + struct pdi *default_pdi = NULL; + struct pdi *outdoor_pdi; + void *end = (void *)first_pdr + MAX_PDA_SIZE; + int record_id; + + while (((void *)pdr < end) && + (pdr_id(pdr) != PDI_END)) { + /* + * For spectrum_cs firmwares, + * PDR area is currently not terminated by PDI_END. + * It's followed by CRC records, which have the type + * field where PDR has length. The type can be 0 or 1. + */ + if (pdr_len(pdr) < 2) + break; + record_id = pdr_id(pdr); + + pdi = hermes_find_pdi(first_pdi, record_id); + if (pdi) + printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", + record_id, pdi); + + switch (record_id) { + case 0x110: /* Modem REFDAC values */ + case 0x120: /* Modem VGDAC values */ + outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1); + default_pdi = NULL; + if (outdoor_pdi) { + pdi = outdoor_pdi; + printk(KERN_DEBUG PFX + "Using outdoor record 0x%04x at %p\n", + record_id + 1, pdi); + } + break; + case 0x5: /* HWIF Compatiblity */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005); + break; + case 0x108: /* PPPPSign */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108); + break; + case 0x109: /* PPPPProf */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109); + break; + case 0x150: /* Antenna diversity */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150); + break; + case 0x160: /* Modem VCO band Set-up */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160); + break; + case 0x161: /* Modem Rx Gain Table Values */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161); + break; + default: + default_pdi = NULL; + break; + } + if (!pdi && default_pdi) { + /* Use default */ + pdi = default_pdi; + printk(KERN_DEBUG PFX + "Using default record 0x%04x at %p\n", + record_id, pdi); + } + + if (pdi) { + /* Lengths of the data in PDI and PDR must match */ + if (pdi_len(pdi) == pdr_len(pdr)) { + /* do the actual plugging */ + hermes_aux_setaddr(hw, pdr_addr(pdr)); + hermes_write_bytes(hw, HERMES_AUXDATA, + pdi->data, pdi_len(pdi)); + } + } + + pdr++; + } + return 0; +} +EXPORT_SYMBOL(hermes_apply_pda_with_defaults); diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/hermes_dld.h new file mode 100644 index 00000000000..6fcb2627799 --- /dev/null +++ b/drivers/net/wireless/hermes_dld.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007, David Kilroy + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ +#ifndef _HERMES_DLD_H +#define _HERMES_DLD_H + +#include "hermes.h" + +int hermesi_program_init(hermes_t *hw, u32 offset); +int hermesi_program_end(hermes_t *hw); +int hermes_program(hermes_t *hw, const char *first_block, const char *end); + +int hermes_read_pda(hermes_t *hw, + __le16 *pda, + u32 pda_addr, + u16 pda_len, + int use_eeprom); +int hermes_apply_pda(hermes_t *hw, + const char *first_pdr, + const __le16 *pda); +int hermes_apply_pda_with_defaults(hermes_t *hw, + const char *first_pdr, + const __le16 *pda); + +size_t hermes_blocks_length(const char *first_block); + +#endif /* _HERMES_DLD_H */ diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h index 4f46b4809e5..42eb67dea1d 100644 --- a/drivers/net/wireless/hermes_rid.h +++ b/drivers/net/wireless/hermes_rid.h @@ -30,6 +30,7 @@ #define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 #define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 #define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 +#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22 #define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 #define HERMES_RID_CNFDEFAULTKEY0 0xFC24 #define HERMES_RID_CNFDEFAULTKEY1 0xFC25 @@ -85,6 +86,16 @@ #define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 #define HERMES_RID_CNFBASICRATES 0xFCB3 #define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 +#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4 +#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5 +#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6 +#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7 +#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8 +#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9 +#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA +#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB +#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 +#define HERMES_RID_CNFDISASSOCIATE 0xFCC8 #define HERMES_RID_CNFTICKTIME 0xFCE0 #define HERMES_RID_CNFSCANREQUEST 0xFCE1 #define HERMES_RID_CNFJOINREQUEST 0xFCE2 @@ -137,6 +148,12 @@ #define HERMES_RID_CURRENTTXRATE6 0xFD85 #define HERMES_RID_OWNMACADDR 0xFD86 #define HERMES_RID_SCANRESULTSTABLE 0xFD88 +#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89 +#define HERMES_RID_CURRENT_WPA_IE 0xFD8A +#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B +#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C +#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D +#define HERMES_RID_TXQUEUEEMPTY 0xFD91 #define HERMES_RID_PHYTYPE 0xFDC0 #define HERMES_RID_CURRENTCHANNEL 0xFDC1 #define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 3b4e55cf33c..63374027735 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -234,7 +234,7 @@ static void sandisk_set_iobase(local_info_t *local) reg.Value = hw_priv->link->io.BasePort1 & 0x00ff; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" " res=%d\n", res); } @@ -246,7 +246,7 @@ static void sandisk_set_iobase(local_info_t *local) reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" " res=%d\n", res); } @@ -305,7 +305,7 @@ static int sandisk_enable_wireless(struct net_device *dev) tuple.DesiredTuple = CISTPL_LONGLINK_MFC; if (pcmcia_get_first_tuple(hw_priv->link, &tuple) || pcmcia_get_tuple_data(hw_priv->link, &tuple) || - pcmcia_parse_tuple(hw_priv->link, &tuple, parse) || + pcmcia_parse_tuple(&tuple, parse) || parse->longlink_mfc.nfn < 2) { /* No multi-function links found */ ret = -ENODEV; @@ -322,7 +322,7 @@ static int sandisk_enable_wireless(struct net_device *dev) reg.Value = COR_SOFT_RESET; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", dev->name, res); goto done; @@ -339,7 +339,7 @@ static int sandisk_enable_wireless(struct net_device *dev) reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", dev->name, res); goto done; @@ -374,7 +374,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local) reg.Value = 0; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", res); return; @@ -386,7 +386,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local) reg.Value |= COR_SOFT_RESET; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", res); return; @@ -399,7 +399,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local) reg.Value |= COR_IREQ_ENA; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", res); return; @@ -433,7 +433,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Value = 0; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 " "(%d)\n", res); return; @@ -446,7 +446,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Value |= COR_SOFT_RESET; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 " "(%d)\n", res); return; @@ -460,7 +460,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Offset = CISREG_CCSR; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 " "(%d)\n", res); return; @@ -472,7 +472,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Value = old_cor & ~COR_SOFT_RESET; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 " "(%d)\n", res); return; @@ -532,145 +532,118 @@ static void prism2_detach(struct pcmcia_device *link) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -#define CFG_CHECK2(fn, retf) \ -do { int _ret = (retf); \ -if (_ret != 0) { \ - PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", _ret); \ - cs_error(link, fn, _ret); \ - goto next_entry; \ -} \ -} while (0) - /* run after a CARD_INSERTION event is received to configure the PCMCIA * socket and make the device available to the system */ + +static int prism2_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->index == 0) + return -ENODEV; + + PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " + "(default 0x%02X)\n", cfg->index, dflt->index); + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + p_dev->conf.Attributes |= CONF_ENABLE_SPKR; + p_dev->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / + 10000 && !ignore_cis_vcc) { + PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" + " this entry\n"); + return -ENODEV; + } + } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / + 10000 && !ignore_cis_vcc) { + PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " + "- skipping this entry\n"); + return -ENODEV; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + else if (!(p_dev->conf.Attributes & CONF_ENABLE_IRQ)) { + /* At least Compaq WL200 does not have IRQInfo1 set, + * but it does not work without interrupts.. */ + printk(KERN_WARNING "Config has no IRQ info, but trying to " + "enable IRQ anyway..\n"); + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + } + + /* IO window settings */ + PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " + "dflt->io.nwin=%d\n", + cfg->io.nwin, dflt->io.nwin); + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " + "io.base=0x%04x, len=%d\n", io->flags, + io->win[0].base, io->win[0].len); + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & + CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + return pcmcia_request_io(p_dev, &p_dev->io); +} + static int prism2_config(struct pcmcia_device *link) { struct net_device *dev; struct hostap_interface *iface; local_info_t *local; int ret = 1; - tuple_t tuple; - cisparse_t *parse; int last_fn, last_ret; - u_char buf[64]; - config_info_t conf; - cistpl_cftable_entry_t dflt = { 0 }; struct hostap_cs_priv *hw_priv; PDEBUG(DEBUG_FLOW, "prism2_config()\n"); - parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (parse == NULL || hw_priv == NULL) { + if (hw_priv == NULL) { ret = -ENOMEM; goto failed; } - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link, &conf)); - /* Look for an appropriate configuration table entry in the CIS */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - for (;;) { - cistpl_cftable_entry_t *cfg = &(parse->cftable_entry); - CFG_CHECK2(GetTupleData, - pcmcia_get_tuple_data(link, &tuple)); - CFG_CHECK2(ParseTuple, - pcmcia_parse_tuple(link, &tuple, parse)); - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " - "(default 0x%02X)\n", cfg->index, dflt.index); - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / - 10000 && !ignore_cis_vcc) { - PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" - " this entry\n"); - goto next_entry; - } - } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / - 10000 && !ignore_cis_vcc) { - PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " - "- skipping this entry\n"); - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) { - /* At least Compaq WL200 does not have IRQInfo1 set, - * but it does not work without interrupts.. */ - printk("Config has no IRQ info, but trying to enable " - "IRQ anyway..\n"); - link->conf.Attributes |= CONF_ENABLE_IRQ; - } - - /* IO window settings */ - PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " - "dflt.io.nwin=%d\n", - cfg->io.nwin, dflt.io.nwin); - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " - "io.base=0x%04x, len=%d\n", io->flags, - io->win[0].base, io->win[0].len); - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = io->flags & - CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK2(RequestIO, - pcmcia_request_io(link, &link->io)); - - /* This configuration table entry is OK */ - break; - - next_entry: - CS_CHECK(GetNextTuple, - pcmcia_get_next_tuple(link, &tuple)); + last_ret = pcmcia_loop_config(link, prism2_config_check, NULL); + if (last_ret) { + if (!ignore_cis_vcc) + printk(KERN_ERR "GetNextTuple(): No matching " + "CIS configuration. Maybe you need the " + "ignore_cis_vcc=1 parameter.\n"); + cs_error(link, RequestIO, last_ret); + goto failed; } /* Need to allocate net_device before requesting IRQ handler */ @@ -738,14 +711,12 @@ static int prism2_config(struct pcmcia_device *link) if (ret == 0 && local->ddev) strcpy(hw_priv->node.dev_name, local->ddev->name); } - kfree(parse); return ret; cs_failed: cs_error(link, last_fn, last_ret); failed: - kfree(parse); kfree(hw_priv); prism2_release((u_long)link); return ret; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 19a401c4a0d..bca74811bc7 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -211,7 +211,7 @@ static u32 ipw2100_debug_level = IPW_DL_NONE; do { \ if (ipw2100_debug_level & (level)) { \ printk(KERN_DEBUG "ipw2100: %c %s ", \ - in_interrupt() ? 'I' : 'U', __FUNCTION__); \ + in_interrupt() ? 'I' : 'U', __func__); \ printk(message); \ } \ } while (0) diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index d4ab28b73b3..0bad1ec3e7e 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1394,13 +1394,13 @@ BIT_ARG16(x) #define IPW_DEBUG(level, fmt, args...) \ do { if (ipw_debug_level & (level)) \ printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) #ifdef CONFIG_IPW2200_DEBUG #define IPW_LL_DEBUG(level, fmt, args...) \ do { if (ipw_debug_level & (level)) \ printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) #else #define IPW_LL_DEBUG(level, fmt, args...) do {} while (0) #endif /* CONFIG_IPW2200_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h index f1d002f7b79..33016fb5e9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h @@ -34,12 +34,12 @@ extern u32 iwl3945_debug_level; #define IWL_DEBUG(level, fmt, args...) \ do { if (iwl3945_debug_level & (level)) \ printk(KERN_ERR DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) #define IWL_DEBUG_LIMIT(level, fmt, args...) \ do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \ printk(KERN_ERR DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) static inline void iwl3945_print_hex_dump(int level, void *p, u32 len) { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index 0b947511461..b3fe48de3ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -59,7 +59,7 @@ * */ -#define _iwl3945_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs)) +#define _iwl3945_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs)) #ifdef CONFIG_IWL3945_DEBUG static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *priv, u32 ofs, u32 val) @@ -73,14 +73,14 @@ static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv * #define iwl3945_write32(priv, ofs, val) _iwl3945_write32(priv, ofs, val) #endif -#define _iwl3945_read32(priv, ofs) readl((priv)->hw_base + (ofs)) +#define _iwl3945_read32(priv, ofs) ioread32((priv)->hw_base + (ofs)) #ifdef CONFIG_IWL3945_DEBUG static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *priv, u32 ofs) { IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); return _iwl3945_read32(priv, ofs); } -#define iwl3945_read32(priv, ofs) __iwl3945_read32(__FILE__, __LINE__, priv, ofs) +#define iwl3945_read32(priv, ofs)__iwl3945_read32(__FILE__, __LINE__, priv, ofs) #else #define iwl3945_read32(p, o) _iwl3945_read32(p, o) #endif @@ -153,28 +153,10 @@ static inline void __iwl3945_clear_bit(const char *f, u32 l, static inline int _iwl3945_grab_nic_access(struct iwl3945_priv *priv) { int ret; - u32 gp_ctl; - #ifdef CONFIG_IWL3945_DEBUG if (atomic_read(&priv->restrict_refcnt)) return 0; #endif - if (test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARNING("WARNING: Requesting MAC access during RFKILL " - "wakes up NIC\n"); - - /* 10 msec allows time for NIC to complete its data save */ - gp_ctl = _iwl3945_read32(priv, CSR_GP_CNTRL); - if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { - IWL_DEBUG_RF_KILL("Wait for complete power-down, " - "gpctl = 0x%08x\n", gp_ctl); - mdelay(10); - } else - IWL_DEBUG_RF_KILL("power-down complete, " - "gpctl = 0x%08x\n", gp_ctl); - } - /* this bit wakes up the NIC */ _iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); ret = _iwl3945_poll_bit(priv, CSR_GP_CNTRL, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 10c64bdb314..6fc5e7361f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -36,8 +36,6 @@ #include <linux/workqueue.h> -#include "../net/mac80211/rate.h" - #include "iwl-3945.h" #define RS_NAME "iwl-3945-rs" @@ -65,6 +63,9 @@ struct iwl3945_rs_sta { u8 ibss_sta_added; struct timer_list rate_scale_flush; struct iwl3945_rate_scale_data win[IWL_RATE_COUNT]; + + /* used to be in sta_info */ + int last_txrate_idx; }; static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT] = { @@ -316,9 +317,10 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, } } -static void rs_rate_init(void *priv_rate, void *priv_sta, - struct ieee80211_local *local, struct sta_info *sta) +static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta) { + struct iwl3945_rs_sta *rs_sta = priv_sta; int i; IWL_DEBUG_RATE("enter\n"); @@ -329,24 +331,22 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, * after assoc.. */ for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { - if (sta->supp_rates[local->hw.conf.channel->band] & (1 << i)) { - sta->txrate_idx = i; + if (sta->supp_rates[sband->band] & (1 << i)) { + rs_sta->last_txrate_idx = i; break; } } - sta->last_txrate_idx = sta->txrate_idx; - /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ - if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) - sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + if (sband->band == IEEE80211_BAND_5GHZ) + rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; IWL_DEBUG_RATE("leave\n"); } -static void *rs_alloc(struct ieee80211_local *local) +static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - return local->hw.priv; + return hw->priv; } /* rate scale requires free function to be implemented */ @@ -354,17 +354,24 @@ static void rs_free(void *priv) { return; } + static void rs_clear(void *priv) { return; } -static void *rs_alloc_sta(void *priv, gfp_t gfp) +static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl3945_rs_sta *rs_sta; + struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; int i; + /* + * XXX: If it's using sta->drv_priv anyway, it might + * as well just put all the information there. + */ + IWL_DEBUG_RATE("enter\n"); rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp); @@ -373,6 +380,8 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp) return NULL; } + psta->rs_sta = rs_sta; + spin_lock_init(&rs_sta->lock); rs_sta->start_rate = IWL_RATE_INVALID; @@ -398,10 +407,14 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp) return rs_sta; } -static void rs_free_sta(void *priv, void *priv_sta) +static void rs_free_sta(void *priv, struct ieee80211_sta *sta, + void *priv_sta) { + struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; struct iwl3945_rs_sta *rs_sta = priv_sta; + psta->rs_sta = NULL; + IWL_DEBUG_RATE("enter\n"); del_timer_sync(&rs_sta->rate_scale_flush); kfree(rs_sta); @@ -443,26 +456,19 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) * NOTE: Uses iwl3945_priv->retry_rate for the # of retries attempted by * the hardware for each rate. */ -static void rs_tx_status(void *priv_rate, - struct net_device *dev, +static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { u8 retries, current_count; int scale_rate_index, first_index, last_index; unsigned long flags; - struct sta_info *sta; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct iwl3945_rs_sta *rs_sta; - struct ieee80211_supported_band *sband; + struct iwl3945_rs_sta *rs_sta = priv_sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - retries = info->status.retry_count; first_index = sband->bitrates[info->tx_rate_idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { @@ -470,17 +476,11 @@ static void rs_tx_status(void *priv_rate, return; } - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - if (!sta || !sta->rate_ctrl_priv) { - rcu_read_unlock(); + if (!priv_sta) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); return; } - rs_sta = (void *)sta->rate_ctrl_priv; - rs_sta->tx_packets++; scale_rate_index = first_index; @@ -547,8 +547,6 @@ static void rs_tx_status(void *priv_rate, spin_unlock_irqrestore(&rs_sta->lock, flags); - rcu_read_unlock(); - IWL_DEBUG_RATE("leave\n"); return; @@ -632,16 +630,15 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, * rate table and must reference the driver allocated rate table * */ -static void rs_get_rate(void *priv_rate, struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + struct sk_buff *skb, struct rate_selection *sel) { u8 low = IWL_RATE_INVALID; u8 high = IWL_RATE_INVALID; u16 high_low; int index; - struct iwl3945_rs_sta *rs_sta; + struct iwl3945_rs_sta *rs_sta = priv_sta; struct iwl3945_rate_scale_data *window = NULL; int current_tpt = IWL_INV_TPT; int low_tpt = IWL_INV_TPT; @@ -649,40 +646,31 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, u32 fail_count; s8 scale_action = 0; unsigned long flags; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct sta_info *sta; u16 fc, rate_mask; - struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; + struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; DECLARE_MAC_BUF(mac); IWL_DEBUG_RATE("enter\n"); - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - /* Send management frames and broadcast/multicast data using lowest * rate. */ fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || - !sta || !sta->rate_ctrl_priv) { + !sta || !priv_sta) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate_idx = rate_lowest_index(local, sband, sta); - rcu_read_unlock(); + sel->rate_idx = rate_lowest_index(sband, sta); return; } rate_mask = sta->supp_rates[sband->band]; - index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); + index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); if (sband->band == IEEE80211_BAND_5GHZ) rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; - rs_sta = (void *)sta->rate_ctrl_priv; - - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !rs_sta->ibss_sta_added) { u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); @@ -803,17 +791,13 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, out: - sta->last_txrate_idx = index; + rs_sta->last_txrate_idx = index; if (sband->band == IEEE80211_BAND_5GHZ) - sta->txrate_idx = sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; + sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; else - sta->txrate_idx = sta->last_txrate_idx; - - rcu_read_unlock(); + sel->rate_idx = rs_sta->last_txrate_idx; IWL_DEBUG_RATE("leave: %d\n", index); - - sel->rate_idx = sta->txrate_idx; } static struct rate_control_ops rs_ops = { @@ -829,114 +813,28 @@ static struct rate_control_ops rs_ops = { .free_sta = rs_free_sta, }; -int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct iwl3945_priv *priv = hw->priv; - struct iwl3945_rs_sta *rs_sta; - struct sta_info *sta; - unsigned long flags; - int count = 0, i; - u32 samples = 0, success = 0, good = 0; - unsigned long now = jiffies; - u32 max_time = 0; - - rcu_read_lock(); - - sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); - if (!sta || !sta->rate_ctrl_priv) { - if (sta) - IWL_DEBUG_RATE("leave - no private rate data!\n"); - else - IWL_DEBUG_RATE("leave - no station!\n"); - rcu_read_unlock(); - return sprintf(buf, "station %d not found\n", sta_id); - } - - rs_sta = (void *)sta->rate_ctrl_priv; - spin_lock_irqsave(&rs_sta->lock, flags); - i = IWL_RATE_54M_INDEX; - while (1) { - u64 mask; - int j; - - count += - sprintf(&buf[count], " %2dMbs: ", iwl3945_rates[i].ieee / 2); - - mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); - for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) - buf[count++] = - (rs_sta->win[i].data & mask) ? '1' : '0'; - - samples += rs_sta->win[i].counter; - good += rs_sta->win[i].success_counter; - success += rs_sta->win[i].success_counter * - iwl3945_rates[i].ieee; - - if (rs_sta->win[i].stamp) { - int delta = - jiffies_to_msecs(now - rs_sta->win[i].stamp); - - if (delta > max_time) - max_time = delta; - - count += sprintf(&buf[count], "%5dms\n", delta); - } else - buf[count++] = '\n'; - - j = iwl3945_get_prev_ieee_rate(i); - if (j == i) - break; - i = j; - } - spin_unlock_irqrestore(&rs_sta->lock, flags); - rcu_read_unlock(); - - /* Display the average rate of all samples taken. - * - * NOTE: We multiple # of samples by 2 since the IEEE measurement - * added from iwl3945_rates is actually 2X the rate */ - if (samples) - count += sprintf( - &buf[count], - "\nAverage rate is %3d.%02dMbs over last %4dms\n" - "%3d%% success (%d good packets over %d tries)\n", - success / (2 * samples), (success * 5 / samples) % 10, - max_time, good * 100 / samples, good, samples); - else - count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n"); - - return count; -} - void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) { struct iwl3945_priv *priv = hw->priv; s32 rssi = 0; unsigned long flags; - struct ieee80211_local *local = hw_to_local(hw); struct iwl3945_rs_sta *rs_sta; - struct sta_info *sta; + struct ieee80211_sta *sta; + struct iwl3945_sta_priv *psta; IWL_DEBUG_RATE("enter\n"); - if (!local->rate_ctrl->ops->name || - strcmp(local->rate_ctrl->ops->name, RS_NAME)) { - IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n"); - IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n"); - return; - } - rcu_read_lock(); - sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); - if (!sta || !sta->rate_ctrl_priv) { + sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); + psta = (void *) sta->drv_priv; + if (!sta || !psta) { IWL_DEBUG_RATE("leave - no private rate data!\n"); rcu_read_unlock(); return; } - rs_sta = (void *)sta->rate_ctrl_priv; + rs_sta = psta->rs_sta; spin_lock_irqsave(&rs_sta->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h index f085d330bdc..98b17ae6ef2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h @@ -176,15 +176,6 @@ static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index) } /** - * iwl3945_fill_rs_info - Fill an output text buffer with the rate representation - * - * NOTE: This is provided as a quick mechanism for a user to visualize - * the performance of the rate control algorithm and is not meant to be - * parsed software. - */ -extern int iwl3945_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); - -/** * 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 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 3f51f363534..7ca5627cc07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -520,10 +520,10 @@ static int iwl3945_is_network_packet(struct iwl3945_priv *priv, /* Filter incoming packets to determine if they are targeted toward * this network, discarding packets coming from ourselves */ switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */ /* packets to our IBSS update information */ return !compare_ether_addr(header->addr3, priv->bssid); - case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ /* packets to our IBSS update information */ return !compare_ether_addr(header->addr2, priv->bssid); default: @@ -531,99 +531,6 @@ static int iwl3945_is_network_packet(struct iwl3945_priv *priv, } } -static void iwl3945_add_radiotap(struct iwl3945_priv *priv, - struct sk_buff *skb, - struct iwl3945_rx_frame_hdr *rx_hdr, - struct ieee80211_rx_status *stats) -{ - /* First cache any information we need before we overwrite - * the information provided in the skb from the hardware */ - s8 signal = stats->signal; - s8 noise = 0; - int rate = stats->rate_idx; - u64 tsf = stats->mactime; - __le16 phy_flags_hw = rx_hdr->phy_flags, antenna; - - struct iwl3945_rt_rx_hdr { - struct ieee80211_radiotap_header rt_hdr; - __le64 rt_tsf; /* TSF */ - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channelMHz; /* channel in MHz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ - s8 rt_dbmnoise; - u8 rt_antenna; /* antenna number */ - } __attribute__ ((packed)) *iwl3945_rt; - - if (skb_headroom(skb) < sizeof(*iwl3945_rt)) { - if (net_ratelimit()) - printk(KERN_ERR "not enough headroom [%d] for " - "radiotap head [%zd]\n", - skb_headroom(skb), sizeof(*iwl3945_rt)); - return; - } - - /* put radiotap header in front of 802.11 header and data */ - iwl3945_rt = (void *)skb_push(skb, sizeof(*iwl3945_rt)); - - /* initialise radiotap header */ - iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl3945_rt->rt_hdr.it_pad = 0; - - /* total header + data */ - put_unaligned_le16(sizeof(*iwl3945_rt), &iwl3945_rt->rt_hdr.it_len); - - /* Indicate all the fields we add to the radiotap header */ - put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA), - &iwl3945_rt->rt_hdr.it_present); - - /* Zero the flags, we'll add to them as we go */ - iwl3945_rt->rt_flags = 0; - - put_unaligned_le64(tsf, &iwl3945_rt->rt_tsf); - - iwl3945_rt->rt_dbmsignal = signal; - iwl3945_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - put_unaligned_le16(stats->freq, &iwl3945_rt->rt_channelMHz); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, - &iwl3945_rt->rt_chbitmask); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, - &iwl3945_rt->rt_chbitmask); - else /* 802.11g */ - put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, - &iwl3945_rt->rt_chbitmask); - - if (rate == -1) - iwl3945_rt->rt_rate = 0; - else { - if (stats->band == IEEE80211_BAND_5GHZ) - rate += IWL_FIRST_OFDM_RATE; - - iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee; - } - - /* antenna number */ - antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; - iwl3945_rt->rt_antenna = le16_to_cpu(antenna) >> 4; - - /* set the preamble flag if we have it */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - stats->flag |= RX_FLAG_RADIOTAP; -} - static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) @@ -657,9 +564,6 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv, iwl3945_set_decrypted_flag(priv, rxb->skb, le32_to_cpu(rx_end->status), stats); - if (priv->add_radiotap) - iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats); - #ifdef CONFIG_IWL3945_LEDS if (ieee80211_is_data(hdr->frame_control)) priv->rxtxpackets += len; @@ -684,7 +588,6 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); u8 network_packet; - rx_status.antenna = 0; rx_status.flag = 0; rx_status.mactime = le64_to_cpu(rx_end->timestamp); rx_status.freq = @@ -696,6 +599,13 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, if (rx_status.band == IEEE80211_BAND_5GHZ) rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; + rx_status.antenna = le16_to_cpu(rx_hdr->phy_flags & + RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if appropriate */ + if (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + rx_status.flag |= RX_FLAG_SHORTPRE; + if ((unlikely(rx_stats->phy_count > 20))) { IWL_DEBUG_DROP ("dsp size out of range [0,20]: " @@ -771,100 +681,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, priv->last_rx_noise = rx_status.noise; } - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); - return; - } - - switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_MGMT: - switch (le16_to_cpu(header->frame_control) & - IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_RESP: - case IEEE80211_STYPE_BEACON:{ - /* If this is a beacon or probe response for - * our network then cache the beacon - * timestamp */ - if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA) - && !compare_ether_addr(header->addr2, - priv->bssid)) || - ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) - && !compare_ether_addr(header->addr3, - priv->bssid)))) { - struct ieee80211_mgmt *mgmt = - (struct ieee80211_mgmt *)header; - __le32 *pos; - pos = (__le32 *)&mgmt->u.beacon. - timestamp; - priv->timestamp0 = le32_to_cpu(pos[0]); - priv->timestamp1 = le32_to_cpu(pos[1]); - priv->beacon_int = le16_to_cpu( - mgmt->u.beacon.beacon_int); - if (priv->call_post_assoc_from_beacon && - (priv->iw_mode == - IEEE80211_IF_TYPE_STA)) - queue_work(priv->workqueue, - &priv->post_associate.work); - - priv->call_post_assoc_from_beacon = 0; - } - - break; - } - - case IEEE80211_STYPE_ACTION: - /* TODO: Parse 802.11h frames for CSA... */ - break; - - /* - * TODO: Use the new callback function from - * mac80211 instead of sniffing these packets. - */ - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP:{ - struct ieee80211_mgmt *mgnt = - (struct ieee80211_mgmt *)header; - - /* We have just associated, give some - * time for the 4-way handshake if - * any. Don't start scan too early. */ - priv->next_scan_jiffies = jiffies + - IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; - - priv->assoc_id = (~((1 << 15) | (1 << 14)) & - le16_to_cpu(mgnt->u. - assoc_resp.aid)); - priv->assoc_capability = - le16_to_cpu(mgnt->u.assoc_resp.capab_info); - if (priv->beacon_int) - queue_work(priv->workqueue, - &priv->post_associate.work); - else - priv->call_post_assoc_from_beacon = 1; - break; - } - - case IEEE80211_STYPE_PROBE_REQ:{ - DECLARE_MAC_BUF(mac1); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) - IWL_DEBUG_DROP - ("Dropping (non network): %s" - ", %s, %s\n", - print_mac(mac1, header->addr1), - print_mac(mac2, header->addr2), - print_mac(mac3, header->addr3)); - return; - } - } - - case IEEE80211_FTYPE_DATA: - /* fall through */ - default: - iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); - break; - } + iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); } int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr, @@ -990,7 +807,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, priv->stations[sta_id].current_rate.rate_n_flags = rate; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && (sta_id != priv->hw_setting.bcast_sta_id) && (sta_id != IWL_MULTICAST_ID)) priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index fa81ba1af3d..bdd32475b99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -73,6 +73,10 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; extern int iwl3945_param_hwcrypto; extern int iwl3945_param_queues_num; +struct iwl3945_sta_priv { + struct iwl3945_rs_sta *rs_sta; +}; + enum iwl3945_antenna { IWL_ANTENNA_DIVERSITY, IWL_ANTENNA_MAIN, @@ -707,7 +711,6 @@ struct iwl3945_priv { enum ieee80211_band band; int alloc_rxb_skb; - bool add_radiotap; void (*rx_handlers[REPLY_MAX])(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb); @@ -852,7 +855,7 @@ struct iwl3945_priv { /* eeprom */ struct iwl3945_eeprom eeprom; - enum ieee80211_if_types iw_mode; + enum nl80211_iftype iw_mode; struct sk_buff *ibss_beacon; @@ -895,7 +898,6 @@ struct iwl3945_priv { struct delayed_work thermal_periodic; struct delayed_work gather_stats; struct delayed_work scan_check; - struct delayed_work post_associate; #define IWL_DEFAULT_TX_POWER 0x0F s8 user_txpower_limit; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index fce950f4163..f4793a60944 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -98,16 +98,17 @@ #define IWL_RSSI_OFFSET 44 -#include "iwl-commands.h" /* PCI registers */ -#define PCI_LINK_CTRL 0x0F0 /* 1 byte */ -#define PCI_POWER_SOURCE 0x0C8 -#define PCI_REG_WUM8 0x0E8 +#define PCI_CFG_RETRY_TIMEOUT 0x041 +#define PCI_CFG_POWER_SOURCE 0x0C8 +#define PCI_REG_WUM8 0x0E8 +#define PCI_CFG_LINK_CTRL 0x0F0 /* PCI register values */ -#define PCI_LINK_VAL_L0S_EN 0x01 -#define PCI_LINK_VAL_L1_EN 0x02 +#define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01 +#define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02 +#define PCI_CFG_CMD_REG_INT_DIS_MSK 0x04 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) #define TFD_QUEUE_SIZE_MAX (256) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 23fed329896..9838de5f436 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -399,7 +399,7 @@ static void iwl4965_nic_config(struct iwl_priv *priv) unsigned long flags; u32 val; u16 radio_cfg; - u8 val_link; + u16 link; spin_lock_irqsave(&priv->lock, flags); @@ -410,10 +410,10 @@ static void iwl4965_nic_config(struct iwl_priv *priv) val & ~(1 << 11)); } - pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); + pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link); /* L1 is enabled by BIOS */ - if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN) + if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) /* diable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else @@ -1607,8 +1607,8 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) return ret; } - -int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) +#ifdef IEEE80211_CONF_CHANNEL_SWITCH +static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; @@ -1648,6 +1648,7 @@ int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); return rc; } +#endif static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 17d4f31c593..c479ee211c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -129,6 +129,13 @@ struct iwl5000_shared { __le32 padding2; } __attribute__ ((packed)); +/* calibrations defined for 5000 */ +/* defines the order in which results should be sent to the runtime uCode */ +enum iwl5000_calib { + IWL5000_CALIB_LO, + IWL5000_CALIB_TX_IQ, + IWL5000_CALIB_TX_IQ_PERD, +}; #endif /* __iwl_5000_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b08036a9d89..5155b8a760a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -209,14 +209,14 @@ static void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; u16 radio_cfg; - u8 val_link; + u16 link; spin_lock_irqsave(&priv->lock, flags); - pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); + pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link); /* L1 is enabled by BIOS */ - if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN) + if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) /* diable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else @@ -445,48 +445,6 @@ static int iwl5000_send_Xtal_calib(struct iwl_priv *priv) sizeof(cal_cmd), &cal_cmd); } -static int iwl5000_send_calib_results(struct iwl_priv *priv) -{ - int ret = 0; - - struct iwl_host_cmd hcmd = { - .id = REPLY_PHY_CALIBRATION_CMD, - .meta.flags = CMD_SIZE_HUGE, - }; - - if (priv->calib_results.lo_res) { - hcmd.len = priv->calib_results.lo_res_len; - hcmd.data = priv->calib_results.lo_res; - ret = iwl_send_cmd_sync(priv, &hcmd); - - if (ret) - goto err; - } - - if (priv->calib_results.tx_iq_res) { - hcmd.len = priv->calib_results.tx_iq_res_len; - hcmd.data = priv->calib_results.tx_iq_res; - ret = iwl_send_cmd_sync(priv, &hcmd); - - if (ret) - goto err; - } - - if (priv->calib_results.tx_iq_perd_res) { - hcmd.len = priv->calib_results.tx_iq_perd_res_len; - hcmd.data = priv->calib_results.tx_iq_perd_res; - ret = iwl_send_cmd_sync(priv, &hcmd); - - if (ret) - goto err; - } - - return 0; -err: - IWL_ERROR("Error %d\n", ret); - return ret; -} - static int iwl5000_send_calib_cfg(struct iwl_priv *priv) { struct iwl5000_calib_cfg_cmd calib_cfg_cmd; @@ -511,33 +469,30 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw; int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; - - iwl_free_calib_results(priv); + int index; /* reduce the size of the length field itself */ len -= 4; + /* Define the order in which the results will be sent to the runtime + * uCode. iwl_send_calib_results sends them in a row according to their + * index. We sort them here */ switch (hdr->op_code) { case IWL5000_PHY_CALIBRATE_LO_CMD: - priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC); - priv->calib_results.lo_res_len = len; - memcpy(priv->calib_results.lo_res, pkt->u.raw, len); + index = IWL5000_CALIB_LO; break; case IWL5000_PHY_CALIBRATE_TX_IQ_CMD: - priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC); - priv->calib_results.tx_iq_res_len = len; - memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len); + index = IWL5000_CALIB_TX_IQ; break; case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD: - priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC); - priv->calib_results.tx_iq_perd_res_len = len; - memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len); + index = IWL5000_CALIB_TX_IQ_PERD; break; default: IWL_ERROR("Unknown calibration notification %d\n", hdr->op_code); return; } + iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); } static void iwl5000_rx_calib_complete(struct iwl_priv *priv, @@ -832,7 +787,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_send_Xtal_calib(priv); if (priv->ucode_type == UCODE_RT) - iwl5000_send_calib_results(priv); + iwl_send_calib_results(priv); return 0; } @@ -878,12 +833,12 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_5100: case CSR_HW_REV_TYPE_5300: - /* 5X00 wants in Celsius */ + case CSR_HW_REV_TYPE_5350: + /* 5X00 and 5350 wants in Celsius */ priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; break; case CSR_HW_REV_TYPE_5150: - case CSR_HW_REV_TYPE_5350: - /* 5X50 wants in Kelvin */ + /* 5150 wants in Kelvin */ priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); break; @@ -1614,6 +1569,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .mod_params = &iwl50_mod_params, }; +MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode"); + module_param_named(disable50, iwl50_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable50, "manually disable the 50XX radio (default 0 [radio on])"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 90a2b6dee7c..e2a58e47703 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -35,8 +35,6 @@ #include <linux/workqueue.h> -#include "../net/mac80211/rate.h" - #include "iwl-dev.h" #include "iwl-sta.h" #include "iwl-core.h" @@ -163,12 +161,15 @@ struct iwl_lq_sta { u32 dbg_fixed_rate; #endif struct iwl_priv *drv; + + /* used to be in sta_info */ + int last_txrate_idx; }; static void rs_rate_scale_perform(struct iwl_priv *priv, - struct net_device *dev, struct ieee80211_hdr *hdr, - struct sta_info *sta); + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta); static void rs_fill_link_cmd(const struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, u32 rate_n_flags); @@ -354,17 +355,11 @@ static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid) static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, struct iwl_lq_sta *lq_data, u8 tid, - struct sta_info *sta) + struct ieee80211_sta *sta) { - unsigned long state; DECLARE_MAC_BUF(mac); - spin_lock_bh(&sta->lock); - state = sta->ampdu_mlme.tid_state_tx[tid]; - spin_unlock_bh(&sta->lock); - - if (state == HT_AGG_STATE_IDLE && - rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { + if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n", print_mac(mac, sta->addr), tid); ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); @@ -373,7 +368,7 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, struct iwl_lq_sta *lq_data, - struct sta_info *sta) + struct ieee80211_sta *sta) { if ((tid < TID_MAX_LOAD_COUNT)) rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); @@ -436,7 +431,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, /* Shift bitmap by one frame (throw away oldest history), * OR in "1", and increment "success" if this * frame was successful. */ - window->data <<= 1;; + window->data <<= 1; if (successes > 0) { window->success_counter++; window->data |= 0x1; @@ -773,7 +768,8 @@ out: /* * mac80211 sends us Tx status */ -static void rs_tx_status(void *priv_rate, struct net_device *dev, +static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { int status; @@ -781,11 +777,9 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, int rs_index, index = 0; struct iwl_lq_sta *lq_sta; struct iwl_link_quality_cmd *table; - struct sta_info *sta; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = local_to_hw(local); + struct iwl_priv *priv = (struct iwl_priv *)priv_r; + struct ieee80211_hw *hw = priv->hw; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_rate_scale_data *window = NULL; struct iwl_rate_scale_data *search_win = NULL; @@ -811,17 +805,9 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, if (retries > 15) retries = 15; - rcu_read_lock(); + lq_sta = (struct iwl_lq_sta *)priv_sta; - sta = sta_info_get(local, hdr->addr1); - - if (!sta || !sta->rate_ctrl_priv) - goto out; - - - lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; - - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) goto out; @@ -965,9 +951,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, } /* See if there's a better rate or modulation mode to try. */ - rs_rate_scale_perform(priv, dev, hdr, sta); + rs_rate_scale_perform(priv, hdr, sta, lq_sta); out: - rcu_read_unlock(); return; } @@ -1128,6 +1113,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, /* Higher rate not available, use the original */ } else { + new_rate = rate; break; } } @@ -1142,7 +1128,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, static int rs_switch_to_mimo2(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, + struct ieee80211_sta *sta, struct iwl_scale_tbl_info *tbl, int index) { u16 rate_mask; @@ -1153,8 +1139,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, !sta->ht_info.ht_supported) return -1; - if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2) - == IWL_MIMO_PS_STATIC) + if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) + == WLAN_HT_CAP_SM_PS_STATIC) return -1; /* Need both Tx chains/antennas to support MIMO */ @@ -1210,7 +1196,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, static int rs_switch_to_siso(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, + struct ieee80211_sta *sta, struct iwl_scale_tbl_info *tbl, int index) { u16 rate_mask; @@ -1270,7 +1256,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, static int rs_move_legacy_other(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, + struct ieee80211_sta *sta, int index) { struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1281,15 +1267,23 @@ static int rs_move_legacy_other(struct iwl_priv *priv, (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret = 0; for (; ;) { switch (tbl->action) { - case IWL_LEGACY_SWITCH_ANTENNA: + case IWL_LEGACY_SWITCH_ANTENNA1: + case IWL_LEGACY_SWITCH_ANTENNA2: IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n"); lq_sta->action_counter++; + if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 && + tx_chains_num <= 1) || + (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 && + tx_chains_num <= 2)) + break; + /* Don't change antenna if success has been great */ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; @@ -1299,7 +1293,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, if (rs_toggle_antenna(valid_tx_ant, &search_tbl->current_rate, search_tbl)) { - lq_sta->search_better_tbl = 1; + rs_set_expected_tpt_table(lq_sta, search_tbl); goto out; } break; @@ -1312,43 +1306,54 @@ static int rs_move_legacy_other(struct iwl_priv *priv, ret = rs_switch_to_siso(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { - lq_sta->search_better_tbl = 1; lq_sta->action_counter = 0; goto out; } break; - case IWL_LEGACY_SWITCH_MIMO2: + case IWL_LEGACY_SWITCH_MIMO2_AB: + case IWL_LEGACY_SWITCH_MIMO2_AC: + case IWL_LEGACY_SWITCH_MIMO2_BC: IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n"); /* Set up search table to try MIMO */ memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_AB;/*FIXME:RS*/ - /*FIXME:RS:need to check ant validity*/ + + if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB) + search_tbl->ant_type = ANT_AB; + else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC) + search_tbl->ant_type = ANT_AC; + else + search_tbl->ant_type = ANT_BC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { - lq_sta->search_better_tbl = 1; lq_sta->action_counter = 0; goto out; } break; } tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) - tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; if (tbl->action == start_action) break; } + search_tbl->lq_type = LQ_NONE; return 0; - out: +out: + lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) - tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; return 0; } @@ -1359,7 +1364,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, static int rs_move_siso_to_other(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, int index) + struct ieee80211_sta *sta, int index) { u8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1370,34 +1375,51 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret; for (;;) { lq_sta->action_counter++; switch (tbl->action) { - case IWL_SISO_SWITCH_ANTENNA: + case IWL_SISO_SWITCH_ANTENNA1: + case IWL_SISO_SWITCH_ANTENNA2: IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n"); + + if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 && + tx_chains_num <= 1) || + (tbl->action == IWL_SISO_SWITCH_ANTENNA2 && + tx_chains_num <= 2)) + break; + if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; memcpy(search_tbl, tbl, sz); if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, search_tbl)) { - lq_sta->search_better_tbl = 1; + &search_tbl->current_rate, search_tbl)) goto out; - } break; - case IWL_SISO_SWITCH_MIMO2: + case IWL_SISO_SWITCH_MIMO2_AB: + case IWL_SISO_SWITCH_MIMO2_AC: + case IWL_SISO_SWITCH_MIMO2_BC: IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n"); memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ + + if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB) + search_tbl->ant_type = ANT_AB; + else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC) + search_tbl->ant_type = ANT_AC; + else + search_tbl->ant_type = ANT_BC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, search_tbl, index); - if (!ret) { - lq_sta->search_better_tbl = 1; + if (!ret) goto out; - } break; case IWL_SISO_SWITCH_GI: if (!tbl->is_fat && @@ -1427,22 +1449,23 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, } search_tbl->current_rate = rate_n_flags_from_tbl( search_tbl, index, is_green); - lq_sta->search_better_tbl = 1; goto out; } tbl->action++; if (tbl->action > IWL_SISO_SWITCH_GI) - tbl->action = IWL_SISO_SWITCH_ANTENNA; + tbl->action = IWL_SISO_SWITCH_ANTENNA1; if (tbl->action == start_action) break; } + search_tbl->lq_type = LQ_NONE; return 0; out: + lq_sta->search_better_tbl = 1; tbl->action++; if (tbl->action > IWL_SISO_SWITCH_GI) - tbl->action = IWL_SISO_SWITCH_ANTENNA; + tbl->action = IWL_SISO_SWITCH_ANTENNA1; return 0; } @@ -1452,43 +1475,64 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, static int rs_move_mimo_to_other(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, int index) + struct ieee80211_sta *sta, int index) { s8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + struct iwl_rate_scale_data *window = &(tbl->win[index]); u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; - /*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/ + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret; for (;;) { lq_sta->action_counter++; switch (tbl->action) { - case IWL_MIMO_SWITCH_ANTENNA_A: - case IWL_MIMO_SWITCH_ANTENNA_B: + case IWL_MIMO2_SWITCH_ANTENNA1: + case IWL_MIMO2_SWITCH_ANTENNA2: + IWL_DEBUG_RATE("LQ: MIMO toggle Antennas\n"); + + if (tx_chains_num <= 2) + break; + + if (window->success_ratio >= IWL_RS_GOOD_RATIO) + break; + + memcpy(search_tbl, tbl, sz); + if (rs_toggle_antenna(valid_tx_ant, + &search_tbl->current_rate, search_tbl)) + goto out; + break; + case IWL_MIMO2_SWITCH_SISO_A: + case IWL_MIMO2_SWITCH_SISO_B: + case IWL_MIMO2_SWITCH_SISO_C: IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n"); /* Set up new search table for SISO */ memcpy(search_tbl, tbl, sz); - /*FIXME:RS:need to check ant validity + C*/ - if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) + if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) search_tbl->ant_type = ANT_A; - else + else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) search_tbl->ant_type = ANT_B; + else + search_tbl->ant_type = ANT_C; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; ret = rs_switch_to_siso(priv, lq_sta, conf, sta, search_tbl, index); - if (!ret) { - lq_sta->search_better_tbl = 1; + if (!ret) goto out; - } + break; - case IWL_MIMO_SWITCH_GI: + case IWL_MIMO2_SWITCH_GI: if (!tbl->is_fat && !(priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ)) @@ -1517,23 +1561,23 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, } search_tbl->current_rate = rate_n_flags_from_tbl( search_tbl, index, is_green); - lq_sta->search_better_tbl = 1; goto out; } tbl->action++; - if (tbl->action > IWL_MIMO_SWITCH_GI) - tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + if (tbl->action > IWL_MIMO2_SWITCH_GI) + tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; if (tbl->action == start_action) break; } - + search_tbl->lq_type = LQ_NONE; return 0; out: + lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_MIMO_SWITCH_GI) - tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + if (tbl->action > IWL_MIMO2_SWITCH_GI) + tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; return 0; } @@ -1624,12 +1668,11 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta) * Do rate scaling and search for new modulation mode. */ static void rs_rate_scale_perform(struct iwl_priv *priv, - struct net_device *dev, struct ieee80211_hdr *hdr, - struct sta_info *sta) + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = local_to_hw(local); + struct ieee80211_hw *hw = priv->hw; struct ieee80211_conf *conf = &hw->conf; int low = IWL_RATE_INVALID; int high = IWL_RATE_INVALID; @@ -1644,7 +1687,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, __le16 fc; u16 rate_mask; u8 update_lq = 0; - struct iwl_lq_sta *lq_sta; struct iwl_scale_tbl_info *tbl, *tbl1; u16 rate_scale_index_msk = 0; u32 rate; @@ -1665,10 +1707,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, return; } - if (!sta || !sta->rate_ctrl_priv) + if (!sta || !lq_sta) return; - lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; + lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; tid = rs_tl_add_packet(lq_sta, hdr); @@ -1686,7 +1728,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, is_green = lq_sta->is_green; /* current tx rate */ - index = sta->last_txrate_idx; + index = lq_sta->last_txrate_idx; IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, tbl->lq_type); @@ -1747,19 +1789,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, rs_stay_in_table(lq_sta); goto out; + } /* Else we have enough samples; calculate estimate of * actual average throughput */ - } else { - /*FIXME:RS remove this else if we don't get this error*/ - if (window->average_tpt != ((window->success_ratio * - tbl->expected_tpt[index] + 64) / 128)) { - IWL_ERROR("expected_tpt should have been calculated" - " by now\n"); - window->average_tpt = ((window->success_ratio * - tbl->expected_tpt[index] + 64) / 128); - } - } + + BUG_ON(window->average_tpt != ((window->success_ratio * + tbl->expected_tpt[index] + 64) / 128)); /* If we are searching for better modulation mode, check success. */ if (lq_sta->search_better_tbl) { @@ -1769,7 +1805,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, * continuing to use the setup that we've been trying. */ if (window->average_tpt > lq_sta->last_tpt) { - IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE " + IWL_DEBUG_RATE("LQ: SWITCHING TO NEW TABLE " "suc=%d cur-tpt=%d old-tpt=%d\n", window->success_ratio, window->average_tpt, @@ -2005,15 +2041,7 @@ lq_update: out: tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green); i = index; - sta->last_txrate_idx = i; - - /* sta->txrate_idx is an index to A mode rates which start - * at IWL_FIRST_OFDM_RATE - */ - if (lq_sta->band == IEEE80211_BAND_5GHZ) - sta->txrate_idx = i - IWL_FIRST_OFDM_RATE; - else - sta->txrate_idx = i; + lq_sta->last_txrate_idx = i; return; } @@ -2021,9 +2049,9 @@ out: static void rs_initialize_lq(struct iwl_priv *priv, struct ieee80211_conf *conf, - struct sta_info *sta) + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta) { - struct iwl_lq_sta *lq_sta; struct iwl_scale_tbl_info *tbl; int rate_idx; int i; @@ -2032,14 +2060,13 @@ static void rs_initialize_lq(struct iwl_priv *priv, u8 active_tbl = 0; u8 valid_tx_ant; - if (!sta || !sta->rate_ctrl_priv) + if (!sta || !lq_sta) goto out; - lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate_idx; + i = lq_sta->last_txrate_idx; if ((lq_sta->lq.sta_id == 0xff) && - (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) + (priv->iw_mode == NL80211_IFTYPE_ADHOC)) goto out; valid_tx_ant = priv->hw_params.valid_tx_ant; @@ -2076,40 +2103,33 @@ static void rs_initialize_lq(struct iwl_priv *priv, return; } -static void rs_get_rate(void *priv_rate, struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + struct sk_buff *skb, struct rate_selection *sel) { int i; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; + struct iwl_priv *priv = (struct iwl_priv *)priv_r; + struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct sta_info *sta; __le16 fc; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl_lq_sta *lq_sta; IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - /* Send management frames and broadcast/multicast data using lowest * rate. */ fc = hdr->frame_control; if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || - !sta || !sta->rate_ctrl_priv) { - sel->rate_idx = rate_lowest_index(local, sband, sta); - goto out; + !sta || !priv_sta) { + sel->rate_idx = rate_lowest_index(sband, sta); + return; } - lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate_idx; + lq_sta = (struct iwl_lq_sta *)priv_sta; + i = lq_sta->last_txrate_idx; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) { u8 sta_id = iwl_find_station(priv, hdr->addr1); DECLARE_MAC_BUF(mac); @@ -2124,23 +2144,22 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, lq_sta->lq.sta_id = sta_id; lq_sta->lq.rs_table[0].rate_n_flags = 0; lq_sta->ibss_sta_added = 1; - rs_initialize_lq(priv, conf, sta); + rs_initialize_lq(priv, conf, sta, lq_sta); } } if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate_idx = rate_lowest_index(local, sband, sta); - goto out; + sel->rate_idx = rate_lowest_index(sband, sta); + return; } if (sband->band == IEEE80211_BAND_5GHZ) i -= IWL_FIRST_OFDM_RATE; sel->rate_idx = i; -out: - rcu_read_unlock(); } -static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) +static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, + gfp_t gfp) { struct iwl_lq_sta *lq_sta; struct iwl_priv *priv; @@ -2163,33 +2182,28 @@ static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) return lq_sta; } -static void rs_rate_init(void *priv_rate, void *priv_sta, - struct ieee80211_local *local, - struct sta_info *sta) +static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta) { int i, j; - struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_supported_band *sband; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl_priv *priv = (struct iwl_priv *)priv_r; + struct ieee80211_conf *conf = &priv->hw->conf; struct iwl_lq_sta *lq_sta = priv_sta; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; - sta->txrate_idx = 3; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); - IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n"); + IWL_DEBUG_RATE("LQ: *** rate scale station global init ***\n"); /* TODO: what is a good starting rate for STA? About middle? Maybe not * the lowest or the highest rate.. Could consider using RSSI from * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ lq_sta->ibss_sta_added = 0; - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { u8 sta_id = iwl_find_station(priv, sta->addr); DECLARE_MAC_BUF(mac); @@ -2212,15 +2226,14 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, } /* Find highest tx rate supported by hardware and destination station */ + lq_sta->last_txrate_idx = 3; for (i = 0; i < sband->n_bitrates; i++) if (sta->supp_rates[sband->band] & BIT(i)) - sta->txrate_idx = i; + lq_sta->last_txrate_idx = i; - sta->last_txrate_idx = sta->txrate_idx; - /* WTF is with this bogus comment? A doesn't have cck rates */ - /* For MODE_IEEE80211A, cck rates are at end of rate table */ - if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) - sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + /* For MODE_IEEE80211A, skip over cck rates in global rate table */ + if (sband->band == IEEE80211_BAND_5GHZ) + lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->is_dup = 0; lq_sta->is_green = rs_use_green(priv, conf); @@ -2260,7 +2273,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->drv = priv; - rs_initialize_lq(priv, conf, sta); + rs_initialize_lq(priv, conf, sta, lq_sta); } static void rs_fill_link_cmd(const struct iwl_priv *priv, @@ -2382,9 +2395,9 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); } -static void *rs_alloc(struct ieee80211_local *local) +static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - return local->hw.priv; + return hw->priv; } /* rate scale requires free function to be implemented */ static void rs_free(void *priv_rate) @@ -2405,12 +2418,12 @@ static void rs_clear(void *priv_rate) #endif /* CONFIG_IWLWIFI_DEBUG */ } -static void rs_free_sta(void *priv_rate, void *priv_sta) +static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, + void *priv_sta) { struct iwl_lq_sta *lq_sta = priv_sta; - struct iwl_priv *priv; + struct iwl_priv *priv __maybe_unused = priv_r; - priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE("enter\n"); kfree(lq_sta); IWL_DEBUG_RATE("leave\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 84d4d1e3375..d148d73635e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -206,21 +206,28 @@ enum { #define IWL_RATE_DECREASE_TH 1920 /* 15% */ /* possible actions when in legacy mode */ -#define IWL_LEGACY_SWITCH_ANTENNA 0 -#define IWL_LEGACY_SWITCH_SISO 1 -#define IWL_LEGACY_SWITCH_MIMO2 2 +#define IWL_LEGACY_SWITCH_ANTENNA1 0 +#define IWL_LEGACY_SWITCH_ANTENNA2 1 +#define IWL_LEGACY_SWITCH_SISO 2 +#define IWL_LEGACY_SWITCH_MIMO2_AB 3 +#define IWL_LEGACY_SWITCH_MIMO2_AC 4 +#define IWL_LEGACY_SWITCH_MIMO2_BC 5 /* possible actions when in siso mode */ -#define IWL_SISO_SWITCH_ANTENNA 0 -#define IWL_SISO_SWITCH_MIMO2 1 -#define IWL_SISO_SWITCH_GI 2 +#define IWL_SISO_SWITCH_ANTENNA1 0 +#define IWL_SISO_SWITCH_ANTENNA2 1 +#define IWL_SISO_SWITCH_MIMO2_AB 2 +#define IWL_SISO_SWITCH_MIMO2_AC 3 +#define IWL_SISO_SWITCH_MIMO2_BC 4 +#define IWL_SISO_SWITCH_GI 5 /* possible actions when in mimo mode */ -#define IWL_MIMO_SWITCH_ANTENNA_A 0 -#define IWL_MIMO_SWITCH_ANTENNA_B 1 -#define IWL_MIMO_SWITCH_GI 2 - -/*FIXME:RS:separate MIMO2/3 transitions*/ +#define IWL_MIMO2_SWITCH_ANTENNA1 0 +#define IWL_MIMO2_SWITCH_ANTENNA2 1 +#define IWL_MIMO2_SWITCH_SISO_A 2 +#define IWL_MIMO2_SWITCH_SISO_B 3 +#define IWL_MIMO2_SWITCH_SISO_C 4 +#define IWL_MIMO2_SWITCH_GI 5 /*FIXME:RS:add posible acctions for MIMO3*/ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e01f048a02d..24a1aeb6448 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -337,7 +337,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ if (new_assoc) { - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + if (priv->iw_mode == NL80211_IFTYPE_STATION) { ret = iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1); if (ret == IWL_INVALID_STATION) { @@ -448,8 +448,8 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, const u8 *dest, int left) { if (!iwl_is_associated(priv) || !priv->ibss_beacon || - ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && - (priv->iw_mode != IEEE80211_IF_TYPE_AP))) + ((priv->iw_mode != NL80211_IFTYPE_ADHOC) && + (priv->iw_mode != NL80211_IFTYPE_AP))) return 0; if (priv->ibss_beacon->len > left) @@ -485,7 +485,7 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) return IWL_RATE_6M_PLCP; } -unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, +static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; @@ -564,8 +564,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, if (!iwl_conf->is_ht) return; - priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) iwl_conf->sgf |= HT_SHORT_GI_20MHZ; if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) @@ -586,6 +584,8 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, iwl_conf->supported_chan_width = 0; } + iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); + memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); iwl_conf->control_channel = ht_bss_conf->primary_channel; @@ -672,7 +672,7 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) beacon_int = priv->beacon_int; spin_unlock_irqrestore(&priv->lock, flags); - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + if (priv->iw_mode == NL80211_IFTYPE_STATION) { if (beacon_int == 0) { priv->rxon_timing.beacon_interval = cpu_to_le16(100); priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); @@ -721,7 +721,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv, else priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; @@ -740,23 +740,23 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; @@ -785,7 +785,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) * in some case A channels are all non IBSS * in this case force B/G channel */ - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info))) ch_info = &priv->channel_info[0]; @@ -1182,7 +1182,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, le32_to_cpu(beacon->low_tsf), rate); #endif - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + if ((priv->iw_mode == NL80211_IFTYPE_AP) && (!test_bit(STATUS_EXIT_PENDING, &priv->status))) queue_work(priv->workqueue, &priv->beacon_update); } @@ -1270,7 +1270,7 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) if (src == IWL_PWR_SRC_VAUX) { u32 val; - ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, + ret = pci_read_config_dword(priv->pci_dev, PCI_CFG_POWER_SOURCE, &val); if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) @@ -2388,7 +2388,7 @@ static void iwl4965_bg_set_monitor(struct work_struct *work) mutex_lock(&priv->mutex); - ret = iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR); + ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR); if (ret) { if (ret == -EAGAIN) @@ -2469,7 +2469,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) DECLARE_MAC_BUF(mac); unsigned long flags; - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __func__); return; } @@ -2486,6 +2486,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) if (!priv->vif || !priv->is_open) return; + iwl_power_cancel_timeout(priv); iwl_scan_cancel_timeout(priv, 200); conf = ieee80211_get_hw_conf(priv->hw); @@ -2503,8 +2504,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - if (priv->current_ht_config.is_ht) - iwl_set_rxon_ht(priv, &priv->current_ht_config); + iwl_set_rxon_ht(priv, &priv->current_ht_config); iwl_set_rxon_chain(priv); priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); @@ -2523,7 +2523,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) else priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; } @@ -2531,10 +2531,10 @@ static void iwl4965_post_associate(struct iwl_priv *priv) iwl4965_commit_rxon(priv); switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: /* assume default assoc id */ priv->assoc_id = 1; @@ -2550,44 +2550,23 @@ static void iwl4965_post_associate(struct iwl_priv *priv) break; } - /* Enable Rx differential gain and sensitivity calibrations */ - iwl_chain_noise_reset(priv); - priv->start_calib = 1; - - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->assoc_station_added = 1; spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 0); spin_unlock_irqrestore(&priv->lock, flags); - iwl_power_update_mode(priv, 0); - /* we have just associated, don't start scan too early */ - priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; -} - -static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); - -static void iwl_bg_scan_completed(struct work_struct *work) -{ - struct iwl_priv *priv = - container_of(work, struct iwl_priv, scan_completed); - - IWL_DEBUG_SCAN("SCAN complete scan\n"); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (test_bit(STATUS_CONF_PENDING, &priv->status)) - iwl4965_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw)); + /* the chain noise calibration will enabled PM upon completion + * If chain noise has already been run, then we need to enable + * power management here */ + if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) + iwl_power_enable_management(priv); - ieee80211_scan_completed(priv->hw); + /* Enable Rx differential gain and sensitivity calibrations */ + iwl_chain_noise_reset(priv); + priv->start_calib = 1; - /* Since setting the TXPOWER may have been deferred while - * performing the scan, fire one off */ - mutex_lock(&priv->mutex); - iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - mutex_unlock(&priv->mutex); } /***************************************************************************** @@ -2728,12 +2707,6 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IWL_DEBUG_MACDUMP("enter\n"); - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - IWL_DEBUG_MAC80211("leave - monitor\n"); - dev_kfree_skb_any(skb); - return 0; - } - IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); @@ -2798,8 +2771,6 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); - priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); - if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); goto out; @@ -2817,7 +2788,6 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co if (unlikely(!priv->cfg->mod_params->disable_hw_scan && test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); - set_bit(STATUS_CONF_PENDING, &priv->status); mutex_unlock(&priv->mutex); return 0; } @@ -2830,7 +2800,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co goto out; } - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && !is_channel_ibss(ch_info)) { IWL_ERROR("channel %d in band %d not IBSS channel\n", conf->channel->hw_value, conf->channel->band); @@ -2851,7 +2821,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co ) priv->staging_rxon.flags = 0; - iwl_set_rxon_channel(priv, conf->channel->band, channel); + iwl_set_rxon_channel(priv, conf->channel); iwl_set_flags_for_band(priv, conf->channel->band); @@ -2880,6 +2850,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co goto out; } + if (conf->flags & IEEE80211_CONF_PS) + ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3); + else + ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM); + if (ret) + IWL_DEBUG_MAC80211("Error setting power level\n"); + IWL_DEBUG_MAC80211("TX Power old=%d new=%d\n", priv->tx_power_user_lmt, conf->power_level); @@ -2896,7 +2873,6 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co IWL_DEBUG_MAC80211("leave\n"); out: - clear_bit(STATUS_CONF_PENDING, &priv->status); mutex_unlock(&priv->mutex); return ret; } @@ -2945,7 +2921,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; } @@ -2984,7 +2960,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, return 0; } - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && conf->changed & IEEE80211_IFCC_BEACON) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) @@ -2994,7 +2970,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, return rc; } - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + if ((priv->iw_mode == NL80211_IFTYPE_AP) && (!conf->ssid_len)) { IWL_DEBUG_MAC80211 ("Leaving in AP mode because HostAPD is not ready.\n"); @@ -3017,7 +2993,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { */ - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); @@ -3052,11 +3028,11 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, * to verify) - jpk */ memcpy(priv->bssid, conf->bssid, ETH_ALEN); - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl4965_config_ap(priv); else { rc = iwl4965_commit_rxon(priv); - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) + if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) iwl_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); } @@ -3092,7 +3068,7 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw, if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - IEEE80211_IF_TYPE_MNTR, + NL80211_IFTYPE_MONITOR, changed_flags, *total_flags); /* queue work 'cuz mac80211 is holding a lock which * prevents us from issuing (synchronous) f/w cmds */ @@ -3173,6 +3149,10 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, priv->power_data.dtim_period = bss_conf->dtim_period; priv->timestamp = bss_conf->timestamp; priv->assoc_capability = bss_conf->assoc_capability; + + /* we have just associated, don't start scan too early + * leave time for EAPOL exchange to complete + */ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; mutex_lock(&priv->mutex); @@ -3189,11 +3169,11 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, } -static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) +static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) { - int rc = 0; unsigned long flags; struct iwl_priv *priv = hw->priv; + int ret; IWL_DEBUG_MAC80211("enter\n"); @@ -3201,41 +3181,47 @@ static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) spin_lock_irqsave(&priv->lock, flags); if (!iwl_is_ready_rf(priv)) { - rc = -EIO; + ret = -EIO; IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); goto out_unlock; } - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ - rc = -EIO; + if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ + ret = -EIO; IWL_ERROR("ERROR: APs don't scan\n"); goto out_unlock; } - /* we don't schedule scan within next_scan_jiffies period */ + /* We don't schedule scan within next_scan_jiffies period. + * Avoid scanning during possible EAPOL exchange, return + * success immediately. + */ if (priv->next_scan_jiffies && - time_after(priv->next_scan_jiffies, jiffies)) { - rc = -EAGAIN; + time_after(priv->next_scan_jiffies, jiffies)) { + IWL_DEBUG_SCAN("scan rejected: within next scan period\n"); + queue_work(priv->workqueue, &priv->scan_completed); + ret = 0; goto out_unlock; } + /* if we just finished scan ask for delay */ - if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + - IWL_DELAY_NEXT_SCAN, jiffies)) { - rc = -EAGAIN; + if (iwl_is_associated(priv) && priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { + IWL_DEBUG_SCAN("scan rejected: within previous scan period\n"); + queue_work(priv->workqueue, &priv->scan_completed); + ret = 0; goto out_unlock; } - if (len) { - IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", - iwl_escape_essid(ssid, len), (int)len); + if (ssid_len) { priv->one_direct_scan = 1; - priv->direct_ssid_len = (u8) - min((u8) len, (u8) IW_ESSID_MAX_SIZE); + priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE); memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); - } else + } else { priv->one_direct_scan = 0; + } - rc = iwl_scan_initiate(priv); + ret = iwl_scan_initiate(priv); IWL_DEBUG_MAC80211("leave\n"); @@ -3243,7 +3229,7 @@ out_unlock: spin_unlock_irqrestore(&priv->lock, flags); mutex_unlock(&priv->mutex); - return rc; + return ret; } static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, @@ -3332,7 +3318,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * in 1X mode. * In legacy wep mode, we use another host command to the uCode */ if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id && - priv->iw_mode != IEEE80211_IF_TYPE_AP) { + priv->iw_mode != NL80211_IFTYPE_AP) { if (cmd == SET_KEY) is_default_wep_key = !priv->key_mapping_key; else @@ -3403,7 +3389,7 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; priv->qos_data.qos_active = 1; - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl_activate_qos(priv, 1); else if (priv->assoc_id && iwl_is_associated(priv)) iwl_activate_qos(priv, 0); @@ -3416,13 +3402,13 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 *ssn) + struct ieee80211_sta *sta, u16 tid, u16 *ssn) { struct iwl_priv *priv = hw->priv; DECLARE_MAC_BUF(mac); IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", - print_mac(mac, addr), tid); + print_mac(mac, sta->addr), tid); if (!(priv->cfg->sku & IWL_SKU_N)) return -EACCES; @@ -3430,16 +3416,16 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: IWL_DEBUG_HT("start Rx\n"); - return iwl_rx_agg_start(priv, addr, tid, *ssn); + return iwl_rx_agg_start(priv, sta->addr, tid, *ssn); case IEEE80211_AMPDU_RX_STOP: IWL_DEBUG_HT("stop Rx\n"); - return iwl_rx_agg_stop(priv, addr, tid); + return iwl_rx_agg_stop(priv, sta->addr, tid); case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT("start Tx\n"); - return iwl_tx_agg_start(priv, addr, tid, ssn); + return iwl_tx_agg_start(priv, sta->addr, tid, ssn); case IEEE80211_AMPDU_TX_STOP: IWL_DEBUG_HT("stop Tx\n"); - return iwl_tx_agg_stop(priv, addr, tid); + return iwl_tx_agg_stop(priv, sta->addr, tid); default: IWL_DEBUG_HT("unknown\n"); return -EINVAL; @@ -3521,7 +3507,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) priv->beacon_int = priv->hw->conf.beacon_int; priv->timestamp = 0; - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) + if ((priv->iw_mode == NL80211_IFTYPE_STATION)) priv->beacon_int = 0; spin_unlock_irqrestore(&priv->lock, flags); @@ -3535,7 +3521,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) /* we are restarting association process * clear RXON_FILTER_ASSOC_MSK bit */ - if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode != NL80211_IFTYPE_AP) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); @@ -3544,7 +3530,17 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) iwl_power_update_mode(priv, 0); /* Per mac80211.h: This is only used in IBSS mode... */ - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { + + /* switch to CAM during association period. + * the ucode will block any association/authentication + * frome during assiciation period if it can not hear + * the AP because of PM. the timer enable PM back is + * association do not complete + */ + if (priv->hw->conf.channel->flags & (IEEE80211_CHAN_PASSIVE_SCAN | + IEEE80211_CHAN_RADAR)) + iwl_power_disable_management(priv, 3000); IWL_DEBUG_MAC80211("leave - not in IBSS\n"); mutex_unlock(&priv->mutex); @@ -3573,7 +3569,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk return -EIO; } - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); mutex_unlock(&priv->mutex); return -EIO; @@ -3630,11 +3626,11 @@ static ssize_t store_debug_level(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = d->driver_data; - char *p = (char *)buf; - u32 val; + unsigned long val; + int ret; - val = simple_strtoul(p, &p, 0); - if (p == buf) + ret = strict_strtoul(buf, 0, &val); + if (ret) printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else @@ -3706,11 +3702,11 @@ static ssize_t store_tx_power(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - char *p = (char *)buf; - u32 val; + unsigned long val; + int ret; - val = simple_strtoul(p, &p, 10); - if (p == buf) + ret = strict_strtoul(buf, 10, &val); + if (ret) printk(KERN_INFO DRV_NAME ": %s is not in decimal form.\n", buf); else @@ -3734,7 +3730,12 @@ static ssize_t store_flags(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - u32 flags = simple_strtoul(buf, NULL, 0); + unsigned long val; + u32 flags; + int ret = strict_strtoul(buf, 0, &val); + if (ret) + return ret; + flags = (u32)val; mutex_lock(&priv->mutex); if (le32_to_cpu(priv->staging_rxon.flags) != flags) { @@ -3742,8 +3743,7 @@ static ssize_t store_flags(struct device *d, if (iwl_scan_cancel_timeout(priv, 100)) IWL_WARNING("Could not cancel scan.\n"); else { - IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n", - flags); + IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags); priv->staging_rxon.flags = cpu_to_le32(flags); iwl4965_commit_rxon(priv); } @@ -3769,7 +3769,12 @@ static ssize_t store_filter_flags(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - u32 filter_flags = simple_strtoul(buf, NULL, 0); + unsigned long val; + u32 filter_flags; + int ret = strict_strtoul(buf, 0, &val); + if (ret) + return ret; + filter_flags = (u32)val; mutex_lock(&priv->mutex); if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { @@ -3870,10 +3875,12 @@ static ssize_t store_retry_rate(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = dev_get_drvdata(d); + long val; + int ret = strict_strtol(buf, 10, &val); + if (!ret) + return ret; - priv->retry_rate = simple_strtoul(buf, NULL, 0); - if (priv->retry_rate <= 0) - priv->retry_rate = 1; + priv->retry_rate = (val > 0) ? val : 1; return count; } @@ -3894,9 +3901,9 @@ static ssize_t store_power_level(struct device *d, { struct iwl_priv *priv = dev_get_drvdata(d); int ret; - int mode; + unsigned long mode; + - mode = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); if (!iwl_is_ready(priv)) { @@ -3904,6 +3911,10 @@ static ssize_t store_power_level(struct device *d, goto out; } + ret = strict_strtoul(buf, 10, &mode); + if (ret) + goto out; + ret = iwl_power_set_user_mode(priv, mode); if (ret) { IWL_DEBUG_MAC80211("failed setting power mode.\n"); @@ -4080,9 +4091,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); - /* FIXME : remove when resolved PENDING */ - INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); iwl_setup_scan_deferred_work(priv); + iwl_setup_power_deferred_work(priv); if (priv->cfg->ops->lib->setup_deferred_work) priv->cfg->ops->lib->setup_deferred_work(priv); @@ -4102,6 +4112,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_delayed_work_sync(&priv->init_alive_start); cancel_delayed_work(&priv->scan_check); + cancel_delayed_work_sync(&priv->set_power_save); cancel_delayed_work(&priv->alive_start); cancel_work_sync(&priv->beacon_update); del_timer_sync(&priv->statistics_periodic); @@ -4150,7 +4161,7 @@ static struct ieee80211_ops iwl4965_hw_ops = { .reset_tsf = iwl4965_mac_reset_tsf, .bss_info_changed = iwl4965_bss_info_changed, .ampdu_action = iwl4965_mac_ampdu_action, - .hw_scan = iwl4965_mac_hw_scan + .hw_scan = iwl_mac_hw_scan }; static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -4204,13 +4215,13 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); if (err) { - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); /* both attempts failed: */ if (err) { printk(KERN_WARNING "%s: No suitable DMA available.\n", @@ -4225,9 +4236,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_drvdata(pdev, priv); - /* We disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state */ - pci_write_config_byte(pdev, 0x41, 0x00); /*********************** * 3. Read REV register @@ -4247,6 +4255,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e ": Detected Intel Wireless WiFi Link %s REV=0x%X\n", priv->cfg->name, priv->hw_rev); + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); + /* amp init */ err = priv->cfg->ops->lib->apm_ops.init(priv); if (err < 0) { @@ -4481,7 +4493,10 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)}, {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)}, - {IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)}, +/* 5350 WiFi/WiMax */ + {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, + {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, + {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, #endif /* CONFIG_IWL5000 */ {0} }; diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index ef49440bd7f..72fbf47229d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -66,6 +66,66 @@ #include "iwl-core.h" #include "iwl-calib.h" +/***************************************************************************** + * INIT calibrations framework + *****************************************************************************/ + + int iwl_send_calib_results(struct iwl_priv *priv) +{ + int ret = 0; + int i = 0; + + struct iwl_host_cmd hcmd = { + .id = REPLY_PHY_CALIBRATION_CMD, + .meta.flags = CMD_SIZE_HUGE, + }; + + for (i = 0; i < IWL_CALIB_MAX; i++) + if (priv->calib_results[i].buf) { + hcmd.len = priv->calib_results[i].buf_len; + hcmd.data = priv->calib_results[i].buf; + ret = iwl_send_cmd_sync(priv, &hcmd); + if (ret) + goto err; + } + + return 0; +err: + IWL_ERROR("Error %d iteration %d\n", ret, i); + return ret; +} +EXPORT_SYMBOL(iwl_send_calib_results); + +int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len) +{ + if (res->buf_len != len) { + kfree(res->buf); + res->buf = kzalloc(len, GFP_ATOMIC); + } + if (unlikely(res->buf == NULL)) + return -ENOMEM; + + res->buf_len = len; + memcpy(res->buf, buf, len); + return 0; +} +EXPORT_SYMBOL(iwl_calib_set); + +void iwl_calib_free_results(struct iwl_priv *priv) +{ + int i; + + for (i = 0; i < IWL_CALIB_MAX; i++) { + kfree(priv->calib_results[i].buf); + priv->calib_results[i].buf = NULL; + priv->calib_results[i].buf_len = 0; + } +} + +/***************************************************************************** + * RUNTIME calibrations framework + *****************************************************************************/ + /* "false alarms" are signals that our DSP tries to lock onto, * but then determines that they are either noise, or transmissions * from a distant wireless network (also "noise", really) that get @@ -748,13 +808,11 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, } } + /* Save for use within RXON, TX, SCAN commands, etc. */ + priv->chain_noise_data.active_chains = active_chains; IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", active_chains); - /* Save for use within RXON, TX, SCAN commands, etc. */ - /*priv->valid_antenna = active_chains;*/ - /*FIXME: should be reflected in RX chains in RXON */ - /* Analyze noise for rx balance */ average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); @@ -779,6 +837,15 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, priv->cfg->ops->utils->gain_computation(priv, average_noise, min_average_noise_antenna_i, min_average_noise); + + /* Some power changes may have been made during the calibration. + * Update and commit the RXON + */ + if (priv->cfg->ops->lib->update_chain_flags) + priv->cfg->ops->lib->update_chain_flags(priv); + + data->state = IWL_CHAIN_NOISE_DONE; + iwl_power_enable_management(priv); } EXPORT_SYMBOL(iwl_chain_noise_calibration); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 28b5b09996e..8d04e966ad4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -163,6 +163,13 @@ enum { /* iwl_cmd_header flags value */ #define IWL_CMD_FAILED_MSK 0x40 +#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) +#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) +#define SEQ_TO_INDEX(s) ((s) & 0xff) +#define INDEX_TO_SEQ(i) ((i) & 0xff) +#define SEQ_HUGE_FRAME __constant_cpu_to_le16(0x4000) +#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) + /** * struct iwl_cmd_header * @@ -171,7 +178,7 @@ enum { */ struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 flags; /* IWL_CMD_* */ + u8 flags; /* 0:5 reserved, 6 abort, 7 internal */ /* * The driver sets up the sequence number to values of its chosing. * uCode does not use this value, but passes it back to the driver @@ -187,11 +194,12 @@ struct iwl_cmd_header { * * The Linux driver uses the following format: * - * 0:7 index/position within Tx queue - * 8:13 Tx queue selection - * 14:14 driver sets this to indicate command is in the 'huge' - * storage at the end of the command buffers, i.e. scan cmd - * 15:15 uCode sets this in uCode-originated response/notification + * 0:7 tfd index - position within TX queue + * 8:12 TX queue id + * 13 reserved + * 14 huge - driver sets this to indicate command is in the + * 'huge' storage at the end of the command buffers + * 15 unsolicited RX or uCode-originated notification */ __le16 sequence; @@ -2026,8 +2034,8 @@ struct iwl4965_spectrum_notification { * bit 2 - '0' PM have to walk up every DTIM * '1' PM could sleep over DTIM till listen Interval. * PCI power managed - * bit 3 - '0' (PCI_LINK_CTRL & 0x1) - * '1' !(PCI_LINK_CTRL & 0x1) + * bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1) + * '1' !(PCI_CFG_LINK_CTRL & 0x1) * Force sleep Modes * bit 31/30- '00' use both mac/xtal sleeps * '01' force Mac sleep diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 80f2f84defa..4c312c55f90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -306,14 +306,14 @@ void iwl_reset_qos(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); priv->qos_data.qos_active = 0; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { if (priv->qos_data.qos_enable) priv->qos_data.qos_active = 1; if (!(priv->active_rate & 0xfff0)) { cw_min = 31; is_legacy = 1; } - } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + } else if (priv->iw_mode == NL80211_IFTYPE_AP) { if (priv->qos_data.qos_enable) priv->qos_data.qos_active = 1; } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { @@ -399,8 +399,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & - (IWL_MIMO_PS_NONE << 2)); + ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS & + (WLAN_HT_CAP_SM_PS_DISABLED << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.fat_channel & BIT(band)) { @@ -646,8 +646,14 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) struct iwl_rxon_cmd *rxon = &priv->staging_rxon; u32 val; - if (!ht_info->is_ht) + if (!ht_info->is_ht) { + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | + RXON_FLG_CHANNEL_MODE_PURE_40_MSK | + RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | + RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT_PROT_MSK); return; + } /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ if (iwl_is_fat_tx_allowed(priv, NULL)) @@ -697,8 +703,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) } EXPORT_SYMBOL(iwl_set_rxon_ht); -/* - * Determine how many receiver/antenna chains to use. +#define IWL_NUM_RX_CHAINS_MULTIPLE 3 +#define IWL_NUM_RX_CHAINS_SINGLE 2 +#define IWL_NUM_IDLE_CHAINS_DUAL 2 +#define IWL_NUM_IDLE_CHAINS_SINGLE 1 + +/* Determine how many receiver/antenna chains to use. * More provides better reception via diversity. Fewer saves power. * MIMO (dual stream) requires at least 2, but works better with 3. * This does not determine *which* chains to use, just how many. @@ -709,10 +719,11 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); /* # of Rx chains to use when expecting MIMO. */ - if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) - return 2; + if (is_single || (!is_cam && (priv->current_ht_config.sm_ps == + WLAN_HT_CAP_SM_PS_STATIC))) + return IWL_NUM_RX_CHAINS_SINGLE; else - return 3; + return IWL_NUM_RX_CHAINS_MULTIPLE; } static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) @@ -720,17 +731,19 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) int idle_cnt; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); /* # Rx chains when idling and maybe trying to save power */ - switch (priv->ps_mode) { - case IWL_MIMO_PS_STATIC: - case IWL_MIMO_PS_DYNAMIC: - idle_cnt = (is_cam) ? 2 : 1; + switch (priv->current_ht_config.sm_ps) { + case WLAN_HT_CAP_SM_PS_STATIC: + case WLAN_HT_CAP_SM_PS_DYNAMIC: + idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : + IWL_NUM_IDLE_CHAINS_SINGLE; break; - case IWL_MIMO_PS_NONE: - idle_cnt = (is_cam) ? active_cnt : 1; + case WLAN_HT_CAP_SM_PS_DISABLED: + idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; break; - case IWL_MIMO_PS_INVALID: + case WLAN_HT_CAP_SM_PS_INVALID: default: - IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode); + IWL_ERROR("invalide mimo ps mode %d\n", + priv->current_ht_config.sm_ps); WARN_ON(1); idle_cnt = -1; break; @@ -738,6 +751,17 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) return idle_cnt; } +/* up to 4 chains */ +static u8 iwl_count_chain_bitmap(u32 chain_bitmap) +{ + u8 res; + res = (chain_bitmap & BIT(0)) >> 0; + res += (chain_bitmap & BIT(1)) >> 1; + res += (chain_bitmap & BIT(2)) >> 2; + res += (chain_bitmap & BIT(4)) >> 4; + return res; +} + /** * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image * @@ -748,37 +772,47 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) { bool is_single = is_single_rx_stream(priv); bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - u8 idle_rx_cnt, active_rx_cnt; + u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt; + u32 active_chains; u16 rx_chain; /* Tell uCode which antennas are actually connected. * Before first association, we assume all antennas are connected. * Just after first association, iwl_chain_noise_calibration() * checks which antennas actually *are* connected. */ - rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; + if (priv->chain_noise_data.active_chains) + active_chains = priv->chain_noise_data.active_chains; + else + active_chains = priv->hw_params.valid_rx_ant; + + rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS; /* How many receivers should we use? */ active_rx_cnt = iwl_get_active_rx_chain_count(priv); idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); - /* correct rx chain count accoridng hw settings */ - if (priv->hw_params.rx_chains_num < active_rx_cnt) - active_rx_cnt = priv->hw_params.rx_chains_num; - if (priv->hw_params.rx_chains_num < idle_rx_cnt) - idle_rx_cnt = priv->hw_params.rx_chains_num; + /* correct rx chain count according hw settings + * and chain noise calibration + */ + valid_rx_cnt = iwl_count_chain_bitmap(active_chains); + if (valid_rx_cnt < active_rx_cnt) + active_rx_cnt = valid_rx_cnt; + + if (valid_rx_cnt < idle_rx_cnt) + idle_rx_cnt = valid_rx_cnt; rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain); - if (!is_single && (active_rx_cnt >= 2) && is_cam) + if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam) priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; else priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; - IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n", + IWL_DEBUG_ASSOC("rx_chain=0x%X active=%d idle=%d\n", priv->staging_rxon.rx_chain, active_rx_cnt, idle_rx_cnt); @@ -788,7 +822,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_set_rxon_chain); /** - * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON + * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz * @channel: Any channel valid for the requested phymode @@ -797,10 +831,11 @@ EXPORT_SYMBOL(iwl_set_rxon_chain); * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the phymode */ -int iwl_set_rxon_channel(struct iwl_priv *priv, - enum ieee80211_band band, - u16 channel) +int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch) { + enum ieee80211_band band = ch->band; + u16 channel = ieee80211_frequency_to_channel(ch->center_freq); + if (!iwl_get_channel_info(priv, band, channel)) { IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", channel, band); @@ -834,6 +869,10 @@ int iwl_setup_mac(struct iwl_priv *priv) /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; /* queues to support 11n aggregation */ @@ -891,7 +930,6 @@ int iwl_init_drv(struct iwl_priv *priv) spin_lock_init(&priv->power_data.lock); spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); - spin_lock_init(&priv->lq_mngr.lock); INIT_LIST_HEAD(&priv->free_frames); @@ -905,10 +943,10 @@ int iwl_init_drv(struct iwl_priv *priv) priv->ieee_rates = NULL; priv->band = IEEE80211_BAND_2GHZ; - priv->iw_mode = IEEE80211_IF_TYPE_STA; + priv->iw_mode = NL80211_IFTYPE_STATION; priv->use_ant_b_for_management_frame = 1; /* start with ant B */ - priv->ps_mode = IWL_MIMO_PS_NONE; + priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ iwl_set_rxon_chain(priv); @@ -922,8 +960,6 @@ int iwl_init_drv(struct iwl_priv *priv) priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; - iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); - priv->rates_mask = IWL_RATES_MASK; /* If power management is turned on, default to AC mode */ priv->power_mode = IWL_POWER_AC; @@ -950,22 +986,6 @@ err: } EXPORT_SYMBOL(iwl_init_drv); -void iwl_free_calib_results(struct iwl_priv *priv) -{ - kfree(priv->calib_results.lo_res); - priv->calib_results.lo_res = NULL; - priv->calib_results.lo_res_len = 0; - - kfree(priv->calib_results.tx_iq_res); - priv->calib_results.tx_iq_res = NULL; - priv->calib_results.tx_iq_res_len = 0; - - kfree(priv->calib_results.tx_iq_perd_res); - priv->calib_results.tx_iq_perd_res = NULL; - priv->calib_results.tx_iq_perd_res_len = 0; -} -EXPORT_SYMBOL(iwl_free_calib_results); - int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret = 0; @@ -993,10 +1013,9 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) } EXPORT_SYMBOL(iwl_set_tx_power); - void iwl_uninit_drv(struct iwl_priv *priv) { - iwl_free_calib_results(priv); + iwl_calib_free_results(priv); iwlcore_free_geos(priv); iwl_free_channel_map(priv); kfree(priv->scan); @@ -1150,7 +1169,6 @@ int iwl_verify_ucode(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_verify_ucode); - static const char *desc_lookup(int i) { switch (i) { @@ -1231,9 +1249,9 @@ EXPORT_SYMBOL(iwl_dump_nic_error_log); /** * iwl_print_event_log - Dump error event log to syslog * - * NOTE: Must be called with iwl4965_grab_nic_access() already obtained! + * NOTE: Must be called with iwl_grab_nic_access() already obtained! */ -void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, +static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 num_events, u32 mode) { u32 i; @@ -1274,8 +1292,6 @@ void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, } } } -EXPORT_SYMBOL(iwl_print_event_log); - void iwl_dump_nic_event_log(struct iwl_priv *priv) { @@ -1391,7 +1407,7 @@ void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv) iwl_scan_cancel(priv); /* FIXME: This is a workaround for AP */ - if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode != NL80211_IFTYPE_AP) { spin_lock_irqsave(&priv->lock, flags); iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_SW_BIT_RFKILL); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 64f139e9744..288b6a800e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -184,14 +184,10 @@ struct iwl_cfg { struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops); void iwl_hw_detect(struct iwl_priv *priv); - void iwl_clear_stations_table(struct iwl_priv *priv); -void iwl_free_calib_results(struct iwl_priv *priv); void iwl_reset_qos(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); -int iwl_set_rxon_channel(struct iwl_priv *priv, - enum ieee80211_band band, - u16 channel); +int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, struct ieee80211_ht_info *sta_ht_inf); @@ -218,7 +214,6 @@ void iwl_rx_replenish(struct iwl_priv *priv); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); -/* FIXME: remove when TX is moved to iwl core */ int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_rx_allocate(struct iwl_priv *priv); @@ -237,11 +232,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, ******************************************************/ int iwl_txq_ctx_reset(struct iwl_priv *priv); int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); -/* FIXME: remove when free Tx is fully merged into iwlcore */ -int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); void iwl_hw_txq_ctx_free(struct iwl_priv *priv); -int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, - dma_addr_t addr, u16 len); int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); @@ -256,6 +247,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); * RF -Kill - here and not in iwl-rfkill.h to be available when * RF-kill subsystem is not compiled. ****************************************************/ +void iwl_rf_kill(struct iwl_priv *priv); void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv); int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); @@ -286,11 +278,17 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) void iwl_init_scan_params(struct iwl_priv *priv); int iwl_scan_cancel(struct iwl_priv *priv); int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); -const char *iwl_escape_essid(const char *essid, u8 essid_len); int iwl_scan_initiate(struct iwl_priv *priv); void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); void iwl_setup_scan_deferred_work(struct iwl_priv *priv); +/******************************************************************************* + * Calibrations - implemented in iwl-calib.c + ******************************************************************************/ +int iwl_send_calib_results(struct iwl_priv *priv); +int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); +void iwl_calib_free_results(struct iwl_priv *priv); + /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ @@ -312,8 +310,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /***************************************************** * Error Handling Debugging ******************************************************/ -void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode); void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); @@ -337,8 +333,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv); #define STATUS_SCAN_HW 15 #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 -#define STATUS_CONF_PENDING 18 -#define STATUS_MODE_PENDING 19 +#define STATUS_MODE_PENDING 18 static inline int iwl_is_ready(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 52629fbd835..662edf4f8d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -64,7 +64,7 @@ #define CSR_BASE (0x000) #define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ -#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ +#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ #define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ #define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ #define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index d2daa174df2..e548d67f87f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -110,11 +110,12 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) * */ -#define IWL_DL_INFO (1 << 0) -#define IWL_DL_MAC80211 (1 << 1) -#define IWL_DL_HOST_COMMAND (1 << 2) -#define IWL_DL_STATE (1 << 3) +#define IWL_DL_INFO (1 << 0) +#define IWL_DL_MAC80211 (1 << 1) +#define IWL_DL_HCMD (1 << 2) +#define IWL_DL_STATE (1 << 3) #define IWL_DL_MACDUMP (1 << 4) +#define IWL_DL_HCMD_DUMP (1 << 5) #define IWL_DL_RADIO (1 << 7) #define IWL_DL_POWER (1 << 8) #define IWL_DL_TEMP (1 << 9) @@ -162,7 +163,8 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DEBUG_ISR(f, a...) IWL_DEBUG(IWL_DL_ISR, f, ## a) #define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a) #define IWL_DEBUG_WEP(f, a...) IWL_DEBUG(IWL_DL_WEP, f, ## a) -#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a) +#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HCMD, f, ## a) +#define IWL_DEBUG_HC_DUMP(f, a...) IWL_DEBUG(IWL_DL_HCMD_DUMP, f, ## a) #define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a) #define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a) #define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cdfb343c7ec..c018121085e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -225,12 +225,6 @@ struct iwl_frame { struct list_head list; }; -#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) -#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) -#define SEQ_TO_INDEX(x) ((u8)(x & 0xff)) -#define INDEX_TO_SEQ(x) ((u8)(x & 0xff)) -#define SEQ_HUGE_FRAME (0x4000) -#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) @@ -412,6 +406,7 @@ struct iwl_ht_info { /* self configuration data */ u8 is_ht; u8 supported_chan_width; + u8 sm_ps; u8 is_green_field; u8 sgf; /* HT_SHORT_GI_* short guard interval */ u8 max_amsdu_size; @@ -570,50 +565,31 @@ struct iwl_hw_params { #define IWL_RX_STATS(x) (&x->u.rx_frame.stats) #define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) - /****************************************************************************** * - * Functions implemented in iwl-base.c which are forward declared here - * for use by iwl-*.c + * Functions implemented in core module which are forward declared here + * for use by iwl-[4-5].c * - *****************************************************************************/ -struct iwl_addsta_cmd; -extern int iwl_send_add_sta(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags); -u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, - u8 flags, struct ieee80211_ht_info *ht_info); -extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left); -extern void iwl4965_update_chain_flags(struct iwl_priv *priv); -int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); -extern int iwl4965_set_power(struct iwl_priv *priv, void *cmd); - -extern const u8 iwl_bcast_addr[ETH_ALEN]; - -/****************************************************************************** - * - * Functions implemented in iwl-[34]*.c which are forward declared here - * for use by iwl-base.c - * - * NOTE: The implementation of these functions are hardware specific - * which is why they are in the hardware specific files (vs. iwl-base.c) + * NOTE: The implementation of these functions are not hardware specific + * which is why they are in the core module files. * * Naming convention -- - * iwl4965_ <-- Its part of iwlwifi (should be changed to iwl4965_) - * iwl4965_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) + * 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 * ****************************************************************************/ +struct iwl_addsta_cmd; +extern int iwl_send_add_sta(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags); +extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, + int is_ap, u8 flags, struct ieee80211_ht_info *ht_info); +extern void iwl4965_update_chain_flags(struct iwl_priv *priv); +extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); +extern const u8 iwl_bcast_addr[ETH_ALEN]; extern int iwl_rxq_stop(struct iwl_priv *priv); extern void iwl_txq_ctx_stop(struct iwl_priv *priv); -extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame, u8 rate); -extern void iwl4965_disable_events(struct iwl_priv *priv); - -extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); extern int iwl_queue_space(const struct iwl_queue *q); static inline int iwl_queue_used(const struct iwl_queue *q, int i) { @@ -636,12 +612,6 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) struct iwl_priv; -/* - * Forward declare iwl-4965.c functions for iwl-base.c - */ -extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); -int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, - u8 tid, int txq_id); /* Structures, enum, and defines specific to the 4965 */ @@ -656,11 +626,6 @@ struct iwl_kw { #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 -#define IWL_MIMO_PS_STATIC 0 -#define IWL_MIMO_PS_NONE 3 -#define IWL_MIMO_PS_DYNAMIC 1 -#define IWL_MIMO_PS_INVALID 2 - #define IWL_OPERATION_MODE_AUTO 0 #define IWL_OPERATION_MODE_HT_ONLY 1 #define IWL_OPERATION_MODE_MIXED 2 @@ -671,18 +636,6 @@ struct iwl_kw { #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 -struct iwl4965_lq_mngr { - spinlock_t lock; - s32 max_window_size; - s32 *expected_tpt; - u8 *next_higher_rate; - u8 *next_lower_rate; - unsigned long stamp; - unsigned long stamp_last; - u32 flush_time; - u32 tx_packets; -}; - /* Sensitivity and chain noise calibration */ #define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) #define INITIALIZATION_VALUE 0xFFFF @@ -727,8 +680,9 @@ enum iwl4965_false_alarm_state { enum iwl4965_chain_noise_state { IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ - IWL_CHAIN_NOISE_ACCUMULATE = 1, - IWL_CHAIN_NOISE_CALIBRATED = 2, + IWL_CHAIN_NOISE_ACCUMULATE, + IWL_CHAIN_NOISE_CALIBRATED, + IWL_CHAIN_NOISE_DONE, }; enum iwl4965_calib_enabled_state { @@ -745,13 +699,10 @@ struct statistics_general_data { u32 beacon_energy_c; }; -struct iwl_calib_results { - void *tx_iq_res; - void *tx_iq_perd_res; - void *lo_res; - u32 tx_iq_res_len; - u32 tx_iq_perd_res_len; - u32 lo_res_len; +/* Opaque calibration results */ +struct iwl_calib_result { + void *buf; + size_t buf_len; }; enum ucode_type { @@ -789,17 +740,18 @@ struct iwl_sensitivity_data { /* Chain noise (differential Rx gain) calib data */ struct iwl_chain_noise_data { - u8 state; - u16 beacon_count; + u32 active_chains; u32 chain_noise_a; u32 chain_noise_b; u32 chain_noise_c; u32 chain_signal_a; u32 chain_signal_b; u32 chain_signal_c; + u16 beacon_count; u8 disconn_array[NUM_RX_CHAINS]; u8 delta_gain_code[NUM_RX_CHAINS]; u8 radio_write; + u8 state; }; #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ @@ -813,6 +765,7 @@ enum { #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ +#define IWL_CALIB_MAX 3 struct iwl_priv { @@ -828,7 +781,6 @@ struct iwl_priv { enum ieee80211_band band; int alloc_rxb_skb; - bool add_radiotap; void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); @@ -857,7 +809,7 @@ struct iwl_priv { s32 last_temperature; /* init calibration results */ - struct iwl_calib_results calib_results; + struct iwl_calib_result calib_results[IWL_CALIB_MAX]; /* Scan related variables */ unsigned long last_scan_jiffies; @@ -939,9 +891,6 @@ struct iwl_priv { u8 last_phy_res[100]; /* Rate scaling data */ - struct iwl4965_lq_mngr lq_mngr; - - /* Rate scaling data */ s8 data_retry_limit; u8 retry_rate; @@ -1005,7 +954,7 @@ struct iwl_priv { u8 *eeprom; struct iwl_eeprom_calib_info *calib_info; - enum ieee80211_if_types iw_mode; + enum nl80211_iftype iw_mode; struct sk_buff *ibss_beacon; @@ -1025,7 +974,6 @@ struct iwl_priv { * hardware */ u16 assoc_id; u16 assoc_capability; - u8 ps_mode; struct iwl_qos_info qos_data; @@ -1047,6 +995,7 @@ struct iwl_priv { struct tasklet_struct irq_tasklet; + struct delayed_work set_power_save; struct delayed_work init_alive_start; struct delayed_work alive_start; struct delayed_work scan_check; diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index cd11c0ca299..a72efdf6d1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -247,8 +247,8 @@ #define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MSK (0x00F00000) /* bits 20-23 */ #define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MSK (0xC0000000) /* bits 30-31*/ -#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) -#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT (4) +#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS (20) +#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS (4) #define RX_RB_TIMEOUT (0x10) #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) @@ -260,8 +260,9 @@ #define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000) #define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000) -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) +#define FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY (0x00000004) +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) /** diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 2eb03eea190..8300f3d00a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -120,8 +120,18 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv, return 1; } - IWL_DEBUG_HC("back from %s (0x%08X)\n", - get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); +#ifdef CONFIG_IWLWIFI_DEBUG + switch (cmd->hdr.cmd) { + case REPLY_TX_LINK_QUALITY_CMD: + case SENSITIVITY_CMD: + IWL_DEBUG_HC_DUMP("back from %s (0x%08X)\n", + get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); + break; + default: + IWL_DEBUG_HC("back from %s (0x%08X)\n", + get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); + } +#endif /* Let iwl_tx_complete free the response skb */ return 1; diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 5bc3df432d2..9740fcc1805 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -61,7 +61,7 @@ * */ -#define _iwl_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs)) +#define _iwl_write32(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) @@ -75,7 +75,7 @@ static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, #define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) #endif -#define _iwl_read32(priv, ofs) readl((priv)->hw_base + (ofs)) +#define _iwl_read32(priv, ofs) ioread32((priv)->hw_base + (ofs)) #ifdef CONFIG_IWLWIFI_DEBUG static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) { @@ -155,28 +155,10 @@ static inline void __iwl_clear_bit(const char *f, u32 l, static inline int _iwl_grab_nic_access(struct iwl_priv *priv) { int ret; - u32 gp_ctl; - #ifdef CONFIG_IWLWIFI_DEBUG if (atomic_read(&priv->restrict_refcnt)) return 0; #endif - if (test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARNING("WARNING: Requesting MAC access during RFKILL " - "wakes up NIC\n"); - - /* 10 msec allows time for NIC to complete its data save */ - gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL); - if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { - IWL_DEBUG_RF_KILL("Wait for complete power-down, " - "gpctl = 0x%08x\n", gp_ctl); - mdelay(10); - } else - IWL_DEBUG_RF_KILL("power-down complete, " - "gpctl = 0x%08x\n", gp_ctl); - } - /* this bit wakes up the NIC */ _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index a099c9e30e5..60a03d2d2d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -152,9 +152,10 @@ static u16 iwl_get_auto_power_mode(struct iwl_priv *priv) /* initialize to default */ static int iwl_power_init_handle(struct iwl_priv *priv) { - int ret = 0, i; struct iwl_power_mgr *pow_data; int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX; + struct iwl_powertable_cmd *cmd; + int i; u16 pci_pm; IWL_DEBUG_POWER("Initialize power \n"); @@ -167,25 +168,19 @@ static int iwl_power_init_handle(struct iwl_priv *priv) memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); - ret = pci_read_config_word(priv->pci_dev, - PCI_LINK_CTRL, &pci_pm); - if (ret != 0) - return 0; - else { - struct iwl_powertable_cmd *cmd; + pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &pci_pm); - IWL_DEBUG_POWER("adjust power command flags\n"); + IWL_DEBUG_POWER("adjust power command flags\n"); - for (i = 0; i < IWL_POWER_MAX; i++) { - cmd = &pow_data->pwr_range_0[i].cmd; + for (i = 0; i < IWL_POWER_MAX; i++) { + cmd = &pow_data->pwr_range_0[i].cmd; - if (pci_pm & 0x1) - cmd->flags &= ~IWL_POWER_PCI_PM_MSK; - else - cmd->flags |= IWL_POWER_PCI_PM_MSK; - } + if (pci_pm & PCI_CFG_LINK_CTRL_VAL_L0S_EN) + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + else + cmd->flags |= IWL_POWER_PCI_PM_MSK; } - return ret; + return 0; } /* adjust power command according to dtim period and power level*/ @@ -255,17 +250,26 @@ static int iwl_update_power_command(struct iwl_priv *priv, /* - * calucaute the final power mode index + * compute the final power mode index */ -int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) +int iwl_power_update_mode(struct iwl_priv *priv, bool force) { struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; u16 uninitialized_var(final_mode); - /* If on battery, set to 3, - * if plugged into AC power, set to CAM ("continuously aware mode"), - * else user level */ + /* Don't update the RX chain when chain noise calibration is running */ + if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE && + priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) { + IWL_DEBUG_POWER("Cannot update the power, chain noise " + "calibration running: %d\n", + priv->chain_noise_data.state); + return -EAGAIN; + } + + /* If on battery, set to 3, + * if plugged into AC power, set to CAM ("continuously aware mode"), + * else user level */ switch (setting->system_power_setting) { case IWL_POWER_SYS_AUTO: @@ -286,11 +290,11 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) final_mode = setting->critical_power_setting; /* driver only support CAM for non STA network */ - if (priv->iw_mode != IEEE80211_IF_TYPE_STA) + if (priv->iw_mode != NL80211_IFTYPE_STATION) final_mode = IWL_POWER_MODE_CAM; if (!iwl_is_rfkill(priv) && !setting->power_disabled && - ((setting->power_mode != final_mode) || refresh)) { + ((setting->power_mode != final_mode) || force)) { struct iwl_powertable_cmd cmd; if (final_mode != IWL_POWER_MODE_CAM) @@ -324,7 +328,7 @@ EXPORT_SYMBOL(iwl_power_update_mode); * this will be usefull for rate scale to disable PM during heavy * Tx/Rx activities */ -int iwl_power_disable_management(struct iwl_priv *priv) +int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) { u16 prev_mode; int ret = 0; @@ -337,6 +341,11 @@ int iwl_power_disable_management(struct iwl_priv *priv) ret = iwl_power_update_mode(priv, 0); priv->power_data.power_disabled = 1; priv->power_data.user_power_setting = prev_mode; + cancel_delayed_work(&priv->set_power_save); + if (ms) + queue_delayed_work(priv->workqueue, &priv->set_power_save, + msecs_to_jiffies(ms)); + return ret; } @@ -359,35 +368,26 @@ EXPORT_SYMBOL(iwl_power_enable_management); /* set user_power_setting */ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) { - int ret = 0; - if (mode > IWL_POWER_LIMIT) return -EINVAL; priv->power_data.user_power_setting = mode; - ret = iwl_power_update_mode(priv, 0); - - return ret; + return iwl_power_update_mode(priv, 0); } EXPORT_SYMBOL(iwl_power_set_user_mode); - /* set system_power_setting. This should be set by over all * PM application. */ int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) { - int ret = 0; - if (mode > IWL_POWER_LIMIT) return -EINVAL; priv->power_data.system_power_setting = mode; - ret = iwl_power_update_mode(priv, 0); - - return ret; + return iwl_power_update_mode(priv, 0); } EXPORT_SYMBOL(iwl_power_set_system_mode); @@ -431,3 +431,35 @@ int iwl_power_temperature_change(struct iwl_priv *priv) return ret; } EXPORT_SYMBOL(iwl_power_temperature_change); + +static void iwl_bg_set_power_save(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, + struct iwl_priv, set_power_save.work); + IWL_DEBUG(IWL_DL_STATE, "update power\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + /* on starting association we disable power managment + * until association, if association failed then this + * timer will expire and enable PM again. + */ + if (!iwl_is_associated(priv)) + iwl_power_enable_management(priv); + + mutex_unlock(&priv->mutex); +} +void iwl_setup_power_deferred_work(struct iwl_priv *priv) +{ + INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save); +} +EXPORT_SYMBOL(iwl_setup_power_deferred_work); + +void iwl_power_cancel_timeout(struct iwl_priv *priv) +{ + cancel_delayed_work(&priv->set_power_save); +} +EXPORT_SYMBOL(iwl_power_cancel_timeout); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index abcbbf96a84..df484a90ae6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -72,14 +72,16 @@ struct iwl_power_mgr { /* final power level that used to calculate final power command */ u8 power_mode; u8 user_power_setting; /* set by user through mac80211 or sysfs */ - u8 system_power_setting; /* set by kernel syatem tools */ + u8 system_power_setting; /* set by kernel system tools */ u8 critical_power_setting; /* set if driver over heated */ u8 is_battery_active; /* DC/AC power */ u8 power_disabled; /* flag to disable using power saving level */ }; -int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh); -int iwl_power_disable_management(struct iwl_priv *priv); +void iwl_setup_power_deferred_work(struct iwl_priv *priv); +void iwl_power_cancel_timeout(struct iwl_priv *priv); +int iwl_power_update_mode(struct iwl_priv *priv, bool force); +int iwl_power_disable_management(struct iwl_priv *priv, u32 ms); int iwl_power_enable_management(struct iwl_priv *priv); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e81bfc42a7c..7cde9d76ff5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -376,7 +376,9 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { int ret; unsigned long flags; - unsigned int rb_size; + u32 rb_size; + const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ + const u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT why this stalls RX */ spin_lock_irqsave(&priv->lock, flags); ret = iwl_grab_nic_access(priv); @@ -398,26 +400,32 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Tell device where to find RBD circular buffer in DRAM */ iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, - rxq->dma_addr >> 8); + (u32)(rxq->dma_addr >> 8)); /* Tell device where in DRAM to update its Rx status */ iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, (priv->shared_phys + priv->rb_closed_offset) >> 4); - /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ + /* Enable Rx DMA + * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set becuase of HW bug in + * the credit mechanism in 5000 HW RX FIFO + * Direct rx interrupts to hosts + * Rx buffer size 4 or 8k + * RB timeout 0x10 + * 256 RBDs + */ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | + FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - rb_size | - /* 0x10 << 4 | */ - (RX_QUEUE_SIZE_LOG << - FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); - - /* - * iwl_write32(priv,CSR_INT_COAL_REG,0); - */ + rb_size| + (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| + (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); iwl_release_nic_access(priv); + + iwl_write32(priv, CSR_INT_COALESCING, 0x40); + spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -789,107 +797,6 @@ static inline void iwl_dbg_report_frame(struct iwl_priv *priv, } #endif -static void iwl_add_radiotap(struct iwl_priv *priv, - struct sk_buff *skb, - struct iwl_rx_phy_res *rx_start, - struct ieee80211_rx_status *stats, - u32 ampdu_status) -{ - s8 signal = stats->signal; - s8 noise = 0; - int rate = stats->rate_idx; - u64 tsf = stats->mactime; - __le16 antenna; - __le16 phy_flags_hw = rx_start->phy_flags; - struct iwl4965_rt_rx_hdr { - struct ieee80211_radiotap_header rt_hdr; - __le64 rt_tsf; /* TSF */ - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channelMHz; /* channel in MHz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ - s8 rt_dbmnoise; - u8 rt_antenna; /* antenna number */ - } __attribute__ ((packed)) *iwl4965_rt; - - /* TODO: We won't have enough headroom for HT frames. Fix it later. */ - if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { - if (net_ratelimit()) - printk(KERN_ERR "not enough headroom [%d] for " - "radiotap head [%zd]\n", - skb_headroom(skb), sizeof(*iwl4965_rt)); - return; - } - - /* put radiotap header in front of 802.11 header and data */ - iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); - - /* initialise radiotap header */ - iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl4965_rt->rt_hdr.it_pad = 0; - - /* total header + data */ - put_unaligned_le16(sizeof(*iwl4965_rt), &iwl4965_rt->rt_hdr.it_len); - - /* Indicate all the fields we add to the radiotap header */ - put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA), - &(iwl4965_rt->rt_hdr.it_present)); - - /* Zero the flags, we'll add to them as we go */ - iwl4965_rt->rt_flags = 0; - - put_unaligned_le64(tsf, &iwl4965_rt->rt_tsf); - - iwl4965_rt->rt_dbmsignal = signal; - iwl4965_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, - &iwl4965_rt->rt_chbitmask); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, - &iwl4965_rt->rt_chbitmask); - else /* 802.11g */ - put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, - &iwl4965_rt->rt_chbitmask); - - if (rate == -1) - iwl4965_rt->rt_rate = 0; - else - iwl4965_rt->rt_rate = iwl_rates[rate].ieee; - - /* - * "antenna number" - * - * It seems that the antenna field in the phy flags value - * is actually a bitfield. This is undefined by radiotap, - * it wants an actual antenna number but I always get "7" - * for most legacy frames I receive indicating that the - * same frame was received on all three RX chains. - * - * I think this field should be removed in favour of a - * new 802.11n radiotap field "RX chains" that is defined - * as a bitmask. - */ - antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; - iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; - - /* set the preamble flag if appropriate */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - stats->flag |= RX_FLAG_RADIOTAP; -} - static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) { /* 0 - mgmt, 1 - cnt, 2 - data */ @@ -1074,9 +981,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - if (priv->add_radiotap) - iwl_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); - iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); priv->alloc_rxb_skb--; @@ -1130,10 +1034,10 @@ static int iwl_is_network_packet(struct iwl_priv *priv, /* Filter incoming packets to determine if they are targeted toward * this network, discarding packets coming from ourselves */ switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */ /* packets to our IBSS update information */ return !compare_ether_addr(header->addr3, priv->bssid); - case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ /* packets to our IBSS update information */ return !compare_ether_addr(header->addr2, priv->bssid); default: @@ -1171,7 +1075,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (rx_status.band == IEEE80211_BAND_5GHZ) rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; - rx_status.antenna = 0; rx_status.flag = 0; /* TSF isn't reliable. In order to allow smooth user experience, @@ -1253,8 +1156,28 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, rx_status.signal, rx_status.noise, rx_status.signal, (unsigned long long)rx_status.mactime); + /* + * "antenna number" + * + * It seems that the antenna field in the phy flags value + * is actually a bitfield. This is undefined by radiotap, + * it wants an actual antenna number but I always get "7" + * for most legacy frames I receive indicating that the + * same frame was received on all three RX chains. + * + * I think this field should be removed in favour of a + * new 802.11n radiotap field "RX chains" that is defined + * as a bitmask. + */ + rx_status.antenna = le16_to_cpu(rx_start->phy_flags & + RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if appropriate */ + if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + rx_status.flag |= RX_FLAG_SHORTPRE; + /* Take shortcut when only in monitor mode */ - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { iwl_pass_packet_to_mac80211(priv, include_phy, rxb, &rx_status); return; @@ -1271,7 +1194,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: case IEEE80211_FTYPE_DATA: - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, header->addr2); /* fall through */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 6c8ac3a87d5..3b0bee331a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -88,7 +88,7 @@ static int iwl_is_empty_essid(const char *essid, int essid_len) -const char *iwl_escape_essid(const char *essid, u8 essid_len) +static const char *iwl_escape_essid(const char *essid, u8 essid_len) { static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; const char *s = essid; @@ -111,7 +111,6 @@ const char *iwl_escape_essid(const char *essid, u8 essid_len) *d = '\0'; return escaped; } -EXPORT_SYMBOL(iwl_escape_essid); /** * iwl_scan_cancel - Cancel any currently executing HW scan @@ -464,11 +463,6 @@ void iwl_init_scan_params(struct iwl_priv *priv) int iwl_scan_initiate(struct iwl_priv *priv) { - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - IWL_ERROR("APs don't scan.\n"); - return 0; - } - if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); return -EIO; @@ -480,8 +474,7 @@ int iwl_scan_initiate(struct iwl_priv *priv) } if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN("Scan request while abort pending. " - "Queuing.\n"); + IWL_DEBUG_SCAN("Scan request while abort pending\n"); return -EAGAIN; } @@ -710,7 +703,7 @@ static void iwl_bg_request_scan(struct work_struct *data) u16 cmd_len; enum ieee80211_band band; u8 n_probes = 2; - u8 rx_chain = 0x7; /* bitmap: ABC chains */ + u8 rx_chain = priv->hw_params.valid_rx_ant; conf = ieee80211_get_hw_conf(priv->hw); @@ -850,7 +843,7 @@ static void iwl_bg_request_scan(struct work_struct *data) /* Force use of chains B and C (0x6) for scan Rx for 4965 * Avoid A (0x1) because of its off-channel reception on A-band. - * MIMO is not used here, but value is required */ + */ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) rx_chain = 0x6; } else { @@ -858,6 +851,7 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } + /* MIMO is not used here, but value is required */ scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | @@ -869,7 +863,7 @@ static void iwl_bg_request_scan(struct work_struct *data) scan->tx_cmd.len = cpu_to_le16(cmd_len); - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | @@ -922,10 +916,29 @@ static void iwl_bg_abort_scan(struct work_struct *work) mutex_unlock(&priv->mutex); } +static void iwl_bg_scan_completed(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, scan_completed); + + IWL_DEBUG_SCAN("SCAN complete scan\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + ieee80211_scan_completed(priv->hw); + + /* Since setting the TXPOWER may have been deferred while + * performing the scan, fire one off */ + mutex_lock(&priv->mutex); + iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + mutex_unlock(&priv->mutex); +} + + void iwl_setup_scan_deferred_work(struct iwl_priv *priv) { - /* FIXME: move here when resolved PENDING - * INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); */ + INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); INIT_WORK(&priv->request_scan, iwl_bg_request_scan); INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 6283a3a707f..61797f3f8d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -47,8 +47,8 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) unsigned long flags; DECLARE_MAC_BUF(mac); - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || - (priv->iw_mode == IEEE80211_IF_TYPE_AP)) + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || + (priv->iw_mode == NL80211_IFTYPE_AP)) start = IWL_STA_ID; if (is_broadcast_ether_addr(addr)) @@ -74,7 +74,7 @@ EXPORT_SYMBOL(iwl_find_station); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + if (priv->iw_mode == NL80211_IFTYPE_STATION) { return IWL_AP_ID; } else { u8 *da = ieee80211_get_DA(hdr); @@ -191,20 +191,20 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, if (!sta_ht_inf || !sta_ht_inf->ht_supported) goto done; - mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; + mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; sta_flags = priv->stations[index].sta.station_flags; sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); switch (mimo_ps_mode) { - case WLAN_HT_CAP_MIMO_PS_STATIC: + case WLAN_HT_CAP_SM_PS_STATIC: sta_flags |= STA_FLG_MIMO_DIS_MSK; break; - case WLAN_HT_CAP_MIMO_PS_DYNAMIC: + case WLAN_HT_CAP_SM_PS_DYNAMIC: sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; break; - case WLAN_HT_CAP_MIMO_PS_DISABLED: + case WLAN_HT_CAP_SM_PS_DISABLED: break; default: IWL_WARNING("Invalid MIMO PS mode %d\n", mimo_ps_mode); @@ -286,7 +286,7 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, /* BCAST station and IBSS stations do not work in HT mode */ if (sta_id != priv->hw_params.bcast_sta_id && - priv->iw_mode != IEEE80211_IF_TYPE_IBSS) + priv->iw_mode != NL80211_IFTYPE_ADHOC) iwl_set_ht_add_station(priv, sta_id, ht_info); spin_unlock_irqrestore(&priv->sta_lock, flags_spin); @@ -817,7 +817,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, }; if ((lq->sta_id == 0xFF) && - (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) + (priv->iw_mode == NL80211_IFTYPE_ADHOC)) return -EINVAL; if (lq->sta_id == 0xFF) @@ -904,7 +904,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) if ((is_ap) && (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + (priv->iw_mode == NL80211_IFTYPE_STATION)) sta_id = iwl_add_station_flags(priv, addr, is_ap, 0, cur_ht_config); else @@ -938,11 +938,11 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If we are a client station in a BSS network, use the special * AP station entry (that's the only station we communicate with) */ - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: return IWL_AP_ID; /* If we are an AP, then find the station, or use BCAST */ - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -950,7 +950,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If this frame is going out to an IBSS network, find the station, * or create a new station table entry */ - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -968,6 +968,11 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; + /* If we are in monitor mode, use BCAST. This is required for + * packet injection. */ + case NL80211_IFTYPE_MONITOR: + return priv->hw_params.bcast_sta_id; + default: IWL_WARNING("Unknown mode of operation: %d\n", priv->iw_mode); return priv->hw_params.bcast_sta_id; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 78b1a7a4ca4..907a53ebc6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -63,7 +63,7 @@ static const u16 default_tid_to_tx_fifo[] = { * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +static int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) { struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; @@ -115,10 +115,8 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) } return 0; } -EXPORT_SYMBOL(iwl_hw_txq_free_tfd); - -int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, +static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, dma_addr_t addr, u16 len) { int index, is_odd; @@ -126,7 +124,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); /* Each TFD can point to a maximum 20 Tx buffers */ - if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { + if (num_tbs >= MAX_NUM_OF_TBS) { IWL_ERROR("Error can not send more than %d chunks\n", MAX_NUM_OF_TBS); return -EINVAL; @@ -151,7 +149,6 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, return 0; } -EXPORT_SYMBOL(iwl_hw_txq_attach_buf_to_tfd); /** * iwl_txq_update_write_ptr - Send new write index to hardware @@ -478,7 +475,6 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_hw_txq_ctx_free); - /** * iwl_txq_ctx_reset - Reset TX queue context * Destroys all DMA structures and initialise them again @@ -545,6 +541,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error_kw: return ret; } + /** * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory */ @@ -796,11 +793,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) goto drop_unlock; } - if (!priv->vif) { - IWL_DEBUG_DROP("Dropping - !priv->vif\n"); - goto drop_unlock; - } - if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); @@ -822,16 +814,18 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* drop all data frame if we are not associated */ if (ieee80211_is_data(fc) && - (!iwl_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || - !priv->assoc_station_added)) { + (priv->iw_mode != NL80211_IFTYPE_MONITOR || + !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */ + (!iwl_is_associated(priv) || + ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) || + !priv->assoc_station_added)) { IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); goto drop_unlock; } spin_unlock_irqrestore(&priv->lock, flags); - hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc)); + hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ sta_id = iwl_get_sta_id(priv, hdr); @@ -849,7 +843,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txq_id = swq_id; if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; seq_number = priv->stations[sta_id].tid[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl = hdr->seq_ctrl & @@ -1064,7 +1058,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | INDEX_TO_SEQ(q->write_ptr)); if (out_cmd->meta.flags & CMD_SIZE_HUGE) - out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); + out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; len = (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd); phys_addr = pci_map_single(priv->pci_dev, out_cmd, len, @@ -1072,12 +1066,26 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) phys_addr += offsetof(struct iwl_cmd, hdr); iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); - IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " - "%d bytes at %d[%d]:%d\n", - get_cmd_string(out_cmd->hdr.cmd), - out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), - fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); - +#ifdef CONFIG_IWLWIFI_DEBUG + switch (out_cmd->hdr.cmd) { + case REPLY_TX_LINK_QUALITY_CMD: + case SENSITIVITY_CMD: + IWL_DEBUG_HC_DUMP("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, + le16_to_cpu(out_cmd->hdr.sequence), fix_size, + q->write_ptr, idx, IWL_CMD_QUEUE_NUM); + break; + default: + IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, + le16_to_cpu(out_cmd->hdr.sequence), fix_size, + q->write_ptr, idx, IWL_CMD_QUEUE_NUM); + } +#endif txq->need_update = 1; /* Set up entry in queue's byte count circular buffer */ @@ -1185,17 +1193,16 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); - int huge = sequence & SEQ_HUGE_FRAME; int cmd_index; + bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); struct iwl_cmd *cmd; /* 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 * in the queue management code. */ - if (txq_id != IWL_CMD_QUEUE_NUM) - IWL_ERROR("Error wrong command queue %d command id 0x%X\n", - txq_id, pkt->hdr.cmd); - BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); + if (WARN(txq_id != IWL_CMD_QUEUE_NUM, + "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd)) + return; cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index b775d5bab66..d15a2c99795 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1160,7 +1160,7 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ if (iwl3945_is_associated(priv) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + (priv->iw_mode == NL80211_IFTYPE_STATION)) if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding AP address for transmit.\n"); @@ -1447,8 +1447,8 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, { if (!iwl3945_is_associated(priv) || !priv->ibss_beacon || - ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && - (priv->iw_mode != IEEE80211_IF_TYPE_AP))) + ((priv->iw_mode != NL80211_IFTYPE_ADHOC) && + (priv->iw_mode != NL80211_IFTYPE_AP))) return 0; if (priv->ibss_beacon->len > left) @@ -1746,14 +1746,14 @@ static void iwl3945_reset_qos(struct iwl3945_priv *priv) spin_lock_irqsave(&priv->lock, flags); priv->qos_data.qos_active = 0; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { if (priv->qos_data.qos_enable) priv->qos_data.qos_active = 1; if (!(priv->active_rate & 0xfff0)) { cw_min = 31; is_legacy = 1; } - } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + } else if (priv->iw_mode == NL80211_IFTYPE_AP) { if (priv->qos_data.qos_enable) priv->qos_data.qos_active = 1; } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { @@ -2120,7 +2120,7 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv) beacon_int = priv->beacon_int; spin_unlock_irqrestore(&priv->lock, flags); - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + if (priv->iw_mode == NL80211_IFTYPE_STATION) { if (beacon_int == 0) { priv->rxon_timing.beacon_interval = cpu_to_le16(100); priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); @@ -2156,7 +2156,7 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv) static int iwl3945_scan_initiate(struct iwl3945_priv *priv) { - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("APs don't scan.\n"); return 0; } @@ -2218,7 +2218,7 @@ static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, else priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; @@ -2237,23 +2237,23 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; @@ -2282,7 +2282,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) * in some case A channels are all non IBSS * in this case force B/G channel */ - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info))) ch_info = &priv->channel_info[0]; @@ -2302,7 +2302,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) { - if (mode == IEEE80211_IF_TYPE_IBSS) { + if (mode == NL80211_IFTYPE_ADHOC) { const struct iwl3945_channel_info *ch_info; ch_info = iwl3945_get_channel_info(priv, @@ -2469,11 +2469,11 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h /* If we are a client station in a BSS network, use the special * AP station entry (that's the only station we communicate with) */ - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: return IWL_AP_ID; /* If we are an AP, then find the station, or use BCAST */ - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -2481,7 +2481,7 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h /* If this frame is going out to an IBSS network, find the station, * or create a new station table entry */ - case IEEE80211_IF_TYPE_IBSS: { + case NL80211_IFTYPE_ADHOC: { DECLARE_MAC_BUF(mac); /* Create new station table entry */ @@ -2502,7 +2502,7 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h } /* If we are in monitor mode, use BCAST. This is required for * packet injection. */ - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: return priv->hw_setting.bcast_sta_id; default: @@ -2565,16 +2565,16 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) /* drop all data frame if we are not associated */ if (ieee80211_is_data(fc) && - (priv->iw_mode != IEEE80211_IF_TYPE_MNTR) && /* packet injection */ + (priv->iw_mode != NL80211_IFTYPE_MONITOR) && /* packet injection */ (!iwl3945_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id))) { + ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) { IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n"); goto drop_unlock; } spin_unlock_irqrestore(&priv->lock, flags); - hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc)); + hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ sta_id = iwl3945_get_sta_id(priv, hdr); @@ -2590,7 +2590,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | @@ -2709,7 +2709,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) sizeof(out_cmd->cmd.tx)); iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, - ieee80211_get_hdrlen(le16_to_cpu(fc))); + ieee80211_hdrlen(fc)); /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); @@ -2806,7 +2806,7 @@ static void iwl3945_radio_kill_sw(struct iwl3945_priv *priv, int disable_radio) if (disable_radio) { iwl3945_scan_cancel(priv); /* FIXME: This is a workaround for AP */ - if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode != NL80211_IFTYPE_AP) { spin_lock_irqsave(&priv->lock, flags); iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_SW_BIT_RFKILL); @@ -3161,7 +3161,7 @@ static void iwl3945_rx_beacon_notif(struct iwl3945_priv *priv, le32_to_cpu(beacon->low_tsf), rate); #endif - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + if ((priv->iw_mode == NL80211_IFTYPE_AP) && (!test_bit(STATUS_EXIT_PENDING, &priv->status))) queue_work(priv->workqueue, &priv->beacon_update); } @@ -4782,8 +4782,11 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after * sending probe req. This should be set long enough to hear probe responses * from more than one AP. */ -#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */ -#define IWL_ACTIVE_DWELL_TIME_52 (10) +#define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */ +#define IWL_ACTIVE_DWELL_TIME_52 (20) + +#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3) +#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2) /* For faster active scanning, scan will move to the next channel if fewer than * PLCP_QUIET_THRESH packets are heard on this channel within @@ -4792,7 +4795,7 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) * no other traffic). * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ #define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ -#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */ +#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(10) /* msec */ /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. * Must be set longer than active dwell time. @@ -4802,19 +4805,23 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 +#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) + static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, - enum ieee80211_band band) + enum ieee80211_band band, + u8 n_probes) { if (band == IEEE80211_BAND_5GHZ) - return IWL_ACTIVE_DWELL_TIME_52; + return IWL_ACTIVE_DWELL_TIME_52 + + IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1); else - return IWL_ACTIVE_DWELL_TIME_24; + return IWL_ACTIVE_DWELL_TIME_24 + + IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); } static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, enum ieee80211_band band) { - u16 active = iwl3945_get_active_dwell_time(priv, band); u16 passive = (band == IEEE80211_BAND_2GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; @@ -4829,15 +4836,12 @@ static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; } - if (passive <= active) - passive = active + 1; - return passive; } static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, enum ieee80211_band band, - u8 is_active, u8 direct_mask, + u8 is_active, u8 n_probes, struct iwl3945_scan_channel *scan_ch) { const struct ieee80211_channel *channels = NULL; @@ -4853,9 +4857,12 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, channels = sband->channels; - active_dwell = iwl3945_get_active_dwell_time(priv, band); + active_dwell = iwl3945_get_active_dwell_time(priv, band, n_probes); passive_dwell = iwl3945_get_passive_dwell_time(priv, band); + if (passive_dwell <= active_dwell) + passive_dwell = active_dwell + 1; + for (i = 0, added = 0; i < sband->n_channels; i++) { if (channels[i].flags & IEEE80211_CHAN_DISABLED) continue; @@ -4875,8 +4882,8 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, else scan_ch->type = 1; /* active */ - if (scan_ch->type & 1) - scan_ch->type |= (direct_mask << 1); + if ((scan_ch->type & 1) && n_probes) + scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); scan_ch->active_dwell = cpu_to_le16(active_dwell); scan_ch->passive_dwell = cpu_to_le16(passive_dwell); @@ -6052,7 +6059,7 @@ static void iwl3945_bg_set_monitor(struct work_struct *work) if (!iwl3945_is_ready(priv)) IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); else - if (iwl3945_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0) + if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0) IWL_ERROR("iwl3945_set_mode() failed\n"); mutex_unlock(&priv->mutex); @@ -6093,7 +6100,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) int rc = 0; struct iwl3945_scan_cmd *scan; struct ieee80211_conf *conf = NULL; - u8 direct_mask; + u8 n_probes = 2; enum ieee80211_band band; conf = ieee80211_get_hw_conf(priv->hw); @@ -6201,7 +6208,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); - direct_mask = 1; + n_probes++; } else if (!iwl3945_is_associated(priv) && priv->essid_len) { IWL_DEBUG_SCAN ("Kicking off one direct scan for '%s' when not associated\n", @@ -6209,11 +6216,9 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); - direct_mask = 1; - } else { + n_probes++; + } else IWL_DEBUG_SCAN("Kicking off one indirect scan.\n"); - direct_mask = 0; - } /* We don't build a direct scan probe request; the uCode will do * that based on the direct_mask added to each channel entry */ @@ -6243,21 +6248,13 @@ static void iwl3945_bg_request_scan(struct work_struct *data) /* select Rx antennas */ scan->flags |= iwl3945_get_antenna_flags(priv); - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; - if (direct_mask) - scan->channel_count = - iwl3945_get_channels_for_scan( - priv, band, 1, /* active */ - direct_mask, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); - else - scan->channel_count = - iwl3945_get_channels_for_scan( - priv, band, 0, /* passive */ - direct_mask, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + scan->channel_count = + iwl3945_get_channels_for_scan(priv, band, 1, /* active */ + n_probes, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); cmd.len += le16_to_cpu(scan->tx_cmd.len) + scan->channel_count * sizeof(struct iwl3945_scan_channel); @@ -6320,16 +6317,13 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) #define IWL_DELAY_NEXT_SCAN (HZ*2) -static void iwl3945_bg_post_associate(struct work_struct *data) +static void iwl3945_post_associate(struct iwl3945_priv *priv) { - struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, - post_associate.work); - int rc = 0; struct ieee80211_conf *conf = NULL; DECLARE_MAC_BUF(mac); - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __func__); return; } @@ -6342,12 +6336,9 @@ static void iwl3945_bg_post_associate(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - mutex_lock(&priv->mutex); - - if (!priv->vif || !priv->is_open) { - mutex_unlock(&priv->mutex); + if (!priv->vif || !priv->is_open) return; - } + iwl3945_scan_cancel_timeout(priv, 200); conf = ieee80211_get_hw_conf(priv->hw); @@ -6381,7 +6372,7 @@ static void iwl3945_bg_post_associate(struct work_struct *data) else priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; } @@ -6389,11 +6380,11 @@ static void iwl3945_bg_post_associate(struct work_struct *data) iwl3945_commit_rxon(priv); switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: iwl3945_rate_scale_init(priv->hw, IWL_AP_ID); break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: /* clear out the station table */ iwl3945_clear_stations_table(priv); @@ -6419,7 +6410,6 @@ static void iwl3945_bg_post_associate(struct work_struct *data) /* we have just associated, don't start scan too early */ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; - mutex_unlock(&priv->mutex); } static void iwl3945_bg_abort_scan(struct work_struct *work) @@ -6567,7 +6557,6 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw) */ mutex_lock(&priv->mutex); iwl3945_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); mutex_unlock(&priv->mutex); } @@ -6650,8 +6639,6 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); - priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); - if (!iwl3945_is_ready(priv)) { IWL_DEBUG_MAC80211("leave - not ready\n"); ret = -EIO; @@ -6767,7 +6754,7 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; } @@ -6804,7 +6791,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, } /* handle this temporarily here */ - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && conf->changed & IEEE80211_IFCC_BEACON) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) @@ -6816,7 +6803,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, /* XXX: this MUST use conf->mac_addr */ - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + if ((priv->iw_mode == NL80211_IFTYPE_AP) && (!conf->ssid_len)) { IWL_DEBUG_MAC80211 ("Leaving in AP mode because HostAPD is not ready.\n"); @@ -6839,7 +6826,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { */ - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); @@ -6874,11 +6861,11 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, * to verify) - jpk */ memcpy(priv->bssid, conf->bssid, ETH_ALEN); - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl3945_config_ap(priv); else { rc = iwl3945_commit_rxon(priv); - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) + if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0); } @@ -6914,7 +6901,7 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw, if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - IEEE80211_IF_TYPE_MNTR, + NL80211_IFTYPE_MONITOR, changed_flags, *total_flags); /* queue work 'cuz mac80211 is holding a lock which * prevents us from issuing (synchronous) f/w cmds */ @@ -6935,7 +6922,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, if (iwl3945_is_ready_rf(priv)) { iwl3945_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl3945_commit_rxon(priv); } @@ -6950,6 +6936,63 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211("leave\n"); } +#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) + +static void iwl3945_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct iwl3945_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("changes = 0x%X\n", changes); + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n", + bss_conf->use_short_preamble); + if (bss_conf->use_short_preamble) + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + } + + if (changes & BSS_CHANGED_ERP_CTS_PROT) { + IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) + priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; + } + + if (changes & BSS_CHANGED_ASSOC) { + IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc); + /* This should never happen as this function should + * never be called from interrupt context. */ + if (WARN_ON_ONCE(in_interrupt())) + return; + if (bss_conf->assoc) { + priv->assoc_id = bss_conf->aid; + priv->beacon_int = bss_conf->beacon_int; + priv->timestamp0 = bss_conf->timestamp & 0xFFFFFFFF; + priv->timestamp1 = (bss_conf->timestamp >> 32) & + 0xFFFFFFFF; + priv->assoc_capability = bss_conf->assoc_capability; + priv->next_scan_jiffies = jiffies + + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; + mutex_lock(&priv->mutex); + iwl3945_post_associate(priv); + mutex_unlock(&priv->mutex); + } else { + priv->assoc_id = 0; + IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc); + } + } else if (changes && iwl3945_is_associated(priv) && priv->assoc_id) { + IWL_DEBUG_MAC80211("Associated Changes %d\n", changes); + iwl3945_send_rxon_assoc(priv); + } + +} + static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) { int rc = 0; @@ -6967,7 +7010,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) goto out_unlock; } - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ + if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ rc = -EIO; IWL_ERROR("ERROR: APs don't scan\n"); goto out_unlock; @@ -7109,7 +7152,7 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, spin_unlock_irqrestore(&priv->lock, flags); mutex_lock(&priv->mutex); - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl3945_activate_qos(priv, 1); else if (priv->assoc_id && iwl3945_is_associated(priv)) iwl3945_activate_qos(priv, 0); @@ -7182,8 +7225,6 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) iwl3945_reset_qos(priv); - cancel_delayed_work(&priv->post_associate); - spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = 0; priv->assoc_capability = 0; @@ -7198,7 +7239,7 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) priv->beacon_int = priv->hw->conf.beacon_int; priv->timestamp1 = 0; priv->timestamp0 = 0; - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) + if ((priv->iw_mode == NL80211_IFTYPE_STATION)) priv->beacon_int = 0; spin_unlock_irqrestore(&priv->lock, flags); @@ -7212,14 +7253,14 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) /* we are restarting association process * clear RXON_FILTER_ASSOC_MSK bit */ - if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode != NL80211_IFTYPE_AP) { iwl3945_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl3945_commit_rxon(priv); } /* Per mac80211.h: This is only used in IBSS mode... */ - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not in IBSS\n"); mutex_unlock(&priv->mutex); @@ -7248,7 +7289,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk return -EIO; } - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); mutex_unlock(&priv->mutex); return -EIO; @@ -7268,7 +7309,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk iwl3945_reset_qos(priv); - queue_work(priv->workqueue, &priv->post_associate.work); + iwl3945_post_associate(priv); mutex_unlock(&priv->mutex); @@ -7329,15 +7370,6 @@ static ssize_t show_temperature(struct device *d, static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); -static ssize_t show_rs_window(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct iwl3945_priv *priv = d->driver_data; - return iwl3945_fill_rs_info(priv->hw, buf, IWL_AP_ID); -} -static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL); - static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { @@ -7767,7 +7799,6 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv) INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor); - INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check); @@ -7785,7 +7816,6 @@ static void iwl3945_cancel_deferred_work(struct iwl3945_priv *priv) cancel_delayed_work_sync(&priv->init_alive_start); cancel_delayed_work(&priv->scan_check); cancel_delayed_work(&priv->alive_start); - cancel_delayed_work(&priv->post_associate); cancel_work_sync(&priv->beacon_update); } @@ -7801,7 +7831,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { #endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, - &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, &dev_attr_temperature.attr, @@ -7830,6 +7859,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .conf_tx = iwl3945_mac_conf_tx, .get_tsf = iwl3945_mac_get_tsf, .reset_tsf = iwl3945_mac_reset_tsf, + .bss_info_changed = iwl3945_bss_info_changed, .hw_scan = iwl3945_mac_hw_scan }; @@ -7868,6 +7898,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e SET_IEEE80211_DEV(hw, &pdev->dev); hw->rate_control_algorithm = "iwl-3945-rs"; + hw->sta_data_size = sizeof(struct iwl3945_sta_priv); IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); priv = hw->priv; @@ -7890,6 +7921,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + /* 4 EDCA QOS priorities */ hw->queues = 4; @@ -7951,7 +7987,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_DEBUG_INFO("Radio disabled.\n"); } - priv->iw_mode = IEEE80211_IF_TYPE_STA; + priv->iw_mode = NL80211_IFTYPE_STATION; printk(KERN_INFO DRV_NAME ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); @@ -8331,6 +8367,8 @@ static void __exit iwl3945_exit(void) iwl3945_rate_control_unregister(); } +MODULE_FIRMWARE("iwlwifi-3945" IWL3945_UCODE_API ".ucode"); + module_param_named(antenna, iwl3945_param_antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); module_param_named(disable, iwl3945_param_disable, int, 0444); diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a267d6e65f0..92be60415d0 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -8,6 +8,7 @@ #include "scan.h" #include "cmd.h" +static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp); static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -20,12 +21,88 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = #define CAPINFO_MASK (~(0xda00)) +/** + * @brief This function finds common rates between rates and card rates. + * + * It will fill common rates in rates as output if found. + * + * NOTE: Setting the MSB of the basic rates need to be taken + * care, either before or after calling this function + * + * @param priv A pointer to struct lbs_private structure + * @param rates the buffer which keeps input and output + * @param rates_size the size of rate1 buffer; new size of buffer on return + * + * @return 0 on success, or -1 on error + */ +static int get_common_rates(struct lbs_private *priv, + u8 *rates, + u16 *rates_size) +{ + u8 *card_rates = lbs_bg_rates; + size_t num_card_rates = sizeof(lbs_bg_rates); + int ret = 0, i, j; + u8 tmp[30]; + size_t tmp_size = 0; + + /* For each rate in card_rates that exists in rate1, copy to tmp */ + for (i = 0; card_rates[i] && (i < num_card_rates); i++) { + for (j = 0; rates[j] && (j < *rates_size); j++) { + if (rates[j] == card_rates[i]) + tmp[tmp_size++] = card_rates[i]; + } + } + + lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); + lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); + lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); + + if (!priv->enablehwauto) { + for (i = 0; i < tmp_size; i++) { + if (tmp[i] == priv->cur_rate) + goto done; + } + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", priv->cur_rate); + ret = -1; + goto done; + } + ret = 0; + +done: + memset(rates, 0, *rates_size); + *rates_size = min_t(int, tmp_size, *rates_size); + memcpy(rates, tmp, *rates_size); + return ret; +} + + +/** + * @brief Sets the MSB on basic rates as the firmware requires + * + * Scan through an array and set the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +static void lbs_set_basic_rate_flags(u8 *rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (rates[i] == 0x02 || rates[i] == 0x04 || + rates[i] == 0x0b || rates[i] == 0x16) + rates[i] |= 0x80; + } +} + /** * @brief Associate to a specific BSS discovered in a scan * * @param priv A pointer to struct lbs_private structure - * @param pbssdesc Pointer to the BSS descriptor to associate with. + * @param assoc_req The association request describing the BSS to associate with * * @return 0-success, otherwise fail */ @@ -33,29 +110,29 @@ static int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req) { int ret; + u8 preamble = RADIO_PREAMBLE_LONG; lbs_deb_enter(LBS_DEB_ASSOC); ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req->bss.bssid); - if (ret) - goto done; + goto out; - /* set preamble to firmware */ + /* Use short preamble only when both the BSS and firmware support it */ if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - else - priv->preamble = CMD_TYPE_LONG_PREAMBLE; + preamble = RADIO_PREAMBLE_SHORT; - lbs_set_radio_control(priv); + ret = lbs_set_radio(priv, preamble, 1); + if (ret) + goto out; ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); -done: +out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } @@ -64,17 +141,22 @@ done: * @brief Join an adhoc network found in a previous scan * * @param priv A pointer to struct lbs_private structure - * @param pbssdesc Pointer to a BSS descriptor found in a previous scan - * to attempt to join + * @param assoc_req The association request describing the BSS to join * - * @return 0--success, -1--fail + * @return 0 on success, error on failure */ -static int lbs_join_adhoc_network(struct lbs_private *priv, +static int lbs_adhoc_join(struct lbs_private *priv, struct assoc_request *assoc_req) { + struct cmd_ds_802_11_ad_hoc_join cmd; struct bss_descriptor *bss = &assoc_req->bss; + u8 preamble = RADIO_PREAMBLE_LONG; + DECLARE_MAC_BUF(mac); + u16 ratesize = 0; int ret = 0; + lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_join("current SSID '%s', ssid length %u\n", escape_essid(priv->curbssparams.ssid, priv->curbssparams.ssid_len), @@ -106,29 +188,106 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, goto out; } - /* Use shortpreamble only when both creator and card supports - short preamble */ - if (!(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) || - !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { - lbs_deb_join("AdhocJoin: Long preamble\n"); - priv->preamble = CMD_TYPE_LONG_PREAMBLE; - } else { + /* Use short preamble only when both the BSS and firmware support it */ + if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && + (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Short preamble\n"); - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + preamble = RADIO_PREAMBLE_SHORT; } - lbs_set_radio_control(priv); + ret = lbs_set_radio(priv, preamble, 1); + if (ret) + goto out; lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); priv->adhoccreate = 0; + priv->curbssparams.channel = bss->channel; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, - 0, CMD_OPTION_WAITFORRSP, - OID_802_11_SSID, assoc_req); + /* Build the join command */ + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + cmd.bss.type = CMD_BSS_TYPE_IBSS; + cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod); + + memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); + memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); + + memcpy(&cmd.bss.phyparamset, &bss->phyparamset, + sizeof(union ieeetypes_phyparamset)); + + memcpy(&cmd.bss.ssparamset, &bss->ssparamset, + sizeof(union IEEEtypes_ssparamset)); + + cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); + lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", + bss->capability, CAPINFO_MASK); + + /* information on BSSID descriptor passed to FW */ + lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", + print_mac(mac, cmd.bss.bssid), cmd.bss.ssid); + + /* Only v8 and below support setting these */ + if (priv->fwrelease < 0x09000000) { + /* failtimeout */ + cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + /* probedelay */ + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + } + + /* Copy Data rates from the rates recorded in scan response */ + memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates)); + ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES); + memcpy(cmd.bss.rates, bss->rates, ratesize); + if (get_common_rates(priv, cmd.bss.rates, &ratesize)) { + lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n"); + ret = -1; + goto out; + } + + /* Copy the ad-hoc creation rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); + + cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); + + if (assoc_req->secinfo.wep_enabled) { + u16 tmp = le16_to_cpu(cmd.bss.capability); + tmp |= WLAN_CAPABILITY_PRIVACY; + cmd.bss.capability = cpu_to_le16(tmp); + } + + if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { + __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM); + + /* wake up first */ + ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + CMD_ACT_SET, 0, 0, + &local_ps_mode); + if (ret) { + ret = -1; + goto out; + } + } + + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto out; + } + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); + if (ret == 0) + ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } @@ -136,39 +295,131 @@ out: * @brief Start an Adhoc Network * * @param priv A pointer to struct lbs_private structure - * @param adhocssid The ssid of the Adhoc Network - * @return 0--success, -1--fail + * @param assoc_req The association request describing the BSS to start + * + * @return 0 on success, error on failure */ -static int lbs_start_adhoc_network(struct lbs_private *priv, +static int lbs_adhoc_start(struct lbs_private *priv, struct assoc_request *assoc_req) { + struct cmd_ds_802_11_ad_hoc_start cmd; + u8 preamble = RADIO_PREAMBLE_LONG; + size_t ratesize = 0; + u16 tmpcap = 0; int ret = 0; - priv->adhoccreate = 1; + lbs_deb_enter(LBS_DEB_ASSOC); if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { - lbs_deb_join("AdhocStart: Short preamble\n"); - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - } else { - lbs_deb_join("AdhocStart: Long preamble\n"); - priv->preamble = CMD_TYPE_LONG_PREAMBLE; + lbs_deb_join("ADHOC_START: Will use short preamble\n"); + preamble = RADIO_PREAMBLE_SHORT; } - lbs_set_radio_control(priv); + ret = lbs_set_radio(priv, preamble, 1); + if (ret) + goto out; - lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); - lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); + /* Build the start command */ + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, - 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len); + + lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n", + escape_essid(assoc_req->ssid, assoc_req->ssid_len), + assoc_req->ssid_len); + + cmd.bsstype = CMD_BSS_TYPE_IBSS; + + if (priv->beacon_period == 0) + priv->beacon_period = MRVDRV_BEACON_INTERVAL; + cmd.beaconperiod = cpu_to_le16(priv->beacon_period); + + WARN_ON(!assoc_req->channel); + + /* set Physical parameter set */ + cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET; + cmd.phyparamset.dsparamset.len = 1; + cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; + + /* set IBSS parameter set */ + cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET; + cmd.ssparamset.ibssparamset.len = 2; + cmd.ssparamset.ibssparamset.atimwindow = 0; + + /* set capability info */ + tmpcap = WLAN_CAPABILITY_IBSS; + if (assoc_req->secinfo.wep_enabled) { + lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n"); + tmpcap |= WLAN_CAPABILITY_PRIVACY; + } else + lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n"); + + cmd.capability = cpu_to_le16(tmpcap); + + /* Only v8 and below support setting probe delay */ + if (priv->fwrelease < 0x09000000) + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + + ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates)); + memcpy(cmd.rates, lbs_bg_rates, ratesize); + + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize); + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(cmd.rates, ratesize); + + lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n", + cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]); + + if (lbs_create_dnld_countryinfo_11d(priv)) { + lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n"); + ret = -1; + goto out; + } + + lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n", + assoc_req->channel, assoc_req->band); + + priv->adhoccreate = 1; + priv->mode = IW_MODE_ADHOC; + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); + if (ret == 0) + ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); + +out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -int lbs_stop_adhoc_network(struct lbs_private *priv) +/** + * @brief Stop and Ad-Hoc network and exit Ad-Hoc mode + * + * @param priv A pointer to struct lbs_private structure + * @return 0 on success, or an error + */ +int lbs_adhoc_stop(struct lbs_private *priv) { - return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); + struct cmd_ds_802_11_ad_hoc_stop cmd; + int ret; + + lbs_deb_enter(LBS_DEB_JOIN); + + memset(&cmd, 0, sizeof (cmd)); + cmd.hdr.size = cpu_to_le16 (sizeof (cmd)); + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); + + /* Clean up everything even if there was an error */ + lbs_mac_event_disconnected(priv); + + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; } static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, @@ -480,14 +731,14 @@ static int assoc_helper_essid(struct lbs_private *priv, if (bss != NULL) { lbs_deb_assoc("SSID found, will join\n"); memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); - lbs_join_adhoc_network(priv, assoc_req); + lbs_adhoc_join(priv, assoc_req); } else { /* else send START command */ lbs_deb_assoc("SSID not found, creating adhoc network\n"); memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, IW_ESSID_MAX_SIZE); assoc_req->bss.ssid_len = assoc_req->ssid_len; - lbs_start_adhoc_network(priv, assoc_req); + lbs_adhoc_start(priv, assoc_req); } } @@ -520,7 +771,7 @@ static int assoc_helper_bssid(struct lbs_private *priv, ret = lbs_associate(priv, assoc_req); lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); } else if (assoc_req->mode == IW_MODE_ADHOC) { - lbs_join_adhoc_network(priv, assoc_req); + lbs_adhoc_join(priv, assoc_req); } out: @@ -572,11 +823,7 @@ static int assoc_helper_mode(struct lbs_private *priv, } priv->mode = assoc_req->mode; - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_SNMP_MIB, - 0, CMD_OPTION_WAITFORRSP, - OID_802_11_INFRASTRUCTURE_MODE, - /* Shoot me now */ (void *) (size_t) assoc_req->mode); + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode); done: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -1029,7 +1276,9 @@ void lbs_association_worker(struct work_struct *work) */ if (priv->mode == IW_MODE_INFRA) { if (should_deauth_infrastructure(priv, assoc_req)) { - ret = lbs_send_deauthentication(priv); + ret = lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); if (ret) { lbs_deb_assoc("Deauthentication due to new " "configuration request failed: %d\n", @@ -1038,7 +1287,7 @@ void lbs_association_worker(struct work_struct *work) } } else if (priv->mode == IW_MODE_ADHOC) { if (should_stop_adhoc(priv, assoc_req)) { - ret = lbs_stop_adhoc_network(priv); + ret = lbs_adhoc_stop(priv); if (ret) { lbs_deb_assoc("Teardown of AdHoc network due to " "new configuration request failed: %d\n", @@ -1214,94 +1463,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) /** - * @brief This function finds common rates between rate1 and card rates. - * - * It will fill common rates in rate1 as output if found. - * - * NOTE: Setting the MSB of the basic rates need to be taken - * care, either before or after calling this function - * - * @param priv A pointer to struct lbs_private structure - * @param rate1 the buffer which keeps input and output - * @param rate1_size the size of rate1 buffer; new size of buffer on return - * - * @return 0 or -1 - */ -static int get_common_rates(struct lbs_private *priv, - u8 *rates, - u16 *rates_size) -{ - u8 *card_rates = lbs_bg_rates; - size_t num_card_rates = sizeof(lbs_bg_rates); - int ret = 0, i, j; - u8 tmp[30]; - size_t tmp_size = 0; - - /* For each rate in card_rates that exists in rate1, copy to tmp */ - for (i = 0; card_rates[i] && (i < num_card_rates); i++) { - for (j = 0; rates[j] && (j < *rates_size); j++) { - if (rates[j] == card_rates[i]) - tmp[tmp_size++] = card_rates[i]; - } - } - - lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); - lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); - lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - - if (!priv->enablehwauto) { - for (i = 0; i < tmp_size; i++) { - if (tmp[i] == priv->cur_rate) - goto done; - } - lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", priv->cur_rate); - ret = -1; - goto done; - } - ret = 0; - -done: - memset(rates, 0, *rates_size); - *rates_size = min_t(int, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); - return ret; -} - - -/** - * @brief Sets the MSB on basic rates as the firmware requires - * - * Scan through an array and set the MSB for basic data rates. - * - * @param rates buffer of data rates - * @param len size of buffer - */ -static void lbs_set_basic_rate_flags(u8 *rates, size_t len) -{ - int i; - - for (i = 0; i < len; i++) { - if (rates[i] == 0x02 || rates[i] == 0x04 || - rates[i] == 0x0b || rates[i] == 0x16) - rates[i] |= 0x80; - } -} - -/** - * @brief Send Deauthentication Request - * - * @param priv A pointer to struct lbs_private structure - * @return 0--success, -1--fail - */ -int lbs_send_deauthentication(struct lbs_private *priv) -{ - return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); -} - -/** * @brief This function prepares command of authenticate. * * @param priv A pointer to struct lbs_private structure @@ -1353,26 +1514,37 @@ out: return ret; } -int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd) +/** + * @brief Deauthenticate from a specific BSS + * + * @param priv A pointer to struct lbs_private structure + * @param bssid The specific BSS to deauthenticate from + * @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating + * + * @return 0 on success, error on failure + */ +int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], + u16 reason) { - struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; + struct cmd_ds_802_11_deauthenticate cmd; + int ret; lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + - S_DS_GEN); + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + memcpy(cmd.macaddr, &bssid[0], ETH_ALEN); + cmd.reasoncode = cpu_to_le16(reason); - /* set AP MAC address */ - memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN); + ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd); - /* Reason code 3 = Station is leaving */ -#define REASON_CODE_STA_LEAVING 3 - dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); + /* Clean up everything even if there was an error; can't assume that + * we're still authenticated to the AP after trying to deauth. + */ + lbs_mac_event_disconnected(priv); lbs_deb_leave(LBS_DEB_JOIN); - return 0; + return ret; } int lbs_cmd_80211_associate(struct lbs_private *priv, @@ -1489,231 +1661,6 @@ done: return ret; } -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; - int ret = 0; - int cmdappendsize = 0; - struct assoc_request *assoc_req = pdata_buf; - u16 tmpcap = 0; - size_t ratesize = 0; - - lbs_deb_enter(LBS_DEB_JOIN); - - if (!priv) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START); - - /* - * Fill in the parameters for 2 data structures: - * 1. cmd_ds_802_11_ad_hoc_start command - * 2. priv->scantable[i] - * - * Driver will fill up SSID, bsstype,IBSS param, Physical Param, - * probe delay, and cap info. - * - * Firmware will fill up beacon period, DTIM, Basic rates - * and operational rates. - */ - - memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE); - memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len); - - lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len), - assoc_req->ssid_len); - - /* set the BSS type */ - adhs->bsstype = CMD_BSS_TYPE_IBSS; - priv->mode = IW_MODE_ADHOC; - if (priv->beacon_period == 0) - priv->beacon_period = MRVDRV_BEACON_INTERVAL; - adhs->beaconperiod = cpu_to_le16(priv->beacon_period); - - /* set Physical param set */ -#define DS_PARA_IE_ID 3 -#define DS_PARA_IE_LEN 1 - - adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID; - adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN; - - WARN_ON(!assoc_req->channel); - - lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n", - assoc_req->channel); - - adhs->phyparamset.dsparamset.currentchan = assoc_req->channel; - - /* set IBSS param set */ -#define IBSS_PARA_IE_ID 6 -#define IBSS_PARA_IE_LEN 2 - - adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; - adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; - adhs->ssparamset.ibssparamset.atimwindow = 0; - - /* set capability info */ - tmpcap = WLAN_CAPABILITY_IBSS; - if (assoc_req->secinfo.wep_enabled) { - lbs_deb_join("ADHOC_S_CMD: WEP enabled, " - "setting privacy on\n"); - tmpcap |= WLAN_CAPABILITY_PRIVACY; - } else { - lbs_deb_join("ADHOC_S_CMD: WEP disabled, " - "setting privacy off\n"); - } - adhs->capability = cpu_to_le16(tmpcap); - - /* probedelay */ - adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - memset(adhs->rates, 0, sizeof(adhs->rates)); - ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates)); - memcpy(adhs->rates, lbs_bg_rates, ratesize); - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(adhs->rates, ratesize); - - lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", - adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); - - lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); - - if (lbs_create_dnld_countryinfo_11d(priv)) { - lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) + - S_DS_GEN + cmdappendsize); - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd) -{ - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); - cmd->size = cpu_to_le16(S_DS_GEN); - - return 0; -} - -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; - struct assoc_request *assoc_req = pdata_buf; - struct bss_descriptor *bss = &assoc_req->bss; - int cmdappendsize = 0; - int ret = 0; - u16 ratesize = 0; - DECLARE_MAC_BUF(mac); - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN); - - join_cmd->bss.type = CMD_BSS_TYPE_IBSS; - join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); - - memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); - memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len); - - memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset, - sizeof(union ieeetypes_phyparamset)); - - memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset, - sizeof(union IEEEtypes_ssparamset)); - - join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); - lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", - bss->capability, CAPINFO_MASK); - - /* information on BSSID descriptor passed to FW */ - lbs_deb_join( - "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", - print_mac(mac, join_cmd->bss.bssid), - join_cmd->bss.ssid); - - /* failtimeout */ - join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); - - /* probedelay */ - join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - priv->curbssparams.channel = bss->channel; - - /* Copy Data rates from the rates recorded in scan response */ - memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); - ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); - memcpy(join_cmd->bss.rates, bss->rates, ratesize); - if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) { - lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); - ret = -1; - goto done; - } - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize); - - join_cmd->bss.ssparamset.ibssparamset.atimwindow = - cpu_to_le16(bss->atimwindow); - - if (assoc_req->secinfo.wep_enabled) { - u16 tmp = le16_to_cpu(join_cmd->bss.capability); - tmp |= WLAN_CAPABILITY_PRIVACY; - join_cmd->bss.capability = cpu_to_le16(tmp); - } - - if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { - /* wake up first */ - __le32 Localpsmode; - - Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_PS_MODE, - CMD_ACT_SET, - 0, 0, &Localpsmode); - - if (ret) { - ret = -1; - goto done; - } - } - - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) + - S_DS_GEN + cmdappendsize); - -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -1815,34 +1762,19 @@ done: return ret; } -int lbs_ret_80211_disassociate(struct lbs_private *priv) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} - -int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *resp) +static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) { int ret = 0; u16 command = le16_to_cpu(resp->command); u16 result = le16_to_cpu(resp->result); - struct cmd_ds_802_11_ad_hoc_result *padhocresult; + struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; union iwreq_data wrqu; struct bss_descriptor *bss; DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); - padhocresult = &resp->params.result; - - lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size)); - lbs_deb_join("ADHOC_RESP: command = %x\n", command); - lbs_deb_join("ADHOC_RESP: result = %x\n", result); + adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp; if (!priv->in_progress_assoc_req) { lbs_deb_join("ADHOC_RESP: no in-progress association " @@ -1856,26 +1788,19 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, * Join result code 0 --> SUCCESS */ if (result) { - lbs_deb_join("ADHOC_RESP: failed\n"); + lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); if (priv->connect_status == LBS_CONNECTED) lbs_mac_event_disconnected(priv); ret = -1; goto done; } - /* - * Now the join cmd should be successful - * If BSSID has changed use SSID to compare instead of BSSID - */ - lbs_deb_join("ADHOC_RESP: associated to '%s'\n", - escape_essid(bss->ssid, bss->ssid_len)); - /* Send a Media Connected event, according to the Spec */ priv->connect_status = LBS_CONNECTED; if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { /* Update the created network descriptor with the new BSSID */ - memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); + memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN); } /* Set the BSSID from the joined/started descriptor */ @@ -1894,22 +1819,13 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); - lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel); - lbs_deb_join("ADHOC_RESP: BSSID = %s\n", - print_mac(mac, padhocresult->bssid)); + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n", + escape_essid(bss->ssid, bss->ssid_len), + print_mac(mac, priv->curbssparams.bssid), + priv->curbssparams.channel); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); return ret; } -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index c516fbe518f..8b7336dd02a 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -12,28 +12,18 @@ struct cmd_ds_command; int lbs_cmd_80211_authenticate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); -int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd); -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); + +int lbs_adhoc_stop(struct lbs_private *priv); + int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd); + u8 bssid[ETH_ALEN], u16 reason); int lbs_cmd_80211_associate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp); -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv); -int lbs_ret_80211_disassociate(struct lbs_private *priv); int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp); -int lbs_stop_adhoc_network(struct lbs_private *priv); - -int lbs_send_deauthentication(struct lbs_private *priv); - #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 75427e61898..297696de2da 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -480,181 +480,166 @@ int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, return ret; } -static int lbs_cmd_802_11_reset(struct cmd_ds_command *cmd, int cmd_action) -{ - struct cmd_ds_802_11_reset *reset = &cmd->params.reset; - - lbs_deb_enter(LBS_DEB_CMD); - - cmd->command = cpu_to_le16(CMD_802_11_RESET); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); - reset->action = cpu_to_le16(cmd_action); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv, - struct cmd_ds_command *cmd, - int cmd_action, - int cmd_oid, void *pdata_buf) +/** + * @brief Set an SNMP MIB value + * + * @param priv A pointer to struct lbs_private structure + * @param oid The OID to set in the firmware + * @param val Value to set the OID to + * + * @return 0 on success, error on failure + */ +int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) { - struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib; - u8 ucTemp; + struct cmd_ds_802_11_snmp_mib cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); - - cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB); - cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN); - - switch (cmd_oid) { - case OID_802_11_INFRASTRUCTURE_MODE: - { - u8 mode = (u8) (size_t) pdata_buf; - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8)); - if (mode == IW_MODE_ADHOC) { - ucTemp = SNMP_MIB_VALUE_ADHOC; - } else { - /* Infra and Auto modes */ - ucTemp = SNMP_MIB_VALUE_INFRA; - } - - memmove(pSNMPMIB->value, &ucTemp, sizeof(u8)); + memset(&cmd, 0, sizeof (cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.oid = cpu_to_le16((u16) oid); + switch (oid) { + case SNMP_MIB_OID_BSS_TYPE: + cmd.bufsize = cpu_to_le16(sizeof(u8)); + cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1; break; + case SNMP_MIB_OID_11D_ENABLE: + case SNMP_MIB_OID_FRAG_THRESHOLD: + case SNMP_MIB_OID_RTS_THRESHOLD: + case SNMP_MIB_OID_SHORT_RETRY_LIMIT: + case SNMP_MIB_OID_LONG_RETRY_LIMIT: + cmd.bufsize = cpu_to_le16(sizeof(u16)); + *((__le16 *)(&cmd.value)) = cpu_to_le16(val); + break; + default: + lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid); + ret = -EINVAL; + goto out; } - case OID_802_11D_ENABLE: - { - u32 ulTemp; - - pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I); - - if (cmd_action == CMD_ACT_SET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); - ulTemp = *(u32 *)pdata_buf; - *((__le16 *)(pSNMPMIB->value)) = - cpu_to_le16((u16) ulTemp); - } - break; - } - - case OID_802_11_FRAGMENTATION_THRESHOLD: - { - u32 ulTemp; - - pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I); - - if (cmd_action == CMD_ACT_GET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); - } else if (cmd_action == CMD_ACT_SET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); - ulTemp = *((u32 *) pdata_buf); - *((__le16 *)(pSNMPMIB->value)) = - cpu_to_le16((u16) ulTemp); + lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n", + le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val); - } + ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd); - break; - } +out: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} - case OID_802_11_RTS_THRESHOLD: - { +/** + * @brief Get an SNMP MIB value + * + * @param priv A pointer to struct lbs_private structure + * @param oid The OID to retrieve from the firmware + * @param out_val Location for the returned value + * + * @return 0 on success, error on failure + */ +int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) +{ + struct cmd_ds_802_11_snmp_mib cmd; + int ret; - u32 ulTemp; - pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I); + lbs_deb_enter(LBS_DEB_CMD); - if (cmd_action == CMD_ACT_GET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); - } else if (cmd_action == CMD_ACT_SET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); - ulTemp = *((u32 *)pdata_buf); - *(__le16 *)(pSNMPMIB->value) = - cpu_to_le16((u16) ulTemp); + memset(&cmd, 0, sizeof (cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_GET); + cmd.oid = cpu_to_le16(oid); - } - break; - } - case OID_802_11_TX_RETRYCOUNT: - pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I); - - if (cmd_action == CMD_ACT_GET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); - } else if (cmd_action == CMD_ACT_SET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); - *((__le16 *)(pSNMPMIB->value)) = - cpu_to_le16((u16) priv->txretrycount); - } + ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd); + if (ret) + goto out; + switch (le16_to_cpu(cmd.bufsize)) { + case sizeof(u8): + if (oid == SNMP_MIB_OID_BSS_TYPE) { + if (cmd.value[0] == 2) + *out_val = IW_MODE_ADHOC; + else + *out_val = IW_MODE_INFRA; + } else + *out_val = cmd.value[0]; + break; + case sizeof(u16): + *out_val = le16_to_cpu(*((__le16 *)(&cmd.value))); break; default: + lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n", + oid, le16_to_cpu(cmd.bufsize)); break; } - lbs_deb_cmd( - "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n", - le16_to_cpu(cmd->command), le16_to_cpu(cmd->size), - le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result)); - - lbs_deb_cmd( - "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n", - le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid), - le16_to_cpu(pSNMPMIB->bufsize), - le16_to_cpu(*(__le16 *) pSNMPMIB->value)); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; +out: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; } -static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) +/** + * @brief Get the min, max, and current TX power + * + * @param priv A pointer to struct lbs_private structure + * @param curlevel Current power level in dBm + * @param minlevel Minimum supported power level in dBm (optional) + * @param maxlevel Maximum supported power level in dBm (optional) + * + * @return 0 on success, error on failure + */ +int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel) { - - struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp; + struct cmd_ds_802_11_rf_tx_power cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - cmd->size = - cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER); - prtp->action = cpu_to_le16(cmd_action); + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_GET); + + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); + if (ret == 0) { + *curlevel = le16_to_cpu(cmd.curlevel); + if (minlevel) + *minlevel = le16_to_cpu(cmd.minlevel); + if (maxlevel) + *maxlevel = le16_to_cpu(cmd.maxlevel); + } - lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", - le16_to_cpu(cmd->size), le16_to_cpu(cmd->command), - le16_to_cpu(prtp->action)); + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} - switch (cmd_action) { - case CMD_ACT_TX_POWER_OPT_GET: - prtp->action = cpu_to_le16(CMD_ACT_GET); - prtp->currentlevel = 0; - break; +/** + * @brief Set the TX power + * + * @param priv A pointer to struct lbs_private structure + * @param dbm The desired power level in dBm + * + * @return 0 on success, error on failure + */ +int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) +{ + struct cmd_ds_802_11_rf_tx_power cmd; + int ret; - case CMD_ACT_TX_POWER_OPT_SET_HIGH: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH); - break; + lbs_deb_enter(LBS_DEB_CMD); - case CMD_ACT_TX_POWER_OPT_SET_MID: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID); - break; + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.curlevel = cpu_to_le16(dbm); - case CMD_ACT_TX_POWER_OPT_SET_LOW: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf)); - break; - } + lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm); + + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); lbs_deb_leave(LBS_DEB_CMD); - return 0; + return ret; } static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd, @@ -838,7 +823,9 @@ int lbs_update_channel(struct lbs_private *priv) int lbs_set_channel(struct lbs_private *priv, u8 channel) { struct cmd_ds_802_11_rf_channel cmd; +#ifdef DEBUG u8 old_channel = priv->curbssparams.channel; +#endif int ret = 0; lbs_deb_enter(LBS_DEB_CMD); @@ -1033,9 +1020,9 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, return ret; } -int lbs_mesh_config_send(struct lbs_private *priv, - struct cmd_ds_mesh_config *cmd, - uint16_t action, uint16_t type) +static int __lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type) { int ret; @@ -1054,6 +1041,19 @@ int lbs_mesh_config_send(struct lbs_private *priv, return ret; } +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type) +{ + int ret; + + if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG)) + return -EOPNOTSUPP; + + ret = __lbs_mesh_config_send(priv, cmd, action, type); + return ret; +} + /* This function is the CMD_MESH_CONFIG legacy function. It only handles the * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG * are all handled by preparing a struct cmd_ds_mesh_config and passing it to @@ -1095,7 +1095,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) action, priv->mesh_tlv, chan, escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); - return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); + return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, @@ -1256,41 +1256,47 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, priv->cur_cmd = NULL; } -int lbs_set_radio_control(struct lbs_private *priv) +int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) { - int ret = 0; struct cmd_ds_802_11_radio_control cmd; + int ret = -EINVAL; lbs_deb_enter(LBS_DEB_CMD); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); - switch (priv->preamble) { - case CMD_TYPE_SHORT_PREAMBLE: - cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE); - break; - - case CMD_TYPE_LONG_PREAMBLE: - cmd.control = cpu_to_le16(SET_LONG_PREAMBLE); - break; + /* Only v8 and below support setting the preamble */ + if (priv->fwrelease < 0x09000000) { + switch (preamble) { + case RADIO_PREAMBLE_SHORT: + if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) + goto out; + /* Fall through */ + case RADIO_PREAMBLE_AUTO: + case RADIO_PREAMBLE_LONG: + cmd.control = cpu_to_le16(preamble); + break; + default: + goto out; + } + } - case CMD_TYPE_AUTO_PREAMBLE: - default: - cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE); - break; + if (radio_on) + cmd.control |= cpu_to_le16(0x1); + else { + cmd.control &= cpu_to_le16(~0x1); + priv->txpower_cur = 0; } - if (priv->radioon) - cmd.control |= cpu_to_le16(TURN_ON_RF); - else - cmd.control &= cpu_to_le16(~TURN_ON_RF); + lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n", + radio_on ? "ON" : "OFF", preamble); - lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon, - priv->preamble); + priv->radio_on = radio_on; ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); +out: lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -1380,55 +1386,25 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_DEAUTHENTICATE: - ret = lbs_cmd_80211_deauthenticate(priv, cmdptr); - break; - - case CMD_802_11_AD_HOC_START: - ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); - break; - - case CMD_802_11_RESET: - ret = lbs_cmd_802_11_reset(cmdptr, cmd_action); - break; - case CMD_802_11_AUTHENTICATE: ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_SNMP_MIB: - ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr, - cmd_action, cmd_oid, pdata_buf); - break; - case CMD_MAC_REG_ACCESS: case CMD_BBP_REG_ACCESS: case CMD_RF_REG_ACCESS: ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf); break; - case CMD_802_11_RF_TX_POWER: - ret = lbs_cmd_802_11_rf_tx_power(cmdptr, - cmd_action, pdata_buf); - break; - case CMD_802_11_MONITOR_MODE: ret = lbs_cmd_802_11_monitor_mode(cmdptr, cmd_action, pdata_buf); break; - case CMD_802_11_AD_HOC_JOIN: - ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); - break; - case CMD_802_11_RSSI: ret = lbs_cmd_802_11_rssi(priv, cmdptr); break; - case CMD_802_11_AD_HOC_STOP: - ret = lbs_cmd_80211_ad_hoc_stop(cmdptr); - break; - case CMD_802_11_SET_AFC: case CMD_802_11_GET_AFC: @@ -1953,6 +1929,70 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) } +/** + * @brief Configures the transmission power control functionality. + * + * @param priv A pointer to struct lbs_private structure + * @param enable Transmission power control enable + * @param p0 Power level when link quality is good (dBm). + * @param p1 Power level when link quality is fair (dBm). + * @param p2 Power level when link quality is poor (dBm). + * @param usesnr Use Signal to Noise Ratio in TPC + * + * @return 0 on success + */ +int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr) +{ + struct cmd_ds_802_11_tpc_cfg cmd; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.enable = !!enable; + cmd.usesnr = !!usesnr; + cmd.P0 = p0; + cmd.P1 = p1; + cmd.P2 = p2; + + ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd); + + return ret; +} + +/** + * @brief Configures the power adaptation settings. + * + * @param priv A pointer to struct lbs_private structure + * @param enable Power adaptation enable + * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm). + * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). + * @param p2 Power level for 48 and 54 Mbps (dBm). + * + * @return 0 on Success + */ + +int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, + int8_t p1, int8_t p2) +{ + struct cmd_ds_802_11_pa_cfg cmd; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.enable = !!enable; + cmd.P0 = p0; + cmd.P1 = p1; + cmd.P2 = p2; + + ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd); + + return ret; +} + + static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index a53b51f8bdb..36be4c9703e 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -26,6 +26,18 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), unsigned long callback_arg); +int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, + int8_t p1, int8_t p2); + +int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr); + +int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, + int8_t p1, int8_t p2); + +int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr); + int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp); @@ -61,4 +73,14 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, struct assoc_request *assoc); +int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel); +int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); + +int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on); + +int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val); + +int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val); + #endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 24de3c3cf87..bcf2a9756fb 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -146,63 +146,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv, return ret; } -static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; - u16 oid = le16_to_cpu(smib->oid); - u16 querytype = le16_to_cpu(smib->querytype); - - lbs_deb_enter(LBS_DEB_CMD); - - lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid, - querytype); - lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize)); - - if (querytype == CMD_ACT_GET) { - switch (oid) { - case FRAGTHRESH_I: - priv->fragthsd = - le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: frag threshold %u\n", - priv->fragthsd); - break; - case RTSTHRESH_I: - priv->rtsthsd = - le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: rts threshold %u\n", - priv->rtsthsd); - break; - case SHORT_RETRYLIM_I: - priv->txretrycount = - le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: tx retry count %u\n", - priv->rtsthsd); - break; - default: - break; - } - } - - lbs_deb_enter(LBS_DEB_CMD); - return 0; -} - -static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; - - lbs_deb_enter(LBS_DEB_CMD); - - priv->txpowerlevel = le16_to_cpu(rtp->currentlevel); - - lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -273,24 +216,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_80211_associate(priv, resp); break; - case CMD_RET(CMD_802_11_DISASSOCIATE): - case CMD_RET(CMD_802_11_DEAUTHENTICATE): - ret = lbs_ret_80211_disassociate(priv); - break; - - case CMD_RET(CMD_802_11_AD_HOC_START): - case CMD_RET(CMD_802_11_AD_HOC_JOIN): - ret = lbs_ret_80211_ad_hoc_start(priv, resp); - break; - - case CMD_RET(CMD_802_11_SNMP_MIB): - ret = lbs_ret_802_11_snmp_mib(priv, resp); - break; - - case CMD_RET(CMD_802_11_RF_TX_POWER): - ret = lbs_ret_802_11_rf_tx_power(priv, resp); - break; - case CMD_RET(CMD_802_11_SET_AFC): case CMD_RET(CMD_802_11_GET_AFC): spin_lock_irqsave(&priv->driver_lock, flags); @@ -300,7 +225,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; - case CMD_RET(CMD_802_11_RESET): case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_BEACON_STOP): break; @@ -309,10 +233,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_802_11_rssi(priv, resp); break; - case CMD_RET(CMD_802_11_AD_HOC_STOP): - ret = lbs_ret_80211_ad_hoc_stop(priv); - break; - case CMD_RET(CMD_802_11D_DOMAIN_INFO): ret = lbs_ret_802_11d_domain_info(resp); break; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index a8ac974daca..1a8888ccead 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -34,7 +34,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event); void lbs_queue_event(struct lbs_private *priv, u32 event); void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); -int lbs_set_radio_control(struct lbs_private *priv); u32 lbs_fw_index_to_data_rate(u8 index); u8 lbs_data_rate_to_fw_index(u32 rate); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 12e687550bc..076a636e8f6 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -189,6 +189,14 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MRVDRV_CMD_UPLD_RDY 0x0008 #define MRVDRV_CARDEVENT 0x0010 +/* Automatic TX control default levels */ +#define POW_ADAPT_DEFAULT_P0 13 +#define POW_ADAPT_DEFAULT_P1 15 +#define POW_ADAPT_DEFAULT_P2 18 +#define TPC_DEFAULT_P0 5 +#define TPC_DEFAULT_P1 10 +#define TPC_DEFAULT_P2 13 + /** TxPD status */ /* Station firmware use TxPD status field to report final Tx transmit @@ -243,6 +251,9 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define CMD_F_HOSTCMD (1 << 0) #define FW_CAPINFO_WPA (1 << 0) +#define FW_CAPINFO_FIRMWARE_UPGRADE (1 << 13) +#define FW_CAPINFO_BOOT2_UPGRADE (1<<14) +#define FW_CAPINFO_PERSISTENT_CONFIG (1<<15) #define KEY_LEN_WPA_AES 16 #define KEY_LEN_WPA_TKIP 32 @@ -316,7 +327,8 @@ enum PS_STATE { enum DNLD_STATE { DNLD_RES_RECEIVED, DNLD_DATA_SENT, - DNLD_CMD_SENT + DNLD_CMD_SENT, + DNLD_BOOTCMD_SENT, }; /** LBS_MEDIA_STATE */ @@ -339,27 +351,6 @@ enum mv_ms_type { MVMS_EVENT }; -/** SNMP_MIB_INDEX_e */ -enum SNMP_MIB_INDEX_e { - DESIRED_BSSTYPE_I = 0, - OP_RATESET_I, - BCNPERIOD_I, - DTIMPERIOD_I, - ASSOCRSP_TIMEOUT_I, - RTSTHRESH_I, - SHORT_RETRYLIM_I, - LONG_RETRYLIM_I, - FRAGTHRESH_I, - DOT11D_I, - DOT11H_I, - MANUFID_I, - PRODID_I, - MANUF_OUI_I, - MANUF_NAME_I, - MANUF_PRODNAME_I, - MANUF_PRODVER_I, -}; - /** KEY_TYPE_ID */ enum KEY_TYPE_ID { KEY_TYPE_ID_WEP = 0, @@ -374,12 +365,6 @@ enum KEY_INFO_WPA { KEY_INFO_WPA_ENABLED = 0x04 }; -/** SNMP_MIB_VALUE_e */ -enum SNMP_MIB_VALUE_e { - SNMP_MIB_VALUE_INFRA = 1, - SNMP_MIB_VALUE_ADHOC -}; - /* Default values for fwt commands. */ #define FWT_DEFAULT_METRIC 0 #define FWT_DEFAULT_DIR 1 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f5bb40c54d8..f6f3753da30 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -58,6 +58,7 @@ struct lbs_802_11_security { u8 WPA2enabled; u8 wep_enabled; u8 auth_mode; + u32 key_mgmt; }; /** Current Basic Service Set State Structure */ @@ -240,9 +241,6 @@ struct lbs_private { uint16_t enablehwauto; uint16_t ratebitmap; - u32 fragthsd; - u32 rtsthsd; - u8 txretrycount; /** Tx-related variables (for single packet tx) */ @@ -253,7 +251,9 @@ struct lbs_private { u32 connect_status; u32 mesh_connect_status; u16 regioncode; - u16 txpowerlevel; + s16 txpower_cur; + s16 txpower_min; + s16 txpower_max; /** POWER MANAGEMENT AND PnP SUPPORT */ u8 surpriseremoved; @@ -291,8 +291,7 @@ struct lbs_private { u16 nextSNRNF; u16 numSNRNF; - u8 radioon; - u32 preamble; + u8 radio_on; /** data rate stuff */ u8 cur_rate; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index c92e41b4faf..5004d7679c0 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -9,17 +9,6 @@ #define DEFAULT_AD_HOC_CHANNEL 6 #define DEFAULT_AD_HOC_CHANNEL_A 36 -/** IEEE 802.11 oids */ -#define OID_802_11_SSID 0x00008002 -#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008 -#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009 -#define OID_802_11_RTS_THRESHOLD 0x0000800A -#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D -#define OID_802_11_SUPPORTED_RATES 0x0000800E -#define OID_802_11_STATISTICS 0x00008012 -#define OID_802_11_TX_RETRYCOUNT 0x0000801D -#define OID_802_11D_ENABLE 0x00008020 - #define CMD_OPTION_WAITFORRSP 0x0002 /** Host command IDs */ @@ -61,7 +50,6 @@ #define CMD_RF_REG_MAP 0x0023 #define CMD_802_11_DEAUTHENTICATE 0x0024 #define CMD_802_11_REASSOCIATE 0x0025 -#define CMD_802_11_DISASSOCIATE 0x0026 #define CMD_MAC_CONTROL 0x0028 #define CMD_802_11_AD_HOC_START 0x002b #define CMD_802_11_AD_HOC_JOIN 0x002c @@ -84,6 +72,7 @@ #define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 #define CMD_802_11_SLEEP_PERIOD 0x0068 #define CMD_802_11_TPC_CFG 0x0072 +#define CMD_802_11_PA_CFG 0x0073 #define CMD_802_11_FW_WAKE_METHOD 0x0074 #define CMD_802_11_SUBSCRIBE_EVENT 0x0075 #define CMD_802_11_RATE_ADAPT_RATESET 0x0076 @@ -153,11 +142,6 @@ #define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 #define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 -/* Define action or option for CMD_802_11_RADIO_CONTROL */ -#define CMD_TYPE_AUTO_PREAMBLE 0x0001 -#define CMD_TYPE_SHORT_PREAMBLE 0x0002 -#define CMD_TYPE_LONG_PREAMBLE 0x0003 - /* Event flags for CMD_802_11_SUBSCRIBE_EVENT */ #define CMD_SUBSCRIBE_RSSI_LOW 0x0001 #define CMD_SUBSCRIBE_SNR_LOW 0x0002 @@ -166,28 +150,14 @@ #define CMD_SUBSCRIBE_RSSI_HIGH 0x0010 #define CMD_SUBSCRIBE_SNR_HIGH 0x0020 -#define TURN_ON_RF 0x01 -#define RADIO_ON 0x01 -#define RADIO_OFF 0x00 - -#define SET_AUTO_PREAMBLE 0x05 -#define SET_SHORT_PREAMBLE 0x03 -#define SET_LONG_PREAMBLE 0x01 +#define RADIO_PREAMBLE_LONG 0x00 +#define RADIO_PREAMBLE_SHORT 0x02 +#define RADIO_PREAMBLE_AUTO 0x04 /* Define action or option for CMD_802_11_RF_CHANNEL */ #define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 #define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 -/* Define action or option for CMD_802_11_RF_TX_POWER */ -#define CMD_ACT_TX_POWER_OPT_GET 0x0000 -#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007 -#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004 -#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000 - -#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007 -#define CMD_ACT_TX_POWER_INDEX_MID 0x0004 -#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 - /* Define action or option for CMD_802_11_DATA_RATE */ #define CMD_ACT_SET_TX_AUTO 0x0000 #define CMD_ACT_SET_TX_FIX_RATE 0x0001 @@ -210,6 +180,19 @@ #define CMD_WAKE_METHOD_COMMAND_INT 0x0001 #define CMD_WAKE_METHOD_GPIO 0x0002 +/* Object IDs for CMD_802_11_SNMP_MIB */ +#define SNMP_MIB_OID_BSS_TYPE 0x0000 +#define SNMP_MIB_OID_OP_RATE_SET 0x0001 +#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */ +#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */ +#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */ +#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005 +#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006 +#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007 +#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008 +#define SNMP_MIB_OID_11D_ENABLE 0x0009 +#define SNMP_MIB_OID_11H_ENABLE 0x000A + /* Define action or option for CMD_BT_ACCESS */ enum cmd_bt_access_opts { /* The bt commands start at 5 instead of 1 because the old dft commands diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 913b480211a..d9f9a12a739 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -151,10 +151,6 @@ struct cmd_ds_get_hw_spec { __le32 fwcapinfo; } __attribute__ ((packed)); -struct cmd_ds_802_11_reset { - __le16 action; -}; - struct cmd_ds_802_11_subscribe_event { struct cmd_header hdr; @@ -232,7 +228,9 @@ struct cmd_ds_802_11_authenticate { }; struct cmd_ds_802_11_deauthenticate { - u8 macaddr[6]; + struct cmd_header hdr; + + u8 macaddr[ETH_ALEN]; __le16 reasoncode; }; @@ -251,20 +249,10 @@ struct cmd_ds_802_11_associate { #endif } __attribute__ ((packed)); -struct cmd_ds_802_11_disassociate { - u8 destmacaddr[6]; - __le16 reasoncode; -}; - struct cmd_ds_802_11_associate_rsp { struct ieeetypes_assocrsp assocRsp; }; -struct cmd_ds_802_11_ad_hoc_result { - u8 pad[3]; - u8 bssid[ETH_ALEN]; -}; - struct cmd_ds_802_11_set_wep { struct cmd_header hdr; @@ -309,7 +297,9 @@ struct cmd_ds_802_11_get_stat { }; struct cmd_ds_802_11_snmp_mib { - __le16 querytype; + struct cmd_header hdr; + + __le16 action; __le16 oid; __le16 bufsize; u8 value[128]; @@ -435,8 +425,12 @@ struct cmd_ds_802_11_mac_address { }; struct cmd_ds_802_11_rf_tx_power { + struct cmd_header hdr; + __le16 action; - __le16 currentlevel; + __le16 curlevel; + s8 maxlevel; + s8 minlevel; }; struct cmd_ds_802_11_rf_antenna { @@ -507,10 +501,12 @@ struct cmd_ds_802_11_rate_adapt_rateset { }; struct cmd_ds_802_11_ad_hoc_start { + struct cmd_header hdr; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 bsstype; __le16 beaconperiod; - u8 dtimperiod; + u8 dtimperiod; /* Reserved on v9 and later */ union IEEEtypes_ssparamset ssparamset; union ieeetypes_phyparamset phyparamset; __le16 probedelay; @@ -519,9 +515,16 @@ struct cmd_ds_802_11_ad_hoc_start { u8 tlv_memory_size_pad[100]; } __attribute__ ((packed)); +struct cmd_ds_802_11_ad_hoc_result { + struct cmd_header hdr; + + u8 pad[3]; + u8 bssid[ETH_ALEN]; +}; + struct adhoc_bssdesc { - u8 bssid[6]; - u8 ssid[32]; + u8 bssid[ETH_ALEN]; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 type; __le16 beaconperiod; u8 dtimperiod; @@ -539,10 +542,15 @@ struct adhoc_bssdesc { } __attribute__ ((packed)); struct cmd_ds_802_11_ad_hoc_join { + struct cmd_header hdr; + struct adhoc_bssdesc bss; - __le16 failtimeout; - __le16 probedelay; + __le16 failtimeout; /* Reserved on v9 and later */ + __le16 probedelay; /* Reserved on v9 and later */ +} __attribute__ ((packed)); +struct cmd_ds_802_11_ad_hoc_stop { + struct cmd_header hdr; } __attribute__ ((packed)); struct cmd_ds_802_11_enable_rsn { @@ -597,14 +605,28 @@ struct cmd_ds_802_11_eeprom_access { } __attribute__ ((packed)); struct cmd_ds_802_11_tpc_cfg { + struct cmd_header hdr; + __le16 action; - u8 enable; - s8 P0; - s8 P1; - s8 P2; - u8 usesnr; + uint8_t enable; + int8_t P0; + int8_t P1; + int8_t P2; + uint8_t usesnr; } __attribute__ ((packed)); + +struct cmd_ds_802_11_pa_cfg { + struct cmd_header hdr; + + __le16 action; + uint8_t enable; + int8_t P0; + int8_t P1; + int8_t P2; +} __attribute__ ((packed)); + + struct cmd_ds_802_11_led_ctrl { __le16 action; __le16 numled; @@ -693,21 +715,13 @@ struct cmd_ds_command { union { struct cmd_ds_802_11_ps_mode psmode; struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_deauthenticate deauth; - struct cmd_ds_802_11_ad_hoc_start ads; - struct cmd_ds_802_11_reset reset; - struct cmd_ds_802_11_ad_hoc_result result; struct cmd_ds_802_11_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; - struct cmd_ds_802_11_snmp_mib smib; - struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; - struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; - struct cmd_ds_802_11_disassociate dassociate; struct cmd_ds_mac_reg_access macreg; struct cmd_ds_bbp_reg_access bbpreg; struct cmd_ds_rf_reg_access rfreg; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 8941919001b..842a08d1f10 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -713,7 +713,7 @@ static int if_cs_host_to_card(struct lbs_private *priv, ret = if_cs_send_cmd(priv, buf, nb); break; default: - lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type); + lbs_pr_err("%s: unsupported type %d\n", __func__, type); } lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); @@ -791,7 +791,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 || (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 || - (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0) + (ret = pcmcia_parse_tuple(&tuple, &parse)) != 0) { lbs_pr_err("error in pcmcia_get_first_tuple etc\n"); goto out1; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 632c291404a..cafbccb7414 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -39,7 +39,10 @@ MODULE_DEVICE_TABLE(usb, if_usb_table); static void if_usb_receive(struct urb *urb); static void if_usb_receive_fwload(struct urb *urb); -static int if_usb_prog_firmware(struct if_usb_card *cardp); +static int __if_usb_prog_firmware(struct if_usb_card *cardp, + const char *fwname, int cmd); +static int if_usb_prog_firmware(struct if_usb_card *cardp, + const char *fwname, int cmd); static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, uint8_t *payload, uint16_t nb); static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, @@ -48,6 +51,62 @@ static void if_usb_free(struct if_usb_card *cardp); static int if_usb_submit_rx_urb(struct if_usb_card *cardp); static int if_usb_reset_device(struct if_usb_card *cardp); +/* sysfs hooks */ + +/** + * Set function to write firmware to device's persistent memory + */ +static ssize_t if_usb_firmware_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct if_usb_card *cardp = priv->card; + char fwname[FIRMWARE_NAME_MAX]; + int ret; + + sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */ + ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_FW); + if (ret == 0) + return count; + + return ret; +} + +/** + * lbs_flash_fw attribute to be exported per ethX interface through sysfs + * (/sys/class/net/ethX/lbs_flash_fw). Use this like so to write firmware to + * the device's persistent memory: + * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_fw + */ +static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); + +/** + * Set function to write firmware to device's persistent memory + */ +static ssize_t if_usb_boot2_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct if_usb_card *cardp = priv->card; + char fwname[FIRMWARE_NAME_MAX]; + int ret; + + sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */ + ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_BOOT2); + if (ret == 0) + return count; + + return ret; +} + +/** + * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs + * (/sys/class/net/ethX/lbs_flash_boot2). Use this like so to write firmware + * to the device's persistent memory: + * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_boot2 + */ +static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set); + /** * @brief call back function to handle the status of the URB * @param urb pointer to urb structure @@ -66,10 +125,10 @@ static void if_usb_write_bulk_callback(struct urb *urb) lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n", urb->actual_length); - /* Used for both firmware TX and regular TX. priv isn't - * valid at firmware load time. + /* Boot commands such as UPDATE_FW and UPDATE_BOOT2 are not + * passed up to the lbs level. */ - if (priv) + if (priv && priv->dnld_sent != DNLD_BOOTCMD_SENT) lbs_host_to_card_done(priv); } else { /* print the failure status number for debug */ @@ -231,7 +290,7 @@ static int if_usb_probe(struct usb_interface *intf, } /* Upload firmware */ - if (if_usb_prog_firmware(cardp)) { + if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) { lbs_deb_usbd(&udev->dev, "FW upload failed\n"); goto err_prog_firmware; } @@ -260,6 +319,12 @@ static int if_usb_probe(struct usb_interface *intf, usb_get_dev(udev); usb_set_intfdata(intf, cardp); + if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw)) + lbs_pr_err("cannot register lbs_flash_fw attribute\n"); + + if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2)) + lbs_pr_err("cannot register lbs_flash_boot2 attribute\n"); + return 0; err_start_card: @@ -285,6 +350,9 @@ static void if_usb_disconnect(struct usb_interface *intf) lbs_deb_enter(LBS_DEB_MAIN); + device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2); + device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_fw); + cardp->surprise_removed = 1; if (priv) { @@ -371,11 +439,10 @@ static int if_usb_reset_device(struct if_usb_card *cardp) *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); cmd->command = cpu_to_le16(CMD_802_11_RESET); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); + cmd->size = cpu_to_le16(sizeof(struct cmd_header)); cmd->result = cpu_to_le16(0); cmd->seqnum = cpu_to_le16(0x5a5a); - cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT); - usb_tx_block(cardp, cardp->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset)); + usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header)); msleep(100); ret = usb_reset_device(cardp->udev); @@ -510,7 +577,7 @@ static void if_usb_receive_fwload(struct urb *urb) if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { kfree_skb(skb); if_usb_submit_rx_urb_fwload(cardp); - cardp->bootcmdresp = 1; + cardp->bootcmdresp = BOOT_CMD_RESP_OK; lbs_deb_usbd(&cardp->udev->dev, "Received valid boot command response\n"); return; @@ -526,7 +593,9 @@ static void if_usb_receive_fwload(struct urb *urb) lbs_pr_info("boot cmd response wrong magic number (0x%x)\n", le32_to_cpu(bootcmdresp.magic)); } - } else if (bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) { + } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) && + (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) && + (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) { lbs_pr_info("boot cmd response cmd_tag error (%d)\n", bootcmdresp.cmd); } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) { @@ -564,8 +633,8 @@ static void if_usb_receive_fwload(struct urb *urb) kfree_skb(skb); - /* reschedule timer for 200ms hence */ - mod_timer(&cardp->fw_timeout, jiffies + (HZ/5)); + /* Give device 5s to either write firmware to its RAM or eeprom */ + mod_timer(&cardp->fw_timeout, jiffies + (HZ*5)); if (cardp->fwfinalblk) { cardp->fwdnldover = 1; @@ -809,7 +878,54 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) } -static int if_usb_prog_firmware(struct if_usb_card *cardp) +/** +* @brief This function programs the firmware subject to cmd +* +* @param cardp the if_usb_card descriptor +* fwname firmware or boot2 image file name +* cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW, +* or BOOT_CMD_UPDATE_BOOT2. +* @return 0 or error code +*/ +static int if_usb_prog_firmware(struct if_usb_card *cardp, + const char *fwname, int cmd) +{ + struct lbs_private *priv = cardp->priv; + unsigned long flags, caps; + int ret; + + caps = priv->fwcapinfo; + if (((cmd == BOOT_CMD_UPDATE_FW) && !(caps & FW_CAPINFO_FIRMWARE_UPGRADE)) || + ((cmd == BOOT_CMD_UPDATE_BOOT2) && !(caps & FW_CAPINFO_BOOT2_UPGRADE))) + return -EOPNOTSUPP; + + /* Ensure main thread is idle. */ + spin_lock_irqsave(&priv->driver_lock, flags); + while (priv->cur_cmd != NULL || priv->dnld_sent != DNLD_RES_RECEIVED) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + if (wait_event_interruptible(priv->waitq, + (priv->cur_cmd == NULL && + priv->dnld_sent == DNLD_RES_RECEIVED))) { + return -ERESTARTSYS; + } + spin_lock_irqsave(&priv->driver_lock, flags); + } + priv->dnld_sent = DNLD_BOOTCMD_SENT; + spin_unlock_irqrestore(&priv->driver_lock, flags); + + ret = __if_usb_prog_firmware(cardp, fwname, cmd); + + spin_lock_irqsave(&priv->driver_lock, flags); + priv->dnld_sent = DNLD_RES_RECEIVED; + spin_unlock_irqrestore(&priv->driver_lock, flags); + + wake_up_interruptible(&priv->waitq); + + return ret; +} + +static int __if_usb_prog_firmware(struct if_usb_card *cardp, + const char *fwname, int cmd) { int i = 0; static int reset_count = 10; @@ -817,20 +933,32 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp) lbs_deb_enter(LBS_DEB_USB); - if ((ret = request_firmware(&cardp->fw, lbs_fw_name, - &cardp->udev->dev)) < 0) { + ret = request_firmware(&cardp->fw, fwname, &cardp->udev->dev); + if (ret < 0) { lbs_pr_err("request_firmware() failed with %#x\n", ret); - lbs_pr_err("firmware %s not found\n", lbs_fw_name); + lbs_pr_err("firmware %s not found\n", fwname); goto done; } - if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) + if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) { + ret = -EINVAL; goto release_fw; + } + + /* Cancel any pending usb business */ + usb_kill_urb(cardp->rx_urb); + usb_kill_urb(cardp->tx_urb); + + cardp->fwlastblksent = 0; + cardp->fwdnldover = 0; + cardp->totalbytes = 0; + cardp->fwfinalblk = 0; + cardp->bootcmdresp = 0; restart: if (if_usb_submit_rx_urb_fwload(cardp) < 0) { lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); - ret = -1; + ret = -EIO; goto release_fw; } @@ -838,8 +966,7 @@ restart: do { int j = 0; i++; - /* Issue Boot command = 1, Boot from Download-FW */ - if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); + if_usb_issue_boot_command(cardp, cmd); /* wait for command response */ do { j++; @@ -847,12 +974,21 @@ restart: } while (cardp->bootcmdresp == 0 && j < 10); } while (cardp->bootcmdresp == 0 && i < 5); - if (cardp->bootcmdresp <= 0) { + if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) { + /* Return to normal operation */ + ret = -EOPNOTSUPP; + usb_kill_urb(cardp->rx_urb); + usb_kill_urb(cardp->tx_urb); + if (if_usb_submit_rx_urb(cardp) < 0) + ret = -EIO; + goto release_fw; + } else if (cardp->bootcmdresp <= 0) { if (--reset_count >= 0) { if_usb_reset_device(cardp); goto restart; } - return -1; + ret = -EIO; + goto release_fw; } i = 0; @@ -882,7 +1018,7 @@ restart: } lbs_pr_info("FW download failure, time = %d ms\n", i * 100); - ret = -1; + ret = -EIO; goto release_fw; } diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index 5771a83a43f..5ba0aee0eb2 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -30,6 +30,7 @@ struct bootcmd #define BOOT_CMD_RESP_OK 0x0001 #define BOOT_CMD_RESP_FAIL 0x0000 +#define BOOT_CMD_RESP_NOT_SUPPORTED 0x0002 struct bootcmdresp { @@ -50,6 +51,10 @@ struct if_usb_card { uint8_t ep_in; uint8_t ep_out; + /* bootcmdresp == 0 means command is pending + * bootcmdresp < 0 means error + * bootcmdresp > 0 is a BOOT_CMD_RESP_* from firmware + */ int8_t bootcmdresp; int ep_in_size; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index bd32ac0b4e0..73dc8c72402 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -291,9 +291,11 @@ static ssize_t lbs_rtap_set(struct device *dev, if (priv->infra_open || priv->mesh_open) return -EBUSY; if (priv->mode == IW_MODE_INFRA) - lbs_send_deauthentication(priv); + lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) - lbs_stop_adhoc_network(priv); + lbs_adhoc_stop(priv); lbs_add_rtap(priv); } priv->monitormode = monitor_mode; @@ -956,17 +958,24 @@ EXPORT_SYMBOL_GPL(lbs_resume); static int lbs_setup_firmware(struct lbs_private *priv) { int ret = -1; + s16 curlevel = 0, minlevel = 0, maxlevel = 0; lbs_deb_enter(LBS_DEB_FW); - /* - * Read MAC address from HW - */ + /* Read MAC address from firmware */ memset(priv->current_addr, 0xff, ETH_ALEN); ret = lbs_update_hw_spec(priv); if (ret) goto done; + /* Read power levels if available */ + ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel); + if (ret == 0) { + priv->txpower_cur = curlevel; + priv->txpower_min = minlevel; + priv->txpower_max = maxlevel; + } + lbs_set_mac_control(priv); done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); @@ -1042,7 +1051,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->mode = IW_MODE_INFRA; priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; - priv->radioon = RADIO_ON; + priv->radio_on = 1; priv->enablehwauto = 1; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; @@ -1196,7 +1205,13 @@ void lbs_remove_card(struct lbs_private *priv) cancel_delayed_work_sync(&priv->scan_work); cancel_delayed_work_sync(&priv->assoc_work); cancel_work_sync(&priv->mcast_work); + + /* worker thread destruction blocks on the in-flight command which + * should have been cleared already in lbs_stop_card(). + */ + lbs_deb_main("destroying worker thread\n"); destroy_workqueue(priv->work_thread); + lbs_deb_main("done destroying worker thread\n"); if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { priv->psmode = LBS802_11POWERMODECAM; @@ -1314,14 +1329,26 @@ void lbs_stop_card(struct lbs_private *priv) device_remove_file(&dev->dev, &dev_attr_lbs_rtap); } - /* Flush pending command nodes */ + /* Delete the timeout of the currently processing command */ del_timer_sync(&priv->command_timer); + + /* Flush pending command nodes */ spin_lock_irqsave(&priv->driver_lock, flags); + lbs_deb_main("clearing pending commands\n"); list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { cmdnode->result = -ENOENT; cmdnode->cmdwaitqwoken = 1; wake_up_interruptible(&cmdnode->cmdwait_q); } + + /* Flush the command the card is currently processing */ + if (priv->cur_cmd) { + lbs_deb_main("clearing current command\n"); + priv->cur_cmd->result = -ENOENT; + priv->cur_cmd->cmdwaitqwoken = 1; + wake_up_interruptible(&priv->cur_cmd->cmdwait_q); + } + lbs_deb_main("done clearing commands\n"); spin_unlock_irqrestore(&priv->driver_lock, flags); unregister_netdev(dev); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 4b274562f96..8f66903641b 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -944,6 +944,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + if (!netif_running(dev)) { ret = -ENETDOWN; goto out; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 8b3ed77860b..82c3e5a50ea 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -30,6 +30,14 @@ static inline void lbs_postpone_association_work(struct lbs_private *priv) queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2); } +static inline void lbs_do_association_work(struct lbs_private *priv) +{ + if (priv->surpriseremoved) + return; + cancel_delayed_work(&priv->assoc_work); + queue_delayed_work(priv->work_thread, &priv->assoc_work, 0); +} + static inline void lbs_cancel_association_work(struct lbs_private *priv) { cancel_delayed_work(&priv->assoc_work); @@ -120,34 +128,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq( return cfp; } - -/** - * @brief Set Radio On/OFF - * - * @param priv A pointer to struct lbs_private structure - * @option Radio Option - * @return 0 --success, otherwise fail - */ -static int lbs_radio_ioctl(struct lbs_private *priv, u8 option) -{ - int ret = 0; - - lbs_deb_enter(LBS_DEB_WEXT); - - if (priv->radioon != option) { - lbs_deb_wext("switching radio %s\n", option ? "on" : "off"); - priv->radioon = option; - - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RADIO_CONTROL, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, 0, NULL); - } - - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; -} - /** * @brief Copy active data rates based on adapter mode and status * @@ -294,21 +274,17 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, { int ret = 0; struct lbs_private *priv = dev->priv; - u32 rthr = vwrq->value; + u32 val = vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); - if (vwrq->disabled) { - priv->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE; - } else { - if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE) - return -EINVAL; - priv->rtsthsd = rthr; - } + if (vwrq->disabled) + val = MRVDRV_RTS_MAX_VALUE; + + if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */ + return -EINVAL; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, - CMD_ACT_SET, CMD_OPTION_WAITFORRSP, - OID_802_11_RTS_THRESHOLD, &rthr); + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; @@ -317,21 +293,18 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; struct lbs_private *priv = dev->priv; + int ret = 0; + u16 val = 0; lbs_deb_enter(LBS_DEB_WEXT); - priv->rtsthsd = 0; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, - CMD_ACT_GET, CMD_OPTION_WAITFORRSP, - OID_802_11_RTS_THRESHOLD, NULL); + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val); if (ret) goto out; - vwrq->value = priv->rtsthsd; - vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE) - || (vwrq->value > MRVDRV_RTS_MAX_VALUE)); + vwrq->value = val; + vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */ vwrq->fixed = 1; out: @@ -342,24 +315,19 @@ out: static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; - u32 fthr = vwrq->value; struct lbs_private *priv = dev->priv; + int ret = 0; + u32 val = vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); - if (vwrq->disabled) { - priv->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE; - } else { - if (fthr < MRVDRV_FRAG_MIN_VALUE - || fthr > MRVDRV_FRAG_MAX_VALUE) - return -EINVAL; - priv->fragthsd = fthr; - } + if (vwrq->disabled) + val = MRVDRV_FRAG_MAX_VALUE; + + if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE) + return -EINVAL; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, - CMD_ACT_SET, CMD_OPTION_WAITFORRSP, - OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; @@ -368,22 +336,19 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; struct lbs_private *priv = dev->priv; + int ret = 0; + u16 val = 0; lbs_deb_enter(LBS_DEB_WEXT); - priv->fragthsd = 0; - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_SNMP_MIB, - CMD_ACT_GET, CMD_OPTION_WAITFORRSP, - OID_802_11_FRAGMENTATION_THRESHOLD, NULL); + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val); if (ret) goto out; - vwrq->value = priv->fragthsd; - vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE) - || (vwrq->value > MRVDRV_FRAG_MAX_VALUE)); + vwrq->value = val; + vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE) + || (val > MRVDRV_FRAG_MAX_VALUE)); vwrq->fixed = 1; out: @@ -410,7 +375,7 @@ static int mesh_wlan_get_mode(struct net_device *dev, { lbs_deb_enter(LBS_DEB_WEXT); - *uwrq = IW_MODE_REPEAT ; + *uwrq = IW_MODE_REPEAT; lbs_deb_leave(LBS_DEB_WEXT); return 0; @@ -420,28 +385,30 @@ static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; struct lbs_private *priv = dev->priv; + s16 curlevel = 0; + int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RF_TX_POWER, - CMD_ACT_TX_POWER_OPT_GET, - CMD_OPTION_WAITFORRSP, 0, NULL); + if (!priv->radio_on) { + lbs_deb_wext("tx power off\n"); + vwrq->value = 0; + vwrq->disabled = 1; + goto out; + } + ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL); if (ret) goto out; - lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel); - vwrq->value = priv->txpowerlevel; + lbs_deb_wext("tx power level %d dbm\n", curlevel); + priv->txpower_cur = curlevel; + + vwrq->value = curlevel; vwrq->fixed = 1; - if (priv->radioon) { - vwrq->disabled = 0; - vwrq->flags = IW_TXPOW_DBM; - } else { - vwrq->disabled = 1; - } + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -451,31 +418,44 @@ out: static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; struct lbs_private *priv = dev->priv; + int ret = 0; + u16 slimit = 0, llimit = 0; lbs_deb_enter(LBS_DEB_WEXT); - if (vwrq->flags == IW_RETRY_LIMIT) { - /* The MAC has a 4-bit Total_Tx_Count register - Total_Tx_Count = 1 + Tx_Retry_Count */ + if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) + return -EOPNOTSUPP; + + /* The MAC has a 4-bit Total_Tx_Count register + Total_Tx_Count = 1 + Tx_Retry_Count */ #define TX_RETRY_MIN 0 #define TX_RETRY_MAX 14 - if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) - return -EINVAL; + if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) + return -EINVAL; - /* Adding 1 to convert retry count to try count */ - priv->txretrycount = vwrq->value + 1; + /* Add 1 to convert retry count to try count */ + if (vwrq->flags & IW_RETRY_SHORT) + slimit = (u16) (vwrq->value + 1); + else if (vwrq->flags & IW_RETRY_LONG) + llimit = (u16) (vwrq->value + 1); + else + slimit = llimit = (u16) (vwrq->value + 1); /* set both */ - ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, - OID_802_11_TX_RETRYCOUNT, NULL); + if (llimit) { + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, + llimit); + if (ret) + goto out; + } + if (slimit) { + /* txretrycount follows the short retry limit */ + priv->txretrycount = slimit; + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, + slimit); if (ret) goto out; - } else { - return -EOPNOTSUPP; } out: @@ -488,22 +468,30 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, { struct lbs_private *priv = dev->priv; int ret = 0; + u16 val = 0; lbs_deb_enter(LBS_DEB_WEXT); - priv->txretrycount = 0; - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_SNMP_MIB, - CMD_ACT_GET, CMD_OPTION_WAITFORRSP, - OID_802_11_TX_RETRYCOUNT, NULL); - if (ret) - goto out; - vwrq->disabled = 0; - if (!vwrq->flags) { - vwrq->flags = IW_RETRY_LIMIT; + + if (vwrq->flags & IW_RETRY_LONG) { + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val); + if (ret) + goto out; + + /* Subtract 1 to convert try count to retry count */ + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + } else { + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val); + if (ret) + goto out; + + /* txretry count follows the short retry limit */ + priv->txretrycount = val; /* Subtract 1 to convert try count to retry count */ - vwrq->value = priv->txretrycount - 1; + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; } out: @@ -693,22 +681,12 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, range->sensitivity = 0; - /* - * Setup the supported power level ranges - */ + /* Setup the supported power level ranges */ memset(range->txpower, 0, sizeof(range->txpower)); - range->txpower[0] = 5; - range->txpower[1] = 7; - range->txpower[2] = 9; - range->txpower[3] = 11; - range->txpower[4] = 13; - range->txpower[5] = 15; - range->txpower[6] = 17; - range->txpower[7] = 19; - - range->num_txpower = 8; - range->txpower_capa = IW_TXPOW_DBM; - range->txpower_capa |= IW_TXPOW_RANGE; + range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; + range->txpower[0] = priv->txpower_min; + range->txpower[1] = priv->txpower_max; + range->num_txpower = 2; range->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | @@ -998,9 +976,11 @@ static int lbs_mesh_set_freq(struct net_device *dev, if (fwrq->m != priv->curbssparams.channel) { lbs_deb_wext("mesh channel change forces eth disconnect\n"); if (priv->mode == IW_MODE_INFRA) - lbs_send_deauthentication(priv); + lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) - lbs_stop_adhoc_network(priv); + lbs_adhoc_stop(priv); } lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); lbs_update_channel(priv); @@ -1045,6 +1025,18 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, new_rate); goto out; } + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_power_adapt_cfg(priv, 0, + POW_ADAPT_DEFAULT_P0, + POW_ADAPT_DEFAULT_P1, + POW_ADAPT_DEFAULT_P2); + if (ret) + goto out; + } + ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, + TPC_DEFAULT_P2, 1); + if (ret) + goto out; } /* Try the newer command first (Firmware Spec 5.1 and above) */ @@ -1612,12 +1604,26 @@ static int lbs_set_encodeext(struct net_device *dev, set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); } - disable_wep (assoc_req); + /* Only disable wep if necessary: can't waste time here. */ + if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE) + disable_wep(assoc_req); } out: if (ret == 0) { - lbs_postpone_association_work(priv); + /* 802.1x and WPA rekeying must happen as quickly as possible, + * especially during the 4-way handshake; thus if in + * infrastructure mode, and either (a) 802.1x is enabled or + * (b) WPA is being used, set the key right away. + */ + if (assoc_req->mode == IW_MODE_INFRA && + ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) || + (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) || + assoc_req->secinfo.WPAenabled || + assoc_req->secinfo.WPA2enabled)) { + lbs_do_association_work(priv); + } else + lbs_postpone_association_work(priv); } else { lbs_cancel_association_work(priv); } @@ -1725,13 +1731,17 @@ static int lbs_set_auth(struct net_device *dev, case IW_AUTH_TKIP_COUNTERMEASURES: case IW_AUTH_CIPHER_PAIRWISE: case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: case IW_AUTH_DROP_UNENCRYPTED: /* * libertas does not use these parameters */ break; + case IW_AUTH_KEY_MGMT: + assoc_req->secinfo.key_mgmt = dwrq->value; + updated = 1; + break; + case IW_AUTH_WPA_VERSION: if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { assoc_req->secinfo.WPAenabled = 0; @@ -1811,6 +1821,10 @@ static int lbs_get_auth(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_KEY_MGMT: + dwrq->value = priv->secinfo.key_mgmt; + break; + case IW_AUTH_WPA_VERSION: dwrq->value = 0; if (priv->secinfo.WPAenabled) @@ -1844,39 +1858,77 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, { int ret = 0; struct lbs_private *priv = dev->priv; - - u16 dbm; + s16 dbm = (s16) vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); if (vwrq->disabled) { - lbs_radio_ioctl(priv, RADIO_OFF); - return 0; + lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); + goto out; } - priv->preamble = CMD_TYPE_AUTO_PREAMBLE; - - lbs_radio_ioctl(priv, RADIO_ON); + if (vwrq->fixed == 0) { + /* User requests automatic tx power control, however there are + * many auto tx settings. For now use firmware defaults until + * we come up with a good way to expose these to the user. */ + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_power_adapt_cfg(priv, 1, + POW_ADAPT_DEFAULT_P0, + POW_ADAPT_DEFAULT_P1, + POW_ADAPT_DEFAULT_P2); + if (ret) + goto out; + } + ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, + TPC_DEFAULT_P2, 1); + if (ret) + goto out; + dbm = priv->txpower_max; + } else { + /* Userspace check in iwrange if it should use dBm or mW, + * therefore this should never happen... Jean II */ + if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { + ret = -EOPNOTSUPP; + goto out; + } - /* Userspace check in iwrange if it should use dBm or mW, - * therefore this should never happen... Jean II */ - if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { - return -EOPNOTSUPP; - } else - dbm = (u16) vwrq->value; + /* Validate requested power level against firmware allowed + * levels */ + if (priv->txpower_min && (dbm < priv->txpower_min)) { + ret = -EINVAL; + goto out; + } - /* auto tx power control */ + if (priv->txpower_max && (dbm > priv->txpower_max)) { + ret = -EINVAL; + goto out; + } + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_power_adapt_cfg(priv, 0, + POW_ADAPT_DEFAULT_P0, + POW_ADAPT_DEFAULT_P1, + POW_ADAPT_DEFAULT_P2); + if (ret) + goto out; + } + ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, + TPC_DEFAULT_P2, 1); + if (ret) + goto out; + } - if (vwrq->fixed == 0) - dbm = 0xffff; + /* If the radio was off, turn it on */ + if (!priv->radio_on) { + ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1); + if (ret) + goto out; + } - lbs_deb_wext("txpower set %d dbm\n", dbm); + lbs_deb_wext("txpower set %d dBm\n", dbm); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RF_TX_POWER, - CMD_ACT_TX_POWER_OPT_SET_LOW, - CMD_OPTION_WAITFORRSP, 0, (void *)&dbm); + ret = lbs_set_tx_power(priv, dbm); +out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } @@ -1928,6 +1980,11 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + /* Check the size of the string */ if (in_ssid_len > IW_ESSID_MAX_SIZE) { ret = -E2BIG; @@ -2005,6 +2062,11 @@ static int lbs_mesh_set_essid(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + /* Check the size of the string */ if (dwrq->length > IW_ESSID_MAX_SIZE) { ret = -E2BIG; @@ -2046,6 +2108,9 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) + return -EINVAL; + if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; diff --git a/drivers/net/wireless/libertas_tf/Makefile b/drivers/net/wireless/libertas_tf/Makefile new file mode 100644 index 00000000000..ff5544d6ac9 --- /dev/null +++ b/drivers/net/wireless/libertas_tf/Makefile @@ -0,0 +1,6 @@ +libertas_tf-objs := main.o cmd.o + +libertas_tf_usb-objs += if_usb.o + +obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf.o +obj-$(CONFIG_LIBERTAS_THINFIRM_USB) += libertas_tf_usb.o diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c new file mode 100644 index 00000000000..fdbcf8ba3e8 --- /dev/null +++ b/drivers/net/wireless/libertas_tf/cmd.c @@ -0,0 +1,669 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * 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. + */ +#include "libertas_tf.h" + +static const struct channel_range channel_ranges[] = { + { LBTF_REGDOMAIN_US, 1, 12 }, + { LBTF_REGDOMAIN_CA, 1, 12 }, + { LBTF_REGDOMAIN_EU, 1, 14 }, + { LBTF_REGDOMAIN_JP, 1, 14 }, + { LBTF_REGDOMAIN_SP, 1, 14 }, + { LBTF_REGDOMAIN_FR, 1, 14 }, +}; + +static u16 lbtf_region_code_to_index[MRVDRV_MAX_REGION_CODE] = +{ + LBTF_REGDOMAIN_US, LBTF_REGDOMAIN_CA, LBTF_REGDOMAIN_EU, + LBTF_REGDOMAIN_SP, LBTF_REGDOMAIN_FR, LBTF_REGDOMAIN_JP, +}; + +static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv); + + +/** + * lbtf_cmd_copyback - Simple callback that copies response back into command + * + * @priv A pointer to struct lbtf_private structure + * @extra A pointer to the original command structure for which + * 'resp' is a response + * @resp A pointer to the command response + * + * Returns: 0 on success, error on failure + */ +int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra, + struct cmd_header *resp) +{ + struct cmd_header *buf = (void *)extra; + uint16_t copy_len; + + copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size)); + memcpy(buf, resp, copy_len); + return 0; +} +EXPORT_SYMBOL_GPL(lbtf_cmd_copyback); + +#define CHAN_TO_IDX(chan) ((chan) - 1) + +static void lbtf_geo_init(struct lbtf_private *priv) +{ + const struct channel_range *range = channel_ranges; + u8 ch; + int i; + + for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) + if (channel_ranges[i].regdomain == priv->regioncode) { + range = &channel_ranges[i]; + break; + } + + for (ch = priv->range.start; ch < priv->range.end; ch++) + priv->channels[CHAN_TO_IDX(ch)].flags = 0; +} + +/** + * lbtf_update_hw_spec: Updates the hardware details. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 on success, error on failure + */ +int lbtf_update_hw_spec(struct lbtf_private *priv) +{ + struct cmd_ds_get_hw_spec cmd; + int ret = -1; + u32 i; + DECLARE_MAC_BUF(mac); + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN); + ret = lbtf_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd); + if (ret) + goto out; + + priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo); + + /* The firmware release is in an interesting format: the patch + * level is in the most significant nibble ... so fix that: */ + priv->fwrelease = le32_to_cpu(cmd.fwrelease); + priv->fwrelease = (priv->fwrelease << 8) | + (priv->fwrelease >> 24 & 0xff); + + printk(KERN_INFO "libertastf: %s, fw %u.%u.%up%u, cap 0x%08x\n", + print_mac(mac, cmd.permanentaddr), + priv->fwrelease >> 24 & 0xff, + priv->fwrelease >> 16 & 0xff, + priv->fwrelease >> 8 & 0xff, + priv->fwrelease & 0xff, + priv->fwcapinfo); + + /* Clamp region code to 8-bit since FW spec indicates that it should + * only ever be 8-bit, even though the field size is 16-bit. Some + * firmware returns non-zero high 8 bits here. + */ + priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF; + + for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { + /* use the region code to search for the index */ + if (priv->regioncode == lbtf_region_code_to_index[i]) + break; + } + + /* if it's unidentified region code, use the default (USA) */ + if (i >= MRVDRV_MAX_REGION_CODE) + priv->regioncode = 0x10; + + if (priv->current_addr[0] == 0xff) + memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN); + + SET_IEEE80211_PERM_ADDR(priv->hw, priv->current_addr); + + lbtf_geo_init(priv); +out: + return ret; +} + +/** + * lbtf_set_channel: Set the radio channel + * + * @priv A pointer to struct lbtf_private structure + * @channel The desired channel, or 0 to clear a locked channel + * + * Returns: 0 on success, error on failure + */ +int lbtf_set_channel(struct lbtf_private *priv, u8 channel) +{ + struct cmd_ds_802_11_rf_channel cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET); + cmd.channel = cpu_to_le16(channel); + + return lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd); +} + +int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon) +{ + struct cmd_ds_802_11_beacon_set cmd; + int size; + + if (beacon->len > MRVL_MAX_BCN_SIZE) + return -1; + size = sizeof(cmd) - sizeof(cmd.beacon) + beacon->len; + cmd.hdr.size = cpu_to_le16(size); + cmd.len = cpu_to_le16(beacon->len); + memcpy(cmd.beacon, (u8 *) beacon->data, beacon->len); + + lbtf_cmd_async(priv, CMD_802_11_BEACON_SET, &cmd.hdr, size); + return 0; +} + +int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable, + int beacon_int) { + struct cmd_ds_802_11_beacon_control cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.beacon_enable = cpu_to_le16(beacon_enable); + cmd.beacon_period = cpu_to_le16(beacon_int); + + lbtf_cmd_async(priv, CMD_802_11_BEACON_CTRL, &cmd.hdr, sizeof(cmd)); + return 0; +} + +static void lbtf_queue_cmd(struct lbtf_private *priv, + struct cmd_ctrl_node *cmdnode) +{ + unsigned long flags; + + if (!cmdnode) + return; + + if (!cmdnode->cmdbuf->size) + return; + + cmdnode->result = 0; + spin_lock_irqsave(&priv->driver_lock, flags); + list_add_tail(&cmdnode->list, &priv->cmdpendingq); + spin_unlock_irqrestore(&priv->driver_lock, flags); +} + +static void lbtf_submit_command(struct lbtf_private *priv, + struct cmd_ctrl_node *cmdnode) +{ + unsigned long flags; + struct cmd_header *cmd; + uint16_t cmdsize; + uint16_t command; + int timeo = 5 * HZ; + int ret; + + cmd = cmdnode->cmdbuf; + + spin_lock_irqsave(&priv->driver_lock, flags); + priv->cur_cmd = cmdnode; + cmdsize = le16_to_cpu(cmd->size); + command = le16_to_cpu(cmd->command); + ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize); + spin_unlock_irqrestore(&priv->driver_lock, flags); + + if (ret) + /* Let the timer kick in and retry, and potentially reset + the whole thing if the condition persists */ + timeo = HZ; + + /* Setup the timer after transmit command */ + mod_timer(&priv->command_timer, jiffies + timeo); +} + +/** + * This function inserts command node to cmdfreeq + * after cleans it. Requires priv->driver_lock held. + */ +static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv, + struct cmd_ctrl_node *cmdnode) +{ + if (!cmdnode) + return; + + cmdnode->callback = NULL; + cmdnode->callback_arg = 0; + + memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE); + + list_add_tail(&cmdnode->list, &priv->cmdfreeq); +} + +static void lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv, + struct cmd_ctrl_node *ptempcmd) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->driver_lock, flags); + __lbtf_cleanup_and_insert_cmd(priv, ptempcmd); + spin_unlock_irqrestore(&priv->driver_lock, flags); +} + +void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd, + int result) +{ + cmd->result = result; + cmd->cmdwaitqwoken = 1; + wake_up_interruptible(&cmd->cmdwait_q); + + if (!cmd->callback) + __lbtf_cleanup_and_insert_cmd(priv, cmd); + priv->cur_cmd = NULL; +} + +int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv) +{ + struct cmd_ds_mac_multicast_addr cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + + cmd.nr_of_adrs = cpu_to_le16((u16) priv->nr_of_multicastmacaddr); + memcpy(cmd.maclist, priv->multicastlist, + priv->nr_of_multicastmacaddr * ETH_ALEN); + + lbtf_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &cmd.hdr, sizeof(cmd)); + return 0; +} + +void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode) +{ + struct cmd_ds_set_mode cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.mode = cpu_to_le16(mode); + lbtf_cmd_async(priv, CMD_802_11_SET_MODE, &cmd.hdr, sizeof(cmd)); +} + +void lbtf_set_bssid(struct lbtf_private *priv, bool activate, u8 *bssid) +{ + struct cmd_ds_set_bssid cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.activate = activate ? 1 : 0; + if (activate) + memcpy(cmd.bssid, bssid, ETH_ALEN); + + lbtf_cmd_async(priv, CMD_802_11_SET_BSSID, &cmd.hdr, sizeof(cmd)); +} + +int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr) +{ + struct cmd_ds_802_11_mac_address cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + + memcpy(cmd.macadd, mac_addr, ETH_ALEN); + + lbtf_cmd_async(priv, CMD_802_11_MAC_ADDRESS, &cmd.hdr, sizeof(cmd)); + return 0; +} + +int lbtf_set_radio_control(struct lbtf_private *priv) +{ + int ret = 0; + struct cmd_ds_802_11_radio_control cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + + switch (priv->preamble) { + case CMD_TYPE_SHORT_PREAMBLE: + cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE); + break; + + case CMD_TYPE_LONG_PREAMBLE: + cmd.control = cpu_to_le16(SET_LONG_PREAMBLE); + break; + + case CMD_TYPE_AUTO_PREAMBLE: + default: + cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE); + break; + } + + if (priv->radioon) + cmd.control |= cpu_to_le16(TURN_ON_RF); + else + cmd.control &= cpu_to_le16(~TURN_ON_RF); + + ret = lbtf_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); + return ret; +} + +void lbtf_set_mac_control(struct lbtf_private *priv) +{ + struct cmd_ds_mac_control cmd; + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(priv->mac_control); + cmd.reserved = 0; + + lbtf_cmd_async(priv, CMD_MAC_CONTROL, + &cmd.hdr, sizeof(cmd)); +} + +/** + * lbtf_allocate_cmd_buffer - Allocates cmd buffer, links it to free cmd queue + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 on success. + */ +int lbtf_allocate_cmd_buffer(struct lbtf_private *priv) +{ + u32 bufsize; + u32 i; + struct cmd_ctrl_node *cmdarray; + + /* Allocate and initialize the command array */ + bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS; + cmdarray = kzalloc(bufsize, GFP_KERNEL); + if (!cmdarray) + return -1; + priv->cmd_array = cmdarray; + + /* Allocate and initialize each command buffer in the command array */ + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL); + if (!cmdarray[i].cmdbuf) + return -1; + } + + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + init_waitqueue_head(&cmdarray[i].cmdwait_q); + lbtf_cleanup_and_insert_cmd(priv, &cmdarray[i]); + } + return 0; +} + +/** + * lbtf_free_cmd_buffer - Frees the cmd buffer. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 + */ +int lbtf_free_cmd_buffer(struct lbtf_private *priv) +{ + struct cmd_ctrl_node *cmdarray; + unsigned int i; + + /* need to check if cmd array is allocated or not */ + if (priv->cmd_array == NULL) + return 0; + + cmdarray = priv->cmd_array; + + /* Release shared memory buffers */ + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + kfree(cmdarray[i].cmdbuf); + cmdarray[i].cmdbuf = NULL; + } + + /* Release cmd_ctrl_node */ + kfree(priv->cmd_array); + priv->cmd_array = NULL; + + return 0; +} + +/** + * lbtf_get_cmd_ctrl_node - Gets free cmd node from free cmd queue. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: pointer to a struct cmd_ctrl_node or NULL if none available. + */ +static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv) +{ + struct cmd_ctrl_node *tempnode; + unsigned long flags; + + if (!priv) + return NULL; + + spin_lock_irqsave(&priv->driver_lock, flags); + + if (!list_empty(&priv->cmdfreeq)) { + tempnode = list_first_entry(&priv->cmdfreeq, + struct cmd_ctrl_node, list); + list_del(&tempnode->list); + } else + tempnode = NULL; + + spin_unlock_irqrestore(&priv->driver_lock, flags); + + return tempnode; +} + +/** + * lbtf_execute_next_command: execute next command in cmd pending queue. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 on success. + */ +int lbtf_execute_next_command(struct lbtf_private *priv) +{ + struct cmd_ctrl_node *cmdnode = NULL; + struct cmd_header *cmd; + unsigned long flags; + + /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the + * only caller to us is lbtf_thread() and we get even when a + * data packet is received */ + + spin_lock_irqsave(&priv->driver_lock, flags); + + if (priv->cur_cmd) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + return -1; + } + + if (!list_empty(&priv->cmdpendingq)) { + cmdnode = list_first_entry(&priv->cmdpendingq, + struct cmd_ctrl_node, list); + } + + if (cmdnode) { + cmd = cmdnode->cmdbuf; + + list_del(&cmdnode->list); + spin_unlock_irqrestore(&priv->driver_lock, flags); + lbtf_submit_command(priv, cmdnode); + } else + spin_unlock_irqrestore(&priv->driver_lock, flags); + return 0; +} + +static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv, + uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbtf_private *, unsigned long, + struct cmd_header *), + unsigned long callback_arg) +{ + struct cmd_ctrl_node *cmdnode; + + if (priv->surpriseremoved) + return ERR_PTR(-ENOENT); + + cmdnode = lbtf_get_cmd_ctrl_node(priv); + if (cmdnode == NULL) { + /* Wake up main thread to execute next command */ + queue_work(lbtf_wq, &priv->cmd_work); + return ERR_PTR(-ENOBUFS); + } + + cmdnode->callback = callback; + cmdnode->callback_arg = callback_arg; + + /* Copy the incoming command to the buffer */ + memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size); + + /* Set sequence number, clean result, move to buffer */ + priv->seqnum++; + cmdnode->cmdbuf->command = cpu_to_le16(command); + cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size); + cmdnode->cmdbuf->seqnum = cpu_to_le16(priv->seqnum); + cmdnode->cmdbuf->result = 0; + cmdnode->cmdwaitqwoken = 0; + lbtf_queue_cmd(priv, cmdnode); + queue_work(lbtf_wq, &priv->cmd_work); + + return cmdnode; +} + +void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size) +{ + __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, NULL, 0); +} + +int __lbtf_cmd(struct lbtf_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbtf_private *, + unsigned long, struct cmd_header *), + unsigned long callback_arg) +{ + struct cmd_ctrl_node *cmdnode; + unsigned long flags; + int ret = 0; + + cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, + callback, callback_arg); + if (IS_ERR(cmdnode)) + return PTR_ERR(cmdnode); + + might_sleep(); + ret = wait_event_interruptible(cmdnode->cmdwait_q, + cmdnode->cmdwaitqwoken); + if (ret) { + printk(KERN_DEBUG + "libertastf: command 0x%04x interrupted by signal", + command); + return ret; + } + + spin_lock_irqsave(&priv->driver_lock, flags); + ret = cmdnode->result; + if (ret) + printk(KERN_DEBUG "libertastf: command 0x%04x failed: %d\n", + command, ret); + + __lbtf_cleanup_and_insert_cmd(priv, cmdnode); + spin_unlock_irqrestore(&priv->driver_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(__lbtf_cmd); + +/* Call holding driver_lock */ +void lbtf_cmd_response_rx(struct lbtf_private *priv) +{ + priv->cmd_response_rxed = 1; + queue_work(lbtf_wq, &priv->cmd_work); +} +EXPORT_SYMBOL_GPL(lbtf_cmd_response_rx); + +int lbtf_process_rx_command(struct lbtf_private *priv) +{ + uint16_t respcmd, curcmd; + struct cmd_header *resp; + int ret = 0; + unsigned long flags; + uint16_t result; + + mutex_lock(&priv->lock); + spin_lock_irqsave(&priv->driver_lock, flags); + + if (!priv->cur_cmd) { + ret = -1; + spin_unlock_irqrestore(&priv->driver_lock, flags); + goto done; + } + + resp = (void *)priv->cmd_resp_buff; + curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command); + respcmd = le16_to_cpu(resp->command); + result = le16_to_cpu(resp->result); + + if (net_ratelimit()) + printk(KERN_DEBUG "libertastf: cmd response 0x%04x, seq %d, size %d\n", + respcmd, le16_to_cpu(resp->seqnum), + le16_to_cpu(resp->size)); + + if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + ret = -1; + goto done; + } + if (respcmd != CMD_RET(curcmd)) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + ret = -1; + goto done; + } + + if (resp->result == cpu_to_le16(0x0004)) { + /* 0x0004 means -EAGAIN. Drop the response, let it time out + and be resubmitted */ + spin_unlock_irqrestore(&priv->driver_lock, flags); + ret = -1; + goto done; + } + + /* Now we got response from FW, cancel the command timer */ + del_timer(&priv->command_timer); + priv->cmd_timed_out = 0; + if (priv->nr_retries) + priv->nr_retries = 0; + + /* If the command is not successful, cleanup and return failure */ + if ((result != 0 || !(respcmd & 0x8000))) { + /* + * Handling errors here + */ + switch (respcmd) { + case CMD_RET(CMD_GET_HW_SPEC): + case CMD_RET(CMD_802_11_RESET): + printk(KERN_DEBUG "libertastf: reset failed\n"); + break; + + } + lbtf_complete_command(priv, priv->cur_cmd, result); + spin_unlock_irqrestore(&priv->driver_lock, flags); + + ret = -1; + goto done; + } + + spin_unlock_irqrestore(&priv->driver_lock, flags); + + if (priv->cur_cmd && priv->cur_cmd->callback) { + ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg, + resp); + } + spin_lock_irqsave(&priv->driver_lock, flags); + + if (priv->cur_cmd) { + /* Clean up and Put current command back to cmdfreeq */ + lbtf_complete_command(priv, priv->cur_cmd, result); + } + spin_unlock_irqrestore(&priv->driver_lock, flags); + +done: + mutex_unlock(&priv->lock); + return ret; +} diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c new file mode 100644 index 00000000000..1cc03a8dd67 --- /dev/null +++ b/drivers/net/wireless/libertas_tf/if_usb.c @@ -0,0 +1,766 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * 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. + */ +#include <linux/delay.h> +#include <linux/moduleparam.h> +#include <linux/firmware.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#define DRV_NAME "lbtf_usb" + +#include "libertas_tf.h" +#include "if_usb.h" + +#define MESSAGE_HEADER_LEN 4 + +static char *lbtf_fw_name = "lbtf_usb.bin"; +module_param_named(fw_name, lbtf_fw_name, charp, 0644); + +static struct usb_device_id if_usb_table[] = { + /* Enter the device signature inside */ + { USB_DEVICE(0x1286, 0x2001) }, + { USB_DEVICE(0x05a3, 0x8388) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, if_usb_table); + +static void if_usb_receive(struct urb *urb); +static void if_usb_receive_fwload(struct urb *urb); +static int if_usb_prog_firmware(struct if_usb_card *cardp); +static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type, + uint8_t *payload, uint16_t nb); +static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, + uint16_t nb, u8 data); +static void if_usb_free(struct if_usb_card *cardp); +static int if_usb_submit_rx_urb(struct if_usb_card *cardp); +static int if_usb_reset_device(struct if_usb_card *cardp); + +/** + * if_usb_wrike_bulk_callback - call back to handle URB status + * + * @param urb pointer to urb structure + */ +static void if_usb_write_bulk_callback(struct urb *urb) +{ + if (urb->status != 0) + printk(KERN_INFO "libertastf: URB in failure status: %d\n", + urb->status); +} + +/** + * if_usb_free - free tx/rx urb, skb and rx buffer + * + * @param cardp pointer if_usb_card + */ +static void if_usb_free(struct if_usb_card *cardp) +{ + /* Unlink tx & rx urb */ + usb_kill_urb(cardp->tx_urb); + usb_kill_urb(cardp->rx_urb); + usb_kill_urb(cardp->cmd_urb); + + usb_free_urb(cardp->tx_urb); + cardp->tx_urb = NULL; + + usb_free_urb(cardp->rx_urb); + cardp->rx_urb = NULL; + + usb_free_urb(cardp->cmd_urb); + cardp->cmd_urb = NULL; + + kfree(cardp->ep_out_buf); + cardp->ep_out_buf = NULL; +} + +static void if_usb_setup_firmware(struct lbtf_private *priv) +{ + struct if_usb_card *cardp = priv->card; + struct cmd_ds_set_boot2_ver b2_cmd; + + if_usb_submit_rx_urb(cardp); + b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd)); + b2_cmd.action = 0; + b2_cmd.version = cardp->boot2_version; + + if (lbtf_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd)) + printk(KERN_INFO "libertastf: setting boot2 version failed\n"); +} + +static void if_usb_fw_timeo(unsigned long priv) +{ + struct if_usb_card *cardp = (void *)priv; + + if (!cardp->fwdnldover) + /* Download timed out */ + cardp->priv->surpriseremoved = 1; + wake_up(&cardp->fw_wq); +} + +/** + * if_usb_probe - sets the configuration values + * + * @ifnum interface number + * @id pointer to usb_device_id + * + * Returns: 0 on success, error code on failure + */ +static int if_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct lbtf_private *priv; + struct if_usb_card *cardp; + int i; + + udev = interface_to_usbdev(intf); + + cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL); + if (!cardp) + goto error; + + setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp); + init_waitqueue_head(&cardp->fw_wq); + + cardp->udev = udev; + iface_desc = intf->cur_altsetting; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if (usb_endpoint_is_bulk_in(endpoint)) { + cardp->ep_in_size = + le16_to_cpu(endpoint->wMaxPacketSize); + cardp->ep_in = usb_endpoint_num(endpoint); + } else if (usb_endpoint_is_bulk_out(endpoint)) { + cardp->ep_out_size = + le16_to_cpu(endpoint->wMaxPacketSize); + cardp->ep_out = usb_endpoint_num(endpoint); + } + } + if (!cardp->ep_out_size || !cardp->ep_in_size) + /* Endpoints not found */ + goto dealloc; + + cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!cardp->rx_urb) + goto dealloc; + + cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!cardp->tx_urb) + goto dealloc; + + cardp->cmd_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!cardp->cmd_urb) + goto dealloc; + + cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, + GFP_KERNEL); + if (!cardp->ep_out_buf) + goto dealloc; + + priv = lbtf_add_card(cardp, &udev->dev); + if (!priv) + goto dealloc; + + cardp->priv = priv; + + priv->hw_host_to_card = if_usb_host_to_card; + priv->hw_prog_firmware = if_usb_prog_firmware; + priv->hw_reset_device = if_usb_reset_device; + cardp->boot2_version = udev->descriptor.bcdDevice; + + usb_get_dev(udev); + usb_set_intfdata(intf, cardp); + + return 0; + +dealloc: + if_usb_free(cardp); +error: + return -ENOMEM; +} + +/** + * if_usb_disconnect - free resource and cleanup + * + * @intf USB interface structure + */ +static void if_usb_disconnect(struct usb_interface *intf) +{ + struct if_usb_card *cardp = usb_get_intfdata(intf); + struct lbtf_private *priv = (struct lbtf_private *) cardp->priv; + + if_usb_reset_device(cardp); + + if (priv) + lbtf_remove_card(priv); + + /* Unlink and free urb */ + if_usb_free(cardp); + + usb_set_intfdata(intf, NULL); + usb_put_dev(interface_to_usbdev(intf)); +} + +/** + * if_usb_send_fw_pkt - This function downloads the FW + * + * @priv pointer to struct lbtf_private + * + * Returns: 0 + */ +static int if_usb_send_fw_pkt(struct if_usb_card *cardp) +{ + struct fwdata *fwdata = cardp->ep_out_buf; + u8 *firmware = (u8 *) cardp->fw->data; + + /* If we got a CRC failure on the last block, back + up and retry it */ + if (!cardp->CRC_OK) { + cardp->totalbytes = cardp->fwlastblksent; + cardp->fwseqnum--; + } + + /* struct fwdata (which we sent to the card) has an + extra __le32 field in between the header and the data, + which is not in the struct fwheader in the actual + firmware binary. Insert the seqnum in the middle... */ + memcpy(&fwdata->hdr, &firmware[cardp->totalbytes], + sizeof(struct fwheader)); + + cardp->fwlastblksent = cardp->totalbytes; + cardp->totalbytes += sizeof(struct fwheader); + + memcpy(fwdata->data, &firmware[cardp->totalbytes], + le32_to_cpu(fwdata->hdr.datalength)); + + fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum); + cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength); + + usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) + + le32_to_cpu(fwdata->hdr.datalength), 0); + + if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) + /* Host has finished FW downloading + * Donwloading FW JUMP BLOCK + */ + cardp->fwfinalblk = 1; + + return 0; +} + +static int if_usb_reset_device(struct if_usb_card *cardp) +{ + struct cmd_ds_802_11_reset *cmd = cardp->ep_out_buf + 4; + int ret; + + *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); + + cmd->hdr.command = cpu_to_le16(CMD_802_11_RESET); + cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset)); + cmd->hdr.result = cpu_to_le16(0); + cmd->hdr.seqnum = cpu_to_le16(0x5a5a); + cmd->action = cpu_to_le16(CMD_ACT_HALT); + usb_tx_block(cardp, cardp->ep_out_buf, + 4 + sizeof(struct cmd_ds_802_11_reset), 0); + + msleep(100); + ret = usb_reset_device(cardp->udev); + msleep(100); + + return ret; +} +EXPORT_SYMBOL_GPL(if_usb_reset_device); + +/** + * usb_tx_block - transfer data to the device + * + * @priv pointer to struct lbtf_private + * @payload pointer to payload data + * @nb data length + * @data non-zero for data, zero for commands + * + * Returns: 0 on success, nonzero otherwise. + */ +static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, + uint16_t nb, u8 data) +{ + struct urb *urb; + + /* check if device is removed */ + if (cardp->priv->surpriseremoved) + return -1; + + if (data) + urb = cardp->tx_urb; + else + urb = cardp->cmd_urb; + + usb_fill_bulk_urb(urb, cardp->udev, + usb_sndbulkpipe(cardp->udev, + cardp->ep_out), + payload, nb, if_usb_write_bulk_callback, cardp); + + urb->transfer_flags |= URB_ZERO_PACKET; + + if (usb_submit_urb(urb, GFP_ATOMIC)) + return -1; + return 0; +} + +static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, + void (*callbackfn)(struct urb *urb)) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); + if (!skb) + return -1; + + cardp->rx_skb = skb; + + /* Fill the receive configuration URB and initialise the Rx call back */ + usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, + usb_rcvbulkpipe(cardp->udev, cardp->ep_in), + (void *) (skb->tail), + MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp); + + cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; + + if (usb_submit_urb(cardp->rx_urb, GFP_ATOMIC)) { + kfree_skb(skb); + cardp->rx_skb = NULL; + return -1; + } else + return 0; +} + +static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp) +{ + return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload); +} + +static int if_usb_submit_rx_urb(struct if_usb_card *cardp) +{ + return __if_usb_submit_rx_urb(cardp, &if_usb_receive); +} + +static void if_usb_receive_fwload(struct urb *urb) +{ + struct if_usb_card *cardp = urb->context; + struct sk_buff *skb = cardp->rx_skb; + struct fwsyncheader *syncfwheader; + struct bootcmdresp bcmdresp; + + if (urb->status) { + kfree_skb(skb); + return; + } + + if (cardp->fwdnldover) { + __le32 *tmp = (__le32 *)(skb->data); + + if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) && + tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) + /* Firmware ready event received */ + wake_up(&cardp->fw_wq); + else + if_usb_submit_rx_urb_fwload(cardp); + kfree_skb(skb); + return; + } + if (cardp->bootcmdresp <= 0) { + memcpy(&bcmdresp, skb->data, sizeof(bcmdresp)); + + if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { + kfree_skb(skb); + if_usb_submit_rx_urb_fwload(cardp); + cardp->bootcmdresp = 1; + /* Received valid boot command response */ + return; + } + if (bcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) { + if (bcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) || + bcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) || + bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) + cardp->bootcmdresp = -1; + } else if (bcmdresp.cmd == BOOT_CMD_FW_BY_USB && + bcmdresp.result == BOOT_CMD_RESP_OK) + cardp->bootcmdresp = 1; + + kfree_skb(skb); + if_usb_submit_rx_urb_fwload(cardp); + return; + } + + syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC); + if (!syncfwheader) { + kfree_skb(skb); + return; + } + + memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader)); + + if (!syncfwheader->cmd) + cardp->CRC_OK = 1; + else + cardp->CRC_OK = 0; + kfree_skb(skb); + + /* reschedule timer for 200ms hence */ + mod_timer(&cardp->fw_timeout, jiffies + (HZ/5)); + + if (cardp->fwfinalblk) { + cardp->fwdnldover = 1; + goto exit; + } + + if_usb_send_fw_pkt(cardp); + + exit: + if_usb_submit_rx_urb_fwload(cardp); + + kfree(syncfwheader); + + return; +} + +#define MRVDRV_MIN_PKT_LEN 30 + +static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, + struct if_usb_card *cardp, + struct lbtf_private *priv) +{ + if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN + || recvlength < MRVDRV_MIN_PKT_LEN) { + kfree_skb(skb); + return; + } + + skb_put(skb, recvlength); + skb_pull(skb, MESSAGE_HEADER_LEN); + lbtf_rx(priv, skb); +} + +static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, + struct sk_buff *skb, + struct if_usb_card *cardp, + struct lbtf_private *priv) +{ + if (recvlength > LBS_CMD_BUFFER_SIZE) { + kfree_skb(skb); + return; + } + + if (!in_interrupt()) + BUG(); + + spin_lock(&priv->driver_lock); + memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN, + recvlength - MESSAGE_HEADER_LEN); + kfree_skb(skb); + lbtf_cmd_response_rx(priv); + spin_unlock(&priv->driver_lock); +} + +/** + * if_usb_receive - read data received from the device. + * + * @urb pointer to struct urb + */ +static void if_usb_receive(struct urb *urb) +{ + struct if_usb_card *cardp = urb->context; + struct sk_buff *skb = cardp->rx_skb; + struct lbtf_private *priv = cardp->priv; + int recvlength = urb->actual_length; + uint8_t *recvbuff = NULL; + uint32_t recvtype = 0; + __le32 *pkt = (__le32 *) skb->data; + + if (recvlength) { + if (urb->status) { + kfree_skb(skb); + goto setup_for_next; + } + + recvbuff = skb->data; + recvtype = le32_to_cpu(pkt[0]); + } else if (urb->status) { + kfree_skb(skb); + return; + } + + switch (recvtype) { + case CMD_TYPE_DATA: + process_cmdtypedata(recvlength, skb, cardp, priv); + break; + + case CMD_TYPE_REQUEST: + process_cmdrequest(recvlength, recvbuff, skb, cardp, priv); + break; + + case CMD_TYPE_INDICATION: + { + /* Event cause handling */ + u32 event_cause = le32_to_cpu(pkt[1]); + + /* Icky undocumented magic special case */ + if (event_cause & 0xffff0000) { + u16 tmp; + u8 retrycnt; + u8 failure; + + tmp = event_cause >> 16; + retrycnt = tmp & 0x00ff; + failure = (tmp & 0xff00) >> 8; + lbtf_send_tx_feedback(priv, retrycnt, failure); + } else if (event_cause == LBTF_EVENT_BCN_SENT) + lbtf_bcn_sent(priv); + else + printk(KERN_DEBUG + "Unsupported notification %d received\n", + event_cause); + kfree_skb(skb); + break; + } + default: + printk(KERN_DEBUG "libertastf: unknown command type 0x%X\n", + recvtype); + kfree_skb(skb); + break; + } + +setup_for_next: + if_usb_submit_rx_urb(cardp); +} + +/** + * if_usb_host_to_card - Download data to the device + * + * @priv pointer to struct lbtf_private structure + * @type type of data + * @buf pointer to data buffer + * @len number of bytes + * + * Returns: 0 on success, nonzero otherwise + */ +static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type, + uint8_t *payload, uint16_t nb) +{ + struct if_usb_card *cardp = priv->card; + u8 data = 0; + + if (type == MVMS_CMD) { + *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); + } else { + *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA); + data = 1; + } + + memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb); + + return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN, + data); +} + +/** + * if_usb_issue_boot_command - Issue boot command to Boot2. + * + * @ivalue 1 boots from FW by USB-Download, 2 boots from FW in EEPROM. + * + * Returns: 0 + */ +static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) +{ + struct bootcmd *bootcmd = cardp->ep_out_buf; + + /* Prepare command */ + bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); + bootcmd->cmd = ivalue; + memset(bootcmd->pad, 0, sizeof(bootcmd->pad)); + + /* Issue command */ + usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd), 0); + + return 0; +} + + +/** + * check_fwfile_format - Check the validity of Boot2/FW image. + * + * @data pointer to image + * @totlen image length + * + * Returns: 0 if the image is valid, nonzero otherwise. + */ +static int check_fwfile_format(const u8 *data, u32 totlen) +{ + u32 bincmd, exit; + u32 blksize, offset, len; + int ret; + + ret = 1; + exit = len = 0; + + do { + struct fwheader *fwh = (void *) data; + + bincmd = le32_to_cpu(fwh->dnldcmd); + blksize = le32_to_cpu(fwh->datalength); + switch (bincmd) { + case FW_HAS_DATA_TO_RECV: + offset = sizeof(struct fwheader) + blksize; + data += offset; + len += offset; + if (len >= totlen) + exit = 1; + break; + case FW_HAS_LAST_BLOCK: + exit = 1; + ret = 0; + break; + default: + exit = 1; + break; + } + } while (!exit); + + if (ret) + printk(KERN_INFO + "libertastf: firmware file format check failed\n"); + return ret; +} + + +static int if_usb_prog_firmware(struct if_usb_card *cardp) +{ + int i = 0; + static int reset_count = 10; + int ret = 0; + + ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev); + if (ret < 0) { + printk(KERN_INFO "libertastf: firmware %s not found\n", + lbtf_fw_name); + goto done; + } + + if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) + goto release_fw; + +restart: + if (if_usb_submit_rx_urb_fwload(cardp) < 0) { + ret = -1; + goto release_fw; + } + + cardp->bootcmdresp = 0; + do { + int j = 0; + i++; + /* Issue Boot command = 1, Boot from Download-FW */ + if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); + /* wait for command response */ + do { + j++; + msleep_interruptible(100); + } while (cardp->bootcmdresp == 0 && j < 10); + } while (cardp->bootcmdresp == 0 && i < 5); + + if (cardp->bootcmdresp <= 0) { + if (--reset_count >= 0) { + if_usb_reset_device(cardp); + goto restart; + } + return -1; + } + + i = 0; + + cardp->totalbytes = 0; + cardp->fwlastblksent = 0; + cardp->CRC_OK = 1; + cardp->fwdnldover = 0; + cardp->fwseqnum = -1; + cardp->totalbytes = 0; + cardp->fwfinalblk = 0; + + /* Send the first firmware packet... */ + if_usb_send_fw_pkt(cardp); + + /* ... and wait for the process to complete */ + wait_event_interruptible(cardp->fw_wq, cardp->priv->surpriseremoved || + cardp->fwdnldover); + + del_timer_sync(&cardp->fw_timeout); + usb_kill_urb(cardp->rx_urb); + + if (!cardp->fwdnldover) { + printk(KERN_INFO "libertastf: failed to load fw," + " resetting device!\n"); + if (--reset_count >= 0) { + if_usb_reset_device(cardp); + goto restart; + } + + printk(KERN_INFO "libertastf: fw download failure\n"); + ret = -1; + goto release_fw; + } + + cardp->priv->fw_ready = 1; + + release_fw: + release_firmware(cardp->fw); + cardp->fw = NULL; + + if_usb_setup_firmware(cardp->priv); + + done: + return ret; +} +EXPORT_SYMBOL_GPL(if_usb_prog_firmware); + + +#define if_usb_suspend NULL +#define if_usb_resume NULL + +static struct usb_driver if_usb_driver = { + .name = DRV_NAME, + .probe = if_usb_probe, + .disconnect = if_usb_disconnect, + .id_table = if_usb_table, + .suspend = if_usb_suspend, + .resume = if_usb_resume, +}; + +static int __init if_usb_init_module(void) +{ + int ret = 0; + + ret = usb_register(&if_usb_driver); + return ret; +} + +static void __exit if_usb_exit_module(void) +{ + usb_deregister(&if_usb_driver); +} + +module_init(if_usb_init_module); +module_exit(if_usb_exit_module); + +MODULE_DESCRIPTION("8388 USB WLAN Thinfirm Driver"); +MODULE_AUTHOR("Cozybit Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/libertas_tf/if_usb.h b/drivers/net/wireless/libertas_tf/if_usb.h new file mode 100644 index 00000000000..6fa5b3f59ef --- /dev/null +++ b/drivers/net/wireless/libertas_tf/if_usb.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * 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. + */ +#include <linux/wait.h> +#include <linux/timer.h> + +struct lbtf_private; + +/** + * This file contains definition for USB interface. + */ +#define CMD_TYPE_REQUEST 0xF00DFACE +#define CMD_TYPE_DATA 0xBEADC0DE +#define CMD_TYPE_INDICATION 0xBEEFFACE + +#define BOOT_CMD_FW_BY_USB 0x01 +#define BOOT_CMD_FW_IN_EEPROM 0x02 +#define BOOT_CMD_UPDATE_BOOT2 0x03 +#define BOOT_CMD_UPDATE_FW 0x04 +#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* LVRM */ + +struct bootcmd { + __le32 magic; + uint8_t cmd; + uint8_t pad[11]; +}; + +#define BOOT_CMD_RESP_OK 0x0001 +#define BOOT_CMD_RESP_FAIL 0x0000 + +struct bootcmdresp { + __le32 magic; + uint8_t cmd; + uint8_t result; + uint8_t pad[2]; +}; + +/** USB card description structure*/ +struct if_usb_card { + struct usb_device *udev; + struct urb *rx_urb, *tx_urb, *cmd_urb; + struct lbtf_private *priv; + + struct sk_buff *rx_skb; + + uint8_t ep_in; + uint8_t ep_out; + + int8_t bootcmdresp; + + int ep_in_size; + + void *ep_out_buf; + int ep_out_size; + + const struct firmware *fw; + struct timer_list fw_timeout; + wait_queue_head_t fw_wq; + uint32_t fwseqnum; + uint32_t totalbytes; + uint32_t fwlastblksent; + uint8_t CRC_OK; + uint8_t fwdnldover; + uint8_t fwfinalblk; + + __le16 boot2_version; +}; + +/** fwheader */ +struct fwheader { + __le32 dnldcmd; + __le32 baseaddr; + __le32 datalength; + __le32 CRC; +}; + +#define FW_MAX_DATA_BLK_SIZE 600 +/** FWData */ +struct fwdata { + struct fwheader hdr; + __le32 seqnum; + uint8_t data[0]; +}; + +/** fwsyncheader */ +struct fwsyncheader { + __le32 cmd; + __le32 seqnum; +}; + +#define FW_HAS_DATA_TO_RECV 0x00000001 +#define FW_HAS_LAST_BLOCK 0x00000004 diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h new file mode 100644 index 00000000000..8995cd7c29b --- /dev/null +++ b/drivers/net/wireless/libertas_tf/libertas_tf.h @@ -0,0 +1,514 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2007, Red Hat, Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * 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. + */ +#include <linux/spinlock.h> +#include <linux/device.h> +#include <linux/kthread.h> +#include <net/mac80211.h> + +#ifndef DRV_NAME +#define DRV_NAME "libertas_tf" +#endif + +#define MRVL_DEFAULT_RETRIES 9 +#define MRVL_PER_PACKET_RATE 0x10 +#define MRVL_MAX_BCN_SIZE 440 +#define CMD_OPTION_WAITFORRSP 0x0002 + +/* Return command are almost always the same as the host command, but with + * bit 15 set high. There are a few exceptions, though... + */ +#define CMD_RET(cmd) (0x8000 | cmd) + +/* Command codes */ +#define CMD_GET_HW_SPEC 0x0003 +#define CMD_802_11_RESET 0x0005 +#define CMD_MAC_MULTICAST_ADR 0x0010 +#define CMD_802_11_RADIO_CONTROL 0x001c +#define CMD_802_11_RF_CHANNEL 0x001d +#define CMD_802_11_RF_TX_POWER 0x001e +#define CMD_MAC_CONTROL 0x0028 +#define CMD_802_11_MAC_ADDRESS 0x004d +#define CMD_SET_BOOT2_VER 0x00a5 +#define CMD_802_11_BEACON_CTRL 0x00b0 +#define CMD_802_11_BEACON_SET 0x00cb +#define CMD_802_11_SET_MODE 0x00cc +#define CMD_802_11_SET_BSSID 0x00cd + +#define CMD_ACT_GET 0x0000 +#define CMD_ACT_SET 0x0001 + +/* Define action or option for CMD_802_11_RESET */ +#define CMD_ACT_HALT 0x0003 + +/* Define action or option for CMD_MAC_CONTROL */ +#define CMD_ACT_MAC_RX_ON 0x0001 +#define CMD_ACT_MAC_TX_ON 0x0002 +#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020 +#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040 +#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 + +/* Define action or option for CMD_802_11_RADIO_CONTROL */ +#define CMD_TYPE_AUTO_PREAMBLE 0x0001 +#define CMD_TYPE_SHORT_PREAMBLE 0x0002 +#define CMD_TYPE_LONG_PREAMBLE 0x0003 + +#define TURN_ON_RF 0x01 +#define RADIO_ON 0x01 +#define RADIO_OFF 0x00 + +#define SET_AUTO_PREAMBLE 0x05 +#define SET_SHORT_PREAMBLE 0x03 +#define SET_LONG_PREAMBLE 0x01 + +/* Define action or option for CMD_802_11_RF_CHANNEL */ +#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 +#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 + +/* Codes for CMD_802_11_SET_MODE */ +enum lbtf_mode { + LBTF_PASSIVE_MODE, + LBTF_STA_MODE, + LBTF_AP_MODE, +}; + +/** Card Event definition */ +#define MACREG_INT_CODE_FIRMWARE_READY 48 +/** Buffer Constants */ + +/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical +* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas +* driver has more local TxPDs. Each TxPD on the host memory is associated +* with a Tx control node. The driver maintains 8 RxPD descriptors for +* station firmware to store Rx packet information. +* +* Current version of MAC has a 32x6 multicast address buffer. +* +* 802.11b can have up to 14 channels, the driver keeps the +* BSSID(MAC address) of each APs or Ad hoc stations it has sensed. +*/ + +#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 +#define LBS_NUM_CMD_BUFFERS 10 +#define LBS_CMD_BUFFER_SIZE (2 * 1024) +#define MRVDRV_MAX_CHANNEL_SIZE 14 +#define MRVDRV_SNAP_HEADER_LEN 8 + +#define LBS_UPLD_SIZE 2312 +#define DEV_NAME_LEN 32 + +/** Misc constants */ +/* This section defines 802.11 specific contants */ + +#define MRVDRV_MAX_REGION_CODE 6 +/** + * the table to keep region code + */ +#define LBTF_REGDOMAIN_US 0x10 +#define LBTF_REGDOMAIN_CA 0x20 +#define LBTF_REGDOMAIN_EU 0x30 +#define LBTF_REGDOMAIN_SP 0x31 +#define LBTF_REGDOMAIN_FR 0x32 +#define LBTF_REGDOMAIN_JP 0x40 + +#define SBI_EVENT_CAUSE_SHIFT 3 + +/** RxPD status */ + +#define MRVDRV_RXPD_STATUS_OK 0x0001 + + +/* This is for firmware specific length */ +#define EXTRA_LEN 36 + +#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \ + (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN) + +#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \ + (ETH_FRAME_LEN + sizeof(struct rxpd) \ + + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN) + +#define CMD_F_HOSTCMD (1 << 0) +#define FW_CAPINFO_WPA (1 << 0) + +#define RF_ANTENNA_1 0x1 +#define RF_ANTENNA_2 0x2 +#define RF_ANTENNA_AUTO 0xFFFF + +#define LBTF_EVENT_BCN_SENT 55 + +/** Global Variable Declaration */ +/** mv_ms_type */ +enum mv_ms_type { + MVMS_DAT = 0, + MVMS_CMD = 1, + MVMS_TXDONE = 2, + MVMS_EVENT +}; + +extern struct workqueue_struct *lbtf_wq; + +struct lbtf_private; + +struct lbtf_offset_value { + u32 offset; + u32 value; +}; + +struct channel_range { + u8 regdomain; + u8 start; + u8 end; /* exclusive (channel must be less than end) */ +}; + +struct if_usb_card; + +/** Private structure for the MV device */ +struct lbtf_private { + void *card; + struct ieee80211_hw *hw; + + /* Command response buffer */ + u8 cmd_resp_buff[LBS_UPLD_SIZE]; + /* Download sent: + bit0 1/0=data_sent/data_tx_done, + bit1 1/0=cmd_sent/cmd_tx_done, + all other bits reserved 0 */ + struct ieee80211_vif *vif; + + struct work_struct cmd_work; + struct work_struct tx_work; + /** Hardware access */ + int (*hw_host_to_card) (struct lbtf_private *priv, u8 type, u8 *payload, u16 nb); + int (*hw_prog_firmware) (struct if_usb_card *cardp); + int (*hw_reset_device) (struct if_usb_card *cardp); + + + /** Wlan adapter data structure*/ + /** STATUS variables */ + u32 fwrelease; + u32 fwcapinfo; + /* protected with big lock */ + + struct mutex lock; + + /** command-related variables */ + u16 seqnum; + /* protected by big lock */ + + struct cmd_ctrl_node *cmd_array; + /** Current command */ + struct cmd_ctrl_node *cur_cmd; + /** command Queues */ + /** Free command buffers */ + struct list_head cmdfreeq; + /** Pending command buffers */ + struct list_head cmdpendingq; + + /** spin locks */ + spinlock_t driver_lock; + + /** Timers */ + struct timer_list command_timer; + int nr_retries; + int cmd_timed_out; + + u8 cmd_response_rxed; + + /** capability Info used in Association, start, join */ + u16 capability; + + /** MAC address information */ + u8 current_addr[ETH_ALEN]; + u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; + u32 nr_of_multicastmacaddr; + int cur_freq; + + struct sk_buff *skb_to_tx; + struct sk_buff *tx_skb; + + /** NIC Operation characteristics */ + u16 mac_control; + u16 regioncode; + struct channel_range range; + + u8 radioon; + u32 preamble; + + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_supported_band band; + struct lbtf_offset_value offsetvalue; + + u8 fw_ready; + u8 surpriseremoved; + struct sk_buff_head bc_ps_buf; +}; + +/* 802.11-related definitions */ + +/* TxPD descriptor */ +struct txpd { + /* Current Tx packet status */ + __le32 tx_status; + /* Tx control */ + __le32 tx_control; + __le32 tx_packet_location; + /* Tx packet length */ + __le16 tx_packet_length; + /* First 2 byte of destination MAC address */ + u8 tx_dest_addr_high[2]; + /* Last 4 byte of destination MAC address */ + u8 tx_dest_addr_low[4]; + /* Pkt Priority */ + u8 priority; + /* Pkt Trasnit Power control */ + u8 powermgmt; + /* Time the packet has been queued in the driver (units = 2ms) */ + u8 pktdelay_2ms; + /* reserved */ + u8 reserved1; +}; + +/* RxPD Descriptor */ +struct rxpd { + /* Current Rx packet status */ + __le16 status; + + /* SNR */ + u8 snr; + + /* Tx control */ + u8 rx_control; + + /* Pkt length */ + __le16 pkt_len; + + /* Noise Floor */ + u8 nf; + + /* Rx Packet Rate */ + u8 rx_rate; + + /* Pkt addr */ + __le32 pkt_ptr; + + /* Next Rx RxPD addr */ + __le32 next_rxpd_ptr; + + /* Pkt Priority */ + u8 priority; + u8 reserved[3]; +}; + +struct cmd_header { + __le16 command; + __le16 size; + __le16 seqnum; + __le16 result; +} __attribute__ ((packed)); + +struct cmd_ctrl_node { + struct list_head list; + int result; + /* command response */ + int (*callback)(struct lbtf_private *, + unsigned long, struct cmd_header *); + unsigned long callback_arg; + /* command data */ + struct cmd_header *cmdbuf; + /* wait queue */ + u16 cmdwaitqwoken; + wait_queue_head_t cmdwait_q; +}; + +/* + * Define data structure for CMD_GET_HW_SPEC + * This structure defines the response for the GET_HW_SPEC command + */ +struct cmd_ds_get_hw_spec { + struct cmd_header hdr; + + /* HW Interface version number */ + __le16 hwifversion; + /* HW version number */ + __le16 version; + /* Max number of TxPD FW can handle */ + __le16 nr_txpd; + /* Max no of Multicast address */ + __le16 nr_mcast_adr; + /* MAC address */ + u8 permanentaddr[6]; + + /* region Code */ + __le16 regioncode; + + /* Number of antenna used */ + __le16 nr_antenna; + + /* FW release number, example 0x01030304 = 2.3.4p1 */ + __le32 fwrelease; + + /* Base Address of TxPD queue */ + __le32 wcb_base; + /* Read Pointer of RxPd queue */ + __le32 rxpd_rdptr; + + /* Write Pointer of RxPd queue */ + __le32 rxpd_wrptr; + + /*FW/HW capability */ + __le32 fwcapinfo; +} __attribute__ ((packed)); + +struct cmd_ds_mac_control { + struct cmd_header hdr; + __le16 action; + u16 reserved; +}; + +struct cmd_ds_802_11_mac_address { + struct cmd_header hdr; + + __le16 action; + uint8_t macadd[ETH_ALEN]; +}; + +struct cmd_ds_mac_multicast_addr { + struct cmd_header hdr; + + __le16 action; + __le16 nr_of_adrs; + u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; +}; + +struct cmd_ds_set_mode { + struct cmd_header hdr; + + __le16 mode; +}; + +struct cmd_ds_set_bssid { + struct cmd_header hdr; + + u8 bssid[6]; + u8 activate; +}; + +struct cmd_ds_802_11_radio_control { + struct cmd_header hdr; + + __le16 action; + __le16 control; +}; + + +struct cmd_ds_802_11_rf_channel { + struct cmd_header hdr; + + __le16 action; + __le16 channel; + __le16 rftype; /* unused */ + __le16 reserved; /* unused */ + u8 channellist[32]; /* unused */ +}; + +struct cmd_ds_set_boot2_ver { + struct cmd_header hdr; + + __le16 action; + __le16 version; +}; + +struct cmd_ds_802_11_reset { + struct cmd_header hdr; + + __le16 action; +}; + +struct cmd_ds_802_11_beacon_control { + struct cmd_header hdr; + + __le16 action; + __le16 beacon_enable; + __le16 beacon_period; +}; + +struct cmd_ds_802_11_beacon_set { + struct cmd_header hdr; + + __le16 len; + u8 beacon[MRVL_MAX_BCN_SIZE]; +}; + +struct lbtf_private; +struct cmd_ctrl_node; + +/** Function Prototype Declaration */ +void lbtf_set_mac_control(struct lbtf_private *priv); + +int lbtf_free_cmd_buffer(struct lbtf_private *priv); + +int lbtf_allocate_cmd_buffer(struct lbtf_private *priv); +int lbtf_execute_next_command(struct lbtf_private *priv); +int lbtf_set_radio_control(struct lbtf_private *priv); +int lbtf_update_hw_spec(struct lbtf_private *priv); +int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv); +void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode); +void lbtf_set_bssid(struct lbtf_private *priv, bool activate, u8 *bssid); +int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr); + +int lbtf_set_channel(struct lbtf_private *priv, u8 channel); + +int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon); +int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable, + int beacon_int); + + +int lbtf_process_rx_command(struct lbtf_private *priv); +void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd, + int result); +void lbtf_cmd_response_rx(struct lbtf_private *priv); + +/* main.c */ +struct chan_freq_power *lbtf_get_region_cfp_table(u8 region, + int *cfp_no); +struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev); +int lbtf_remove_card(struct lbtf_private *priv); +int lbtf_start_card(struct lbtf_private *priv); +int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb); +void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail); +void lbtf_bcn_sent(struct lbtf_private *priv); + +/* support functions for cmd.c */ +/* lbtf_cmd() infers the size of the buffer to copy data back into, from + the size of the target of the pointer. Since the command to be sent + may often be smaller, that size is set in cmd->size by the caller.*/ +#define lbtf_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \ + uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \ + (cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd))); \ + __lbtf_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg); \ +}) + +#define lbtf_cmd_with_response(priv, cmdnr, cmd) \ + lbtf_cmd(priv, cmdnr, cmd, lbtf_cmd_copyback, (unsigned long) (cmd)) + +void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size); + +int __lbtf_cmd(struct lbtf_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbtf_private *, unsigned long, + struct cmd_header *), + unsigned long callback_arg); + +int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra, + struct cmd_header *resp); diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c new file mode 100644 index 00000000000..feff945ad85 --- /dev/null +++ b/drivers/net/wireless/libertas_tf/main.c @@ -0,0 +1,662 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * 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. + */ +#include "libertas_tf.h" +#include "linux/etherdevice.h" + +#define DRIVER_RELEASE_VERSION "004.p0" +/* thinfirm version: 5.132.X.pX */ +#define LBTF_FW_VER_MIN 0x05840300 +#define LBTF_FW_VER_MAX 0x0584ffff +#define QOS_CONTROL_LEN 2 + +static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION; +struct workqueue_struct *lbtf_wq; + +static const struct ieee80211_channel lbtf_channels[] = { + { .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 }, +}; + +/* This table contains the hardware specific values for the modulation rates. */ +static const struct ieee80211_rate lbtf_rates[] = { + { .bitrate = 10, + .hw_value = 0, }, + { .bitrate = 20, + .hw_value = 1, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = 2, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = 3, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = 5, + .flags = 0 }, + { .bitrate = 90, + .hw_value = 6, + .flags = 0 }, + { .bitrate = 120, + .hw_value = 7, + .flags = 0 }, + { .bitrate = 180, + .hw_value = 8, + .flags = 0 }, + { .bitrate = 240, + .hw_value = 9, + .flags = 0 }, + { .bitrate = 360, + .hw_value = 10, + .flags = 0 }, + { .bitrate = 480, + .hw_value = 11, + .flags = 0 }, + { .bitrate = 540, + .hw_value = 12, + .flags = 0 }, +}; + +static void lbtf_cmd_work(struct work_struct *work) +{ + struct lbtf_private *priv = container_of(work, struct lbtf_private, + cmd_work); + spin_lock_irq(&priv->driver_lock); + /* command response? */ + if (priv->cmd_response_rxed) { + priv->cmd_response_rxed = 0; + spin_unlock_irq(&priv->driver_lock); + lbtf_process_rx_command(priv); + spin_lock_irq(&priv->driver_lock); + } + + if (priv->cmd_timed_out && priv->cur_cmd) { + struct cmd_ctrl_node *cmdnode = priv->cur_cmd; + + if (++priv->nr_retries > 10) { + lbtf_complete_command(priv, cmdnode, + -ETIMEDOUT); + priv->nr_retries = 0; + } else { + priv->cur_cmd = NULL; + + /* Stick it back at the _top_ of the pending + * queue for immediate resubmission */ + list_add(&cmdnode->list, &priv->cmdpendingq); + } + } + priv->cmd_timed_out = 0; + spin_unlock_irq(&priv->driver_lock); + + if (!priv->fw_ready) + return; + /* Execute the next command */ + if (!priv->cur_cmd) + lbtf_execute_next_command(priv); +} + +/** + * lbtf_setup_firmware: initialize firmware. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 on success. + */ +static int lbtf_setup_firmware(struct lbtf_private *priv) +{ + int ret = -1; + + /* + * Read priv address from HW + */ + memset(priv->current_addr, 0xff, ETH_ALEN); + ret = lbtf_update_hw_spec(priv); + if (ret) { + ret = -1; + goto done; + } + + lbtf_set_mac_control(priv); + lbtf_set_radio_control(priv); + + ret = 0; +done: + return ret; +} + +/** + * This function handles the timeout of command sending. + * It will re-send the same command again. + */ +static void command_timer_fn(unsigned long data) +{ + struct lbtf_private *priv = (struct lbtf_private *)data; + unsigned long flags; + + spin_lock_irqsave(&priv->driver_lock, flags); + + if (!priv->cur_cmd) { + printk(KERN_DEBUG "libertastf: command timer expired; " + "no pending command\n"); + goto out; + } + + printk(KERN_DEBUG "libertas: command %x timed out\n", + le16_to_cpu(priv->cur_cmd->cmdbuf->command)); + + priv->cmd_timed_out = 1; + queue_work(lbtf_wq, &priv->cmd_work); +out: + spin_unlock_irqrestore(&priv->driver_lock, flags); +} + +static int lbtf_init_adapter(struct lbtf_private *priv) +{ + memset(priv->current_addr, 0xff, ETH_ALEN); + mutex_init(&priv->lock); + + priv->vif = NULL; + setup_timer(&priv->command_timer, command_timer_fn, + (unsigned long)priv); + + INIT_LIST_HEAD(&priv->cmdfreeq); + INIT_LIST_HEAD(&priv->cmdpendingq); + + spin_lock_init(&priv->driver_lock); + + /* Allocate the command buffers */ + if (lbtf_allocate_cmd_buffer(priv)) + return -1; + + return 0; +} + +static void lbtf_free_adapter(struct lbtf_private *priv) +{ + lbtf_free_cmd_buffer(priv); + del_timer(&priv->command_timer); +} + +static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct lbtf_private *priv = hw->priv; + + priv->skb_to_tx = skb; + queue_work(lbtf_wq, &priv->tx_work); + /* + * queue will be restarted when we receive transmission feedback if + * there are no buffered multicast frames to send + */ + ieee80211_stop_queues(priv->hw); + return 0; +} + +static void lbtf_tx_work(struct work_struct *work) +{ + struct lbtf_private *priv = container_of(work, struct lbtf_private, + tx_work); + unsigned int len; + struct ieee80211_tx_info *info; + struct txpd *txpd; + struct sk_buff *skb = NULL; + int err; + + if ((priv->vif->type == NL80211_IFTYPE_AP) && + (!skb_queue_empty(&priv->bc_ps_buf))) + skb = skb_dequeue(&priv->bc_ps_buf); + else if (priv->skb_to_tx) { + skb = priv->skb_to_tx; + priv->skb_to_tx = NULL; + } else + return; + + len = skb->len; + info = IEEE80211_SKB_CB(skb); + txpd = (struct txpd *) skb_push(skb, sizeof(struct txpd)); + + if (priv->surpriseremoved) { + dev_kfree_skb_any(skb); + return; + } + + memset(txpd, 0, sizeof(struct txpd)); + /* Activate per-packet rate selection */ + txpd->tx_control |= cpu_to_le32(MRVL_PER_PACKET_RATE | + ieee80211_get_tx_rate(priv->hw, info)->hw_value); + + /* copy destination address from 802.11 header */ + memcpy(txpd->tx_dest_addr_high, skb->data + sizeof(struct txpd) + 4, + ETH_ALEN); + txpd->tx_packet_length = cpu_to_le16(len); + txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); + BUG_ON(priv->tx_skb); + spin_lock_irq(&priv->driver_lock); + priv->tx_skb = skb; + err = priv->hw_host_to_card(priv, MVMS_DAT, skb->data, skb->len); + spin_unlock_irq(&priv->driver_lock); + if (err) { + dev_kfree_skb_any(skb); + priv->tx_skb = NULL; + } +} + +static int lbtf_op_start(struct ieee80211_hw *hw) +{ + struct lbtf_private *priv = hw->priv; + void *card = priv->card; + int ret = -1; + + if (!priv->fw_ready) + /* Upload firmware */ + if (priv->hw_prog_firmware(card)) + goto err_prog_firmware; + + /* poke the firmware */ + priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; + priv->radioon = RADIO_ON; + priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; + ret = lbtf_setup_firmware(priv); + if (ret) + goto err_prog_firmware; + + if ((priv->fwrelease < LBTF_FW_VER_MIN) || + (priv->fwrelease > LBTF_FW_VER_MAX)) { + ret = -1; + goto err_prog_firmware; + } + + printk(KERN_INFO "libertastf: Marvell WLAN 802.11 thinfirm adapter\n"); + return 0; + +err_prog_firmware: + priv->hw_reset_device(card); + return ret; +} + +static void lbtf_op_stop(struct ieee80211_hw *hw) +{ + struct lbtf_private *priv = hw->priv; + unsigned long flags; + struct sk_buff *skb; + + struct cmd_ctrl_node *cmdnode; + /* Flush pending command nodes */ + spin_lock_irqsave(&priv->driver_lock, flags); + list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { + cmdnode->result = -ENOENT; + cmdnode->cmdwaitqwoken = 1; + wake_up_interruptible(&cmdnode->cmdwait_q); + } + + spin_unlock_irqrestore(&priv->driver_lock, flags); + cancel_work_sync(&priv->cmd_work); + cancel_work_sync(&priv->tx_work); + while ((skb = skb_dequeue(&priv->bc_ps_buf))) + dev_kfree_skb_any(skb); + priv->radioon = RADIO_OFF; + lbtf_set_radio_control(priv); + + return; +} + +static int lbtf_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct lbtf_private *priv = hw->priv; + if (priv->vif != NULL) + return -EOPNOTSUPP; + + priv->vif = conf->vif; + switch (conf->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + lbtf_set_mode(priv, LBTF_AP_MODE); + break; + case NL80211_IFTYPE_STATION: + lbtf_set_mode(priv, LBTF_STA_MODE); + break; + default: + priv->vif = NULL; + return -EOPNOTSUPP; + } + lbtf_set_mac_address(priv, (u8 *) conf->mac_addr); + return 0; +} + +static void lbtf_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct lbtf_private *priv = hw->priv; + + if (priv->vif->type == NL80211_IFTYPE_AP || + priv->vif->type == NL80211_IFTYPE_MESH_POINT) + lbtf_beacon_ctrl(priv, 0, 0); + lbtf_set_mode(priv, LBTF_PASSIVE_MODE); + lbtf_set_bssid(priv, 0, NULL); + priv->vif = NULL; +} + +static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct lbtf_private *priv = hw->priv; + if (conf->channel->center_freq != priv->cur_freq) { + priv->cur_freq = conf->channel->center_freq; + lbtf_set_channel(priv, conf->channel->hw_value); + } + return 0; +} + +static int lbtf_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct lbtf_private *priv = hw->priv; + struct sk_buff *beacon; + + switch (priv->vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + beacon = ieee80211_beacon_get(hw, vif); + if (beacon) { + lbtf_beacon_set(priv, beacon); + kfree_skb(beacon); + lbtf_beacon_ctrl(priv, 1, hw->conf.beacon_int); + } + break; + default: + break; + } + + if (conf->bssid) { + u8 null_bssid[ETH_ALEN] = {0}; + bool activate = compare_ether_addr(conf->bssid, null_bssid); + lbtf_set_bssid(priv, activate, conf->bssid); + } + + return 0; +} + +#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI) +static void lbtf_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct lbtf_private *priv = hw->priv; + int old_mac_control = priv->mac_control; + int i; + changed_flags &= SUPPORTED_FIF_FLAGS; + *new_flags &= SUPPORTED_FIF_FLAGS; + + if (!changed_flags) + return; + + if (*new_flags & (FIF_PROMISC_IN_BSS)) + priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE; + else + priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; + if (*new_flags & (FIF_ALLMULTI) || + mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { + priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; + priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; + } else if (mc_count) { + priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; + priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; + priv->nr_of_multicastmacaddr = mc_count; + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + memcpy(&priv->multicastlist[i], mclist->da_addr, + ETH_ALEN); + mclist = mclist->next; + } + lbtf_cmd_set_mac_multicast_addr(priv); + } else { + priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE | + CMD_ACT_MAC_ALL_MULTICAST_ENABLE); + if (priv->nr_of_multicastmacaddr) { + priv->nr_of_multicastmacaddr = 0; + lbtf_cmd_set_mac_multicast_addr(priv); + } + } + + + if (priv->mac_control != old_mac_control) + lbtf_set_mac_control(priv); +} + +static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct lbtf_private *priv = hw->priv; + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + else + priv->preamble = CMD_TYPE_LONG_PREAMBLE; + lbtf_set_radio_control(priv); + } + + return; +} + +static const struct ieee80211_ops lbtf_ops = { + .tx = lbtf_op_tx, + .start = lbtf_op_start, + .stop = lbtf_op_stop, + .add_interface = lbtf_op_add_interface, + .remove_interface = lbtf_op_remove_interface, + .config = lbtf_op_config, + .config_interface = lbtf_op_config_interface, + .configure_filter = lbtf_op_configure_filter, + .bss_info_changed = lbtf_op_bss_info_changed, +}; + +int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) +{ + struct ieee80211_rx_status stats; + struct rxpd *prxpd; + int need_padding; + unsigned int flags; + struct ieee80211_hdr *hdr; + + prxpd = (struct rxpd *) skb->data; + + stats.flag = 0; + if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) + stats.flag |= RX_FLAG_FAILED_FCS_CRC; + stats.freq = priv->cur_freq; + stats.band = IEEE80211_BAND_2GHZ; + stats.signal = prxpd->snr; + stats.noise = prxpd->nf; + stats.qual = prxpd->snr - prxpd->nf; + /* Marvell rate index has a hole at value 4 */ + if (prxpd->rx_rate > 4) + --prxpd->rx_rate; + stats.rate_idx = prxpd->rx_rate; + skb_pull(skb, sizeof(struct rxpd)); + + hdr = (struct ieee80211_hdr *)skb->data; + flags = le32_to_cpu(*(__le32 *)(skb->data + 4)); + + need_padding = ieee80211_is_data_qos(hdr->frame_control); + need_padding ^= ieee80211_has_a4(hdr->frame_control); + need_padding ^= ieee80211_is_data_qos(hdr->frame_control) && + (*ieee80211_get_qos_ctl(hdr) & + IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); + + if (need_padding) { + memmove(skb->data + 2, skb->data, skb->len); + skb_reserve(skb, 2); + } + + ieee80211_rx_irqsafe(priv->hw, skb, &stats); + return 0; +} +EXPORT_SYMBOL_GPL(lbtf_rx); + +/** + * lbtf_add_card: Add and initialize the card, no fw upload yet. + * + * @card A pointer to card + * + * Returns: pointer to struct lbtf_priv. + */ +struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) +{ + struct ieee80211_hw *hw; + struct lbtf_private *priv = NULL; + + hw = ieee80211_alloc_hw(sizeof(struct lbtf_private), &lbtf_ops); + if (!hw) + goto done; + + priv = hw->priv; + if (lbtf_init_adapter(priv)) + goto err_init_adapter; + + priv->hw = hw; + priv->card = card; + priv->tx_skb = NULL; + + hw->queues = 1; + hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + hw->extra_tx_headroom = sizeof(struct txpd); + memcpy(priv->channels, lbtf_channels, sizeof(lbtf_channels)); + memcpy(priv->rates, lbtf_rates, sizeof(lbtf_rates)); + priv->band.n_bitrates = ARRAY_SIZE(lbtf_rates); + priv->band.bitrates = priv->rates; + priv->band.n_channels = ARRAY_SIZE(lbtf_channels); + priv->band.channels = priv->channels; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + skb_queue_head_init(&priv->bc_ps_buf); + + SET_IEEE80211_DEV(hw, dmdev); + + INIT_WORK(&priv->cmd_work, lbtf_cmd_work); + INIT_WORK(&priv->tx_work, lbtf_tx_work); + if (ieee80211_register_hw(hw)) + goto err_init_adapter; + + goto done; + +err_init_adapter: + lbtf_free_adapter(priv); + ieee80211_free_hw(hw); + priv = NULL; + +done: + return priv; +} +EXPORT_SYMBOL_GPL(lbtf_add_card); + + +int lbtf_remove_card(struct lbtf_private *priv) +{ + struct ieee80211_hw *hw = priv->hw; + + priv->surpriseremoved = 1; + del_timer(&priv->command_timer); + lbtf_free_adapter(priv); + priv->hw = NULL; + ieee80211_unregister_hw(hw); + ieee80211_free_hw(hw); + + return 0; +} +EXPORT_SYMBOL_GPL(lbtf_remove_card); + +void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb); + memset(&info->status, 0, sizeof(info->status)); + /* + * Commented out, otherwise we never go beyond 1Mbit/s using mac80211 + * default pid rc algorithm. + * + * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt; + */ + info->status.excessive_retries = fail ? 1 : 0; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail) + info->flags |= IEEE80211_TX_STAT_ACK; + skb_pull(priv->tx_skb, sizeof(struct txpd)); + ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb); + priv->tx_skb = NULL; + if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf)) + ieee80211_wake_queues(priv->hw); + else + queue_work(lbtf_wq, &priv->tx_work); +} +EXPORT_SYMBOL_GPL(lbtf_send_tx_feedback); + +void lbtf_bcn_sent(struct lbtf_private *priv) +{ + struct sk_buff *skb = NULL; + + if (priv->vif->type != NL80211_IFTYPE_AP) + return; + + if (skb_queue_empty(&priv->bc_ps_buf)) { + bool tx_buff_bc = 0; + + while ((skb = ieee80211_get_buffered_bc(priv->hw, priv->vif))) { + skb_queue_tail(&priv->bc_ps_buf, skb); + tx_buff_bc = 1; + } + if (tx_buff_bc) { + ieee80211_stop_queues(priv->hw); + queue_work(lbtf_wq, &priv->tx_work); + } + } + + skb = ieee80211_beacon_get(priv->hw, priv->vif); + + if (skb) { + lbtf_beacon_set(priv, skb); + kfree_skb(skb); + } +} +EXPORT_SYMBOL_GPL(lbtf_bcn_sent); + +static int __init lbtf_init_module(void) +{ + lbtf_wq = create_workqueue("libertastf"); + if (lbtf_wq == NULL) { + printk(KERN_ERR "libertastf: couldn't create workqueue\n"); + return -ENOMEM; + } + return 0; +} + +static void __exit lbtf_exit_module(void) +{ + destroy_workqueue(lbtf_wq); +} + +module_init(lbtf_init_module); +module_exit(lbtf_exit_module); + +MODULE_DESCRIPTION("Libertas WLAN Thinfirm Driver Library"); +MODULE_AUTHOR("Cozybit Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 248d31a7aa3..1a019e98dac 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -14,6 +14,8 @@ * - RX filtering based on filter configuration (data->rx_filter) */ +#include <linux/list.h> +#include <linux/spinlock.h> #include <net/mac80211.h> #include <net/ieee80211_radiotap.h> #include <linux/if_arp.h> @@ -28,11 +30,56 @@ static int radios = 2; module_param(radios, int, 0444); MODULE_PARM_DESC(radios, "Number of simulated radios"); +struct hwsim_vif_priv { + u32 magic; +}; + +#define HWSIM_VIF_MAGIC 0x69537748 + +static inline void hwsim_check_magic(struct ieee80211_vif *vif) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + WARN_ON(vp->magic != HWSIM_VIF_MAGIC); +} + +static inline void hwsim_set_magic(struct ieee80211_vif *vif) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + vp->magic = HWSIM_VIF_MAGIC; +} + +static inline void hwsim_clear_magic(struct ieee80211_vif *vif) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + vp->magic = 0; +} + +struct hwsim_sta_priv { + u32 magic; +}; + +#define HWSIM_STA_MAGIC 0x6d537748 + +static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) +{ + struct hwsim_sta_priv *sp = (void *)sta->drv_priv; + WARN_ON(sp->magic != HWSIM_VIF_MAGIC); +} + +static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) +{ + struct hwsim_sta_priv *sp = (void *)sta->drv_priv; + sp->magic = HWSIM_VIF_MAGIC; +} + +static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) +{ + struct hwsim_sta_priv *sp = (void *)sta->drv_priv; + sp->magic = 0; +} static struct class *hwsim_class; -static struct ieee80211_hw **hwsim_radios; -static int hwsim_radio_count; static struct net_device *hwsim_mon; /* global monitor netdev */ @@ -68,7 +115,12 @@ static const struct ieee80211_rate hwsim_rates[] = { { .bitrate = 540 } }; +static spinlock_t hwsim_radio_lock; +static struct list_head hwsim_radios; + struct mac80211_hwsim_data { + struct list_head list; + struct ieee80211_hw *hw; struct device *dev; struct ieee80211_supported_band band; struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)]; @@ -144,11 +196,11 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, } -static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, - struct sk_buff *skb) +static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, + struct sk_buff *skb) { - struct mac80211_hwsim_data *data = hw->priv; - int i, ack = 0; + struct mac80211_hwsim_data *data = hw->priv, *data2; + bool ack = false; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_rx_status rx_status; @@ -161,13 +213,13 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, /* TODO: simulate signal strength (and optional packet drop) */ /* Copy skb to all enabled radios that are on the current frequency */ - for (i = 0; i < hwsim_radio_count; i++) { - struct mac80211_hwsim_data *data2; + spin_lock(&hwsim_radio_lock); + list_for_each_entry(data2, &hwsim_radios, list) { struct sk_buff *nskb; - if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw) + if (data == data2) continue; - data2 = hwsim_radios[i]->priv; + if (!data2->started || !data2->radio_enabled || data->channel->center_freq != data2->channel->center_freq) continue; @@ -176,11 +228,12 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (nskb == NULL) continue; - if (memcmp(hdr->addr1, hwsim_radios[i]->wiphy->perm_addr, + if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, ETH_ALEN) == 0) - ack = 1; - ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status); + ack = true; + ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status); } + spin_unlock(&hwsim_radio_lock); return ack; } @@ -189,7 +242,7 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct mac80211_hwsim_data *data = hw->priv; - int ack; + bool ack; struct ieee80211_tx_info *txi; mac80211_hwsim_monitor_rx(hw, skb); @@ -210,6 +263,12 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ack = mac80211_hwsim_tx_frame(hw, skb); txi = IEEE80211_SKB_CB(skb); + + if (txi->control.vif) + hwsim_check_magic(txi->control.vif); + if (txi->control.sta) + hwsim_check_sta_magic(txi->control.sta); + memset(&txi->status, 0, sizeof(txi->status)); if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { if (ack) @@ -246,6 +305,7 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", wiphy_name(hw->wiphy), __func__, conf->type, print_mac(mac, conf->mac_addr)); + hwsim_set_magic(conf->vif); return 0; } @@ -257,6 +317,8 @@ static void mac80211_hwsim_remove_interface( printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", wiphy_name(hw->wiphy), __func__, conf->type, print_mac(mac, conf->mac_addr)); + hwsim_check_magic(conf->vif); + hwsim_clear_magic(conf->vif); } @@ -267,7 +329,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, struct sk_buff *skb; struct ieee80211_tx_info *info; - if (vif->type != IEEE80211_IF_TYPE_AP) + hwsim_check_magic(vif); + + if (vif->type != NL80211_IFTYPE_AP) return; skb = ieee80211_beacon_get(hw, vif); @@ -341,7 +405,45 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, *total_flags = data->rx_filter; } +static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + hwsim_check_magic(vif); + return 0; +} + +static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + hwsim_check_magic(vif); +} + +static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + hwsim_check_magic(vif); + switch (cmd) { + case STA_NOTIFY_ADD: + hwsim_set_sta_magic(sta); + break; + case STA_NOTIFY_REMOVE: + hwsim_clear_sta_magic(sta); + break; + } +} +static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + bool set) +{ + hwsim_check_sta_magic(sta); + return 0; +} static const struct ieee80211_ops mac80211_hwsim_ops = { @@ -352,23 +454,30 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .remove_interface = mac80211_hwsim_remove_interface, .config = mac80211_hwsim_config, .configure_filter = mac80211_hwsim_configure_filter, + .config_interface = mac80211_hwsim_config_interface, + .bss_info_changed = mac80211_hwsim_bss_info_changed, + .sta_notify = mac80211_hwsim_sta_notify, + .set_tim = mac80211_hwsim_set_tim, }; static void mac80211_hwsim_free(void) { - int i; - - for (i = 0; i < hwsim_radio_count; i++) { - if (hwsim_radios[i]) { - struct mac80211_hwsim_data *data; - data = hwsim_radios[i]->priv; - ieee80211_unregister_hw(hwsim_radios[i]); - device_unregister(data->dev); - ieee80211_free_hw(hwsim_radios[i]); - } + struct list_head tmplist, *i, *tmp; + struct mac80211_hwsim_data *data; + + INIT_LIST_HEAD(&tmplist); + + spin_lock_bh(&hwsim_radio_lock); + list_for_each_safe(i, tmp, &hwsim_radios) + list_move(i, &tmplist); + spin_unlock_bh(&hwsim_radio_lock); + + list_for_each_entry(data, &tmplist, list) { + ieee80211_unregister_hw(data->hw); + device_unregister(data->dev); + ieee80211_free_hw(data->hw); } - kfree(hwsim_radios); class_destroy(hwsim_class); } @@ -398,42 +507,37 @@ static int __init init_mac80211_hwsim(void) struct ieee80211_hw *hw; DECLARE_MAC_BUF(mac); - if (radios < 1 || radios > 65535) + if (radios < 1 || radios > 100) return -EINVAL; - hwsim_radio_count = radios; - hwsim_radios = kcalloc(hwsim_radio_count, - sizeof(struct ieee80211_hw *), GFP_KERNEL); - if (hwsim_radios == NULL) - return -ENOMEM; + spin_lock_init(&hwsim_radio_lock); + INIT_LIST_HEAD(&hwsim_radios); hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); - if (IS_ERR(hwsim_class)) { - kfree(hwsim_radios); + if (IS_ERR(hwsim_class)) return PTR_ERR(hwsim_class); - } memset(addr, 0, ETH_ALEN); addr[0] = 0x02; - for (i = 0; i < hwsim_radio_count; i++) { + for (i = 0; i < radios; i++) { printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n", i); hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops); - if (hw == NULL) { + if (!hw) { printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw " "failed\n"); err = -ENOMEM; goto failed; } - hwsim_radios[i] = hw; - data = hw->priv; - data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw, - "hwsim%d", i); + data->hw = hw; + + data->dev = device_create(hwsim_class, NULL, 0, hw, + "hwsim%d", i); if (IS_ERR(data->dev)) { printk(KERN_DEBUG - "mac80211_hwsim: device_create_drvdata " + "mac80211_hwsim: device_create " "failed (%ld)\n", PTR_ERR(data->dev)); err = -ENOMEM; goto failed_drvdata; @@ -446,7 +550,15 @@ static int __init init_mac80211_hwsim(void) SET_IEEE80211_PERM_ADDR(hw, addr); hw->channel_change_time = 1; - hw->queues = 1; + hw->queues = 4; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP); + hw->ampdu_queues = 1; + + /* ask mac80211 to reserve space for magic */ + hw->vif_data_size = sizeof(struct hwsim_vif_priv); + hw->sta_data_size = sizeof(struct hwsim_sta_priv); memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels)); memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); @@ -454,6 +566,19 @@ static int __init init_mac80211_hwsim(void) data->band.n_channels = ARRAY_SIZE(hwsim_channels); data->band.bitrates = data->rates; data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); + data->band.ht_info.ht_supported = 1; + data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + data->band.ht_info.ampdu_factor = 0x3; + data->band.ht_info.ampdu_density = 0x6; + memset(data->band.ht_info.supp_mcs_set, 0, + sizeof(data->band.ht_info.supp_mcs_set)); + data->band.ht_info.supp_mcs_set[0] = 0xff; + data->band.ht_info.supp_mcs_set[1] = 0xff; + data->band.ht_info.supp_mcs_set[12] = + IEEE80211_HT_CAP_MCS_TX_DEFINED; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; err = ieee80211_register_hw(hw); @@ -469,6 +594,8 @@ static int __init init_mac80211_hwsim(void) setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, (unsigned long) hw); + + list_add_tail(&data->list, &hwsim_radios); } hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); @@ -500,7 +627,6 @@ failed_hw: device_unregister(data->dev); failed_drvdata: ieee80211_free_hw(hw); - hwsim_radios[i] = NULL; failed: mac80211_hwsim_free(); return err; @@ -509,8 +635,7 @@ failed: static void __exit exit_mac80211_hwsim(void) { - printk(KERN_DEBUG "mac80211_hwsim: unregister %d radios\n", - hwsim_radio_count); + printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n"); unregister_netdev(hwsim_mon); mac80211_hwsim_free(); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index f479c1af678..a670f36b5f3 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -398,7 +398,7 @@ static int netwave_probe(struct pcmcia_device *link) link->io.IOAddrLines = 5; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = &netwave_interrupt; @@ -749,9 +749,10 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { for (i = j = 0x0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) break; + if (i == 0) + break; } - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestIO, i); goto failed; } diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 36c004e1560..50904771f29 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -79,15 +79,21 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> +#include <linux/firmware.h> #include <linux/if_arp.h> #include <linux/wireless.h> #include <net/iw_handler.h> #include <net/ieee80211.h> +#include <linux/scatterlist.h> +#include <linux/crypto.h> + #include "hermes_rid.h" +#include "hermes_dld.h" #include "orinoco.h" /********************************************************************/ @@ -241,6 +247,74 @@ static int __orinoco_program_rids(struct net_device *dev); static void __orinoco_set_multicast_list(struct net_device *dev); /********************************************************************/ +/* Michael MIC crypto setup */ +/********************************************************************/ +#define MICHAEL_MIC_LEN 8 +static int orinoco_mic_init(struct orinoco_private *priv) +{ + priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); + if (IS_ERR(priv->tx_tfm_mic)) { + printk(KERN_DEBUG "orinoco_mic_init: could not allocate " + "crypto API michael_mic\n"); + priv->tx_tfm_mic = NULL; + return -ENOMEM; + } + + priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); + if (IS_ERR(priv->rx_tfm_mic)) { + printk(KERN_DEBUG "orinoco_mic_init: could not allocate " + "crypto API michael_mic\n"); + priv->rx_tfm_mic = NULL; + return -ENOMEM; + } + + return 0; +} + +static void orinoco_mic_free(struct orinoco_private *priv) +{ + if (priv->tx_tfm_mic) + crypto_free_hash(priv->tx_tfm_mic); + if (priv->rx_tfm_mic) + crypto_free_hash(priv->rx_tfm_mic); +} + +static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, + u8 *da, u8 *sa, u8 priority, + u8 *data, size_t data_len, u8 *mic) +{ + struct hash_desc desc; + struct scatterlist sg[2]; + u8 hdr[ETH_HLEN + 2]; /* size of header + padding */ + + if (tfm_michael == NULL) { + printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); + return -1; + } + + /* Copy header into buffer. We need the padding on the end zeroed */ + memcpy(&hdr[0], da, ETH_ALEN); + memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN); + hdr[ETH_ALEN*2] = priority; + hdr[ETH_ALEN*2+1] = 0; + hdr[ETH_ALEN*2+2] = 0; + hdr[ETH_ALEN*2+3] = 0; + + /* Use scatter gather to MIC header and data in one go */ + sg_init_table(sg, 2); + sg_set_buf(&sg[0], hdr, sizeof(hdr)); + sg_set_buf(&sg[1], data, data_len); + + if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN)) + return -1; + + desc.tfm = tfm_michael; + desc.flags = 0; + return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr), + mic); +} + +/********************************************************************/ /* Internal helper functions */ /********************************************************************/ @@ -273,12 +347,19 @@ static inline void set_port_type(struct orinoco_private *priv) #define ORINOCO_MAX_BSS_COUNT 64 static int orinoco_bss_data_allocate(struct orinoco_private *priv) { - if (priv->bss_data) + if (priv->bss_xbss_data) return 0; - priv->bss_data = - kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(bss_element), GFP_KERNEL); - if (!priv->bss_data) { + if (priv->has_ext_scan) + priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * + sizeof(struct xbss_element), + GFP_KERNEL); + else + priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * + sizeof(struct bss_element), + GFP_KERNEL); + + if (!priv->bss_xbss_data) { printk(KERN_WARNING "Out of memory allocating beacons"); return -ENOMEM; } @@ -287,18 +368,319 @@ static int orinoco_bss_data_allocate(struct orinoco_private *priv) static void orinoco_bss_data_free(struct orinoco_private *priv) { - kfree(priv->bss_data); - priv->bss_data = NULL; + kfree(priv->bss_xbss_data); + priv->bss_xbss_data = NULL; } +#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data) +#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data) static void orinoco_bss_data_init(struct orinoco_private *priv) { int i; INIT_LIST_HEAD(&priv->bss_free_list); INIT_LIST_HEAD(&priv->bss_list); - for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) - list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list); + if (priv->has_ext_scan) + for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) + list_add_tail(&(PRIV_XBSS[i].list), + &priv->bss_free_list); + else + for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) + list_add_tail(&(PRIV_BSS[i].list), + &priv->bss_free_list); + +} + +static inline u8 *orinoco_get_ie(u8 *data, size_t len, + enum ieee80211_mfie eid) +{ + u8 *p = data; + while ((p + 2) < (data + len)) { + if (p[0] == eid) + return p; + p += p[1] + 2; + } + return NULL; +} + +#define WPA_OUI_TYPE "\x00\x50\xF2\x01" +#define WPA_SELECTOR_LEN 4 +static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) +{ + u8 *p = data; + while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { + if ((p[0] == MFIE_TYPE_GENERIC) && + (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) + return p; + p += p[1] + 2; + } + return NULL; +} + + +/********************************************************************/ +/* Download functionality */ +/********************************************************************/ + +struct fw_info { + char *pri_fw; + char *sta_fw; + char *ap_fw; + u32 pda_addr; + u16 pda_size; +}; + +const static struct fw_info orinoco_fw[] = { + { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, + { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, + { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 0x100 } +}; + +/* Structure used to access fields in FW + * Make sure LE decoding macros are used + */ +struct orinoco_fw_header { + char hdr_vers[6]; /* ASCII string for header version */ + __le16 headersize; /* Total length of header */ + __le32 entry_point; /* NIC entry point */ + __le32 blocks; /* Number of blocks to program */ + __le32 block_offset; /* Offset of block data from eof header */ + __le32 pdr_offset; /* Offset to PDR data from eof header */ + __le32 pri_offset; /* Offset to primary plug data */ + __le32 compat_offset; /* Offset to compatibility data*/ + char signature[0]; /* FW signature length headersize-20 */ +} __attribute__ ((packed)); + +/* Download either STA or AP firmware into the card. */ +static int +orinoco_dl_firmware(struct orinoco_private *priv, + const struct fw_info *fw, + int ap) +{ + /* Plug Data Area (PDA) */ + __le16 pda[512] = { 0 }; + + hermes_t *hw = &priv->hw; + const struct firmware *fw_entry; + const struct orinoco_fw_header *hdr; + const unsigned char *first_block; + const unsigned char *end; + const char *firmware; + struct net_device *dev = priv->ndev; + int err; + + if (ap) + firmware = fw->ap_fw; + else + firmware = fw->sta_fw; + + printk(KERN_DEBUG "%s: Attempting to download firmware %s\n", + dev->name, firmware); + + /* Read current plug data */ + err = hermes_read_pda(hw, pda, fw->pda_addr, + min_t(u16, fw->pda_size, sizeof(pda)), 0); + printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); + if (err) + return err; + + err = request_firmware(&fw_entry, firmware, priv->dev); + if (err) { + printk(KERN_ERR "%s: Cannot find firmware %s\n", + dev->name, firmware); + return -ENOENT; + } + + hdr = (const struct orinoco_fw_header *) fw_entry->data; + + /* Enable aux port to allow programming */ + err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); + printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); + if (err != 0) + goto abort; + + /* Program data */ + first_block = (fw_entry->data + + le16_to_cpu(hdr->headersize) + + le32_to_cpu(hdr->block_offset)); + end = fw_entry->data + fw_entry->size; + + err = hermes_program(hw, first_block, end); + printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err); + if (err != 0) + goto abort; + + /* Update production data */ + first_block = (fw_entry->data + + le16_to_cpu(hdr->headersize) + + le32_to_cpu(hdr->pdr_offset)); + + err = hermes_apply_pda_with_defaults(hw, first_block, pda); + printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); + if (err) + goto abort; + + /* Tell card we've finished */ + err = hermesi_program_end(hw); + printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err); + if (err != 0) + goto abort; + + /* Check if we're running */ + printk(KERN_DEBUG "%s: hermes_present returned %d\n", + dev->name, hermes_present(hw)); + +abort: + release_firmware(fw_entry); + return err; +} + +/* End markers */ +#define TEXT_END 0x1A /* End of text header */ + +/* + * Process a firmware image - stop the card, load the firmware, reset + * the card and make sure it responds. For the secondary firmware take + * care of the PDA - read it and then write it on top of the firmware. + */ +static int +symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, + const unsigned char *image, const unsigned char *end, + int secondary) +{ + hermes_t *hw = &priv->hw; + int ret; + const unsigned char *ptr; + const unsigned char *first_block; + + /* Plug Data Area (PDA) */ + __le16 pda[256]; + + /* Binary block begins after the 0x1A marker */ + ptr = image; + while (*ptr++ != TEXT_END); + first_block = ptr; + + /* Read the PDA from EEPROM */ + if (secondary) { + ret = hermes_read_pda(hw, pda, fw->pda_addr, sizeof(pda), 1); + if (ret) + return ret; + } + + /* Stop the firmware, so that it can be safely rewritten */ + if (priv->stop_fw) { + ret = priv->stop_fw(priv, 1); + if (ret) + return ret; + } + + /* Program the adapter with new firmware */ + ret = hermes_program(hw, first_block, end); + if (ret) + return ret; + + /* Write the PDA to the adapter */ + if (secondary) { + size_t len = hermes_blocks_length(first_block); + ptr = first_block + len; + ret = hermes_apply_pda(hw, ptr, pda); + if (ret) + return ret; + } + + /* Run the firmware */ + if (priv->stop_fw) { + ret = priv->stop_fw(priv, 0); + if (ret) + return ret; + } + + /* Reset hermes chip and make sure it responds */ + ret = hermes_init(hw); + + /* hermes_reset() should return 0 with the secondary firmware */ + if (secondary && ret != 0) + return -ENODEV; + + /* And this should work with any firmware */ + if (!hermes_present(hw)) + return -ENODEV; + + return 0; +} + + +/* + * Download the firmware into the card, this also does a PCMCIA soft + * reset on the card, to make sure it's in a sane state. + */ +static int +symbol_dl_firmware(struct orinoco_private *priv, + const struct fw_info *fw) +{ + struct net_device *dev = priv->ndev; + int ret; + const struct firmware *fw_entry; + + if (request_firmware(&fw_entry, fw->pri_fw, + priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->pri_fw); + return -ENOENT; + } + + /* Load primary firmware */ + ret = symbol_dl_image(priv, fw, fw_entry->data, + fw_entry->data + fw_entry->size, 0); + release_firmware(fw_entry); + if (ret) { + printk(KERN_ERR "%s: Primary firmware download failed\n", + dev->name); + return ret; + } + + if (request_firmware(&fw_entry, fw->sta_fw, + priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->sta_fw); + return -ENOENT; + } + + /* Load secondary firmware */ + ret = symbol_dl_image(priv, fw, fw_entry->data, + fw_entry->data + fw_entry->size, 1); + release_firmware(fw_entry); + if (ret) { + printk(KERN_ERR "%s: Secondary firmware download failed\n", + dev->name); + } + + return ret; +} + +static int orinoco_download(struct orinoco_private *priv) +{ + int err = 0; + /* Reload firmware */ + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + /* case FIRMWARE_TYPE_INTERSIL: */ + err = orinoco_dl_firmware(priv, + &orinoco_fw[priv->firmware_type], 0); + break; + + case FIRMWARE_TYPE_SYMBOL: + err = symbol_dl_firmware(priv, + &orinoco_fw[priv->firmware_type]); + break; + case FIRMWARE_TYPE_INTERSIL: + break; + } + /* TODO: if we fail we probably need to reinitialise + * the driver */ + + return err; } /********************************************************************/ @@ -453,8 +835,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) int err = 0; u16 txfid = priv->txfid; struct ethhdr *eh; - int data_off; - struct hermes_tx_descriptor desc; + int tx_control; unsigned long flags; if (! netif_running(dev)) { @@ -486,23 +867,54 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_HLEN) goto drop; - eh = (struct ethhdr *)skb->data; + tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - memset(&desc, 0, sizeof(desc)); - desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); - err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx descriptor " - "to BAP\n", dev->name, err); - goto busy; + if (priv->encode_alg == IW_ENCODE_ALG_TKIP) + tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | + HERMES_TXCTRL_MIC; + + if (priv->has_alt_txcntl) { + /* WPA enabled firmwares have tx_cntl at the end of + * the 802.11 header. So write zeroed descriptor and + * 802.11 header at the same time + */ + char desc[HERMES_802_3_OFFSET]; + __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET]; + + memset(&desc, 0, sizeof(desc)); + + *txcntl = cpu_to_le16(tx_control); + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), + txfid, 0); + if (err) { + if (net_ratelimit()) + printk(KERN_ERR "%s: Error %d writing Tx " + "descriptor to BAP\n", dev->name, err); + goto busy; + } + } else { + struct hermes_tx_descriptor desc; + + memset(&desc, 0, sizeof(desc)); + + desc.tx_control = cpu_to_le16(tx_control); + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), + txfid, 0); + if (err) { + if (net_ratelimit()) + printk(KERN_ERR "%s: Error %d writing Tx " + "descriptor to BAP\n", dev->name, err); + goto busy; + } + + /* Clear the 802.11 header and data length fields - some + * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused + * if this isn't done. */ + hermes_clear_words(hw, HERMES_DATA0, + HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); } - /* Clear the 802.11 header and data length fields - some - * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused - * if this isn't done. */ - hermes_clear_words(hw, HERMES_DATA0, - HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); + eh = (struct ethhdr *)skb->data; /* Encapsulate Ethernet-II frames */ if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ @@ -513,33 +925,65 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) /* Strip destination and source from the data */ skb_pull(skb, 2 * ETH_ALEN); - data_off = HERMES_802_2_OFFSET + sizeof(encaps_hdr); /* And move them to a separate header */ memcpy(&hdr.eth, eh, 2 * ETH_ALEN); hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len); memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); - err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), - txfid, HERMES_802_3_OFFSET); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing packet " - "header to BAP\n", dev->name, err); - goto busy; + /* Insert the SNAP header */ + if (skb_headroom(skb) < sizeof(hdr)) { + printk(KERN_ERR + "%s: Not enough headroom for 802.2 headers %d\n", + dev->name, skb_headroom(skb)); + goto drop; } - } else { /* IEEE 802.3 frame */ - data_off = HERMES_802_3_OFFSET; + eh = (struct ethhdr *) skb_push(skb, sizeof(hdr)); + memcpy(eh, &hdr, sizeof(hdr)); } err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len, - txfid, data_off); + txfid, HERMES_802_3_OFFSET); if (err) { printk(KERN_ERR "%s: Error %d writing packet to BAP\n", dev->name, err); goto busy; } + /* Calculate Michael MIC */ + if (priv->encode_alg == IW_ENCODE_ALG_TKIP) { + u8 mic_buf[MICHAEL_MIC_LEN + 1]; + u8 *mic; + size_t offset; + size_t len; + + if (skb->len % 2) { + /* MIC start is on an odd boundary */ + mic_buf[0] = skb->data[skb->len - 1]; + mic = &mic_buf[1]; + offset = skb->len - 1; + len = MICHAEL_MIC_LEN + 1; + } else { + mic = &mic_buf[0]; + offset = skb->len; + len = MICHAEL_MIC_LEN; + } + + michael_mic(priv->tx_tfm_mic, + priv->tkip_key[priv->tx_key].tx_mic, + eh->h_dest, eh->h_source, 0 /* priority */, + skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); + + /* Write the MIC */ + err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len, + txfid, HERMES_802_3_OFFSET + offset); + if (err) { + printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", + dev->name, err); + goto busy; + } + } + /* Finally, we actually initiate the send */ netif_stop_queue(dev); @@ -554,7 +998,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; - stats->tx_bytes += data_off + skb->len; + stats->tx_bytes += HERMES_802_3_OFFSET + skb->len; goto ok; drop: @@ -834,21 +1278,48 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, stats->rx_dropped++; } +/* Get tsc from the firmware */ +static int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, + u8 *tsc) +{ + hermes_t *hw = &priv->hw; + int err = 0; + u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; + + if ((key < 0) || (key > 4)) + return -EINVAL; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, + sizeof(tsc_arr), NULL, &tsc_arr); + if (!err) + memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); + + return err; +} + static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) { struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; - u16 rxfid, status, fc; + u16 rxfid, status; int length; - struct hermes_rx_descriptor desc; - struct ethhdr *hdr; + struct hermes_rx_descriptor *desc; + struct orinoco_rx_data *rx_data; int err; + desc = kmalloc(sizeof(*desc), GFP_ATOMIC); + if (!desc) { + printk(KERN_WARNING + "%s: Can't allocate space for RX descriptor\n", + dev->name); + goto update_stats; + } + rxfid = hermes_read_regn(hw, RXFID); - err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), + err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc), rxfid, 0); if (err) { printk(KERN_ERR "%s: error %d reading Rx descriptor. " @@ -856,7 +1327,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) goto update_stats; } - status = le16_to_cpu(desc.status); + status = le16_to_cpu(desc->status); if (status & HERMES_RXSTAT_BADCRC) { DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", @@ -867,8 +1338,8 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) /* Handle frames in monitor mode */ if (priv->iw_mode == IW_MODE_MONITOR) { - orinoco_rx_monitor(dev, rxfid, &desc); - return; + orinoco_rx_monitor(dev, rxfid, desc); + goto out; } if (status & HERMES_RXSTAT_UNDECRYPTABLE) { @@ -878,15 +1349,14 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) goto update_stats; } - length = le16_to_cpu(desc.data_len); - fc = le16_to_cpu(desc.frame_ctl); + length = le16_to_cpu(desc->data_len); /* Sanity checks */ if (length < 3) { /* No for even an 802.2 LLC header */ /* At least on Symbol firmware with PCF we get quite a lot of these legitimately - Poll frames with no data. */ - return; + goto out; } if (length > IEEE80211_DATA_LEN) { printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", @@ -895,6 +1365,11 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) goto update_stats; } + /* Payload size does not include Michael MIC. Increase payload + * size to read it together with the data. */ + if (status & HERMES_RXSTAT_MIC) + length += MICHAEL_MIC_LEN; + /* We need space for the packet data itself, plus an ethernet header, plus 2 bytes so we can align the IP header on a 32bit boundary, plus 1 byte so we can read in odd length @@ -921,6 +1396,100 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) goto drop; } + /* Add desc and skb to rx queue */ + rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC); + if (!rx_data) { + printk(KERN_WARNING "%s: Can't allocate RX packet\n", + dev->name); + goto drop; + } + rx_data->desc = desc; + rx_data->skb = skb; + list_add_tail(&rx_data->list, &priv->rx_list); + tasklet_schedule(&priv->rx_tasklet); + + return; + +drop: + dev_kfree_skb_irq(skb); +update_stats: + stats->rx_errors++; + stats->rx_dropped++; +out: + kfree(desc); +} + +static void orinoco_rx(struct net_device *dev, + struct hermes_rx_descriptor *desc, + struct sk_buff *skb) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + u16 status, fc; + int length; + struct ethhdr *hdr; + + status = le16_to_cpu(desc->status); + length = le16_to_cpu(desc->data_len); + fc = le16_to_cpu(desc->frame_ctl); + + /* Calculate and check MIC */ + if (status & HERMES_RXSTAT_MIC) { + int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> + HERMES_MIC_KEY_ID_SHIFT); + u8 mic[MICHAEL_MIC_LEN]; + u8 *rxmic; + u8 *src = (fc & IEEE80211_FCTL_FROMDS) ? + desc->addr3 : desc->addr2; + + /* Extract Michael MIC from payload */ + rxmic = skb->data + skb->len - MICHAEL_MIC_LEN; + + skb_trim(skb, skb->len - MICHAEL_MIC_LEN); + length -= MICHAEL_MIC_LEN; + + michael_mic(priv->rx_tfm_mic, + priv->tkip_key[key_id].rx_mic, + desc->addr1, + src, + 0, /* priority or QoS? */ + skb->data, + skb->len, + &mic[0]); + + if (memcmp(mic, rxmic, + MICHAEL_MIC_LEN)) { + union iwreq_data wrqu; + struct iw_michaelmicfailure wxmic; + DECLARE_MAC_BUF(mac); + + printk(KERN_WARNING "%s: " + "Invalid Michael MIC in data frame from %s, " + "using key %i\n", + dev->name, print_mac(mac, src), key_id); + + /* TODO: update stats */ + + /* Notify userspace */ + memset(&wxmic, 0, sizeof(wxmic)); + wxmic.flags = key_id & IW_MICFAILURE_KEY_ID; + wxmic.flags |= (desc->addr1[0] & 1) ? + IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE; + wxmic.src_addr.sa_family = ARPHRD_ETHER; + memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN); + + (void) orinoco_hw_get_tkip_iv(priv, key_id, + &wxmic.tsc[0]); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(wxmic); + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, + (char *) &wxmic); + + goto drop; + } + } + /* Handle decapsulation * In most cases, the firmware tell us about SNAP frames. * For some reason, the SNAP frames sent by LinkSys APs @@ -939,11 +1508,11 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN); hdr->h_proto = htons(length); } - memcpy(hdr->h_dest, desc.addr1, ETH_ALEN); + memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); if (fc & IEEE80211_FCTL_FROMDS) - memcpy(hdr->h_source, desc.addr3, ETH_ALEN); + memcpy(hdr->h_source, desc->addr3, ETH_ALEN); else - memcpy(hdr->h_source, desc.addr2, ETH_ALEN); + memcpy(hdr->h_source, desc->addr2, ETH_ALEN); dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); @@ -952,7 +1521,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) skb->pkt_type = PACKET_OTHERHOST; /* Process the wireless stats if needed */ - orinoco_stat_gather(dev, skb, &desc); + orinoco_stat_gather(dev, skb, desc); /* Pass the packet to the networking stack */ netif_rx(skb); @@ -961,13 +1530,33 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) return; - drop: - dev_kfree_skb_irq(skb); - update_stats: + drop: + dev_kfree_skb(skb); stats->rx_errors++; stats->rx_dropped++; } +static void orinoco_rx_isr_tasklet(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_rx_data *rx_data, *temp; + struct hermes_rx_descriptor *desc; + struct sk_buff *skb; + + /* extract desc and skb from queue */ + list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { + desc = rx_data->desc; + skb = rx_data->skb; + list_del(&rx_data->list); + kfree(rx_data); + + orinoco_rx(dev, desc, skb); + + kfree(desc); + } +} + /********************************************************************/ /* Rx path (info frames) */ /********************************************************************/ @@ -1087,52 +1676,172 @@ static void orinoco_join_ap(struct work_struct *work) } /* Send new BSSID to userspace */ -static void orinoco_send_wevents(struct work_struct *work) +static void orinoco_send_bssid_wevent(struct orinoco_private *priv) { - struct orinoco_private *priv = - container_of(work, struct orinoco_private, wevent_work); struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; union iwreq_data wrqu; int err; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return; err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) - goto out; + return; wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +} - out: - orinoco_unlock(priv, &flags); +static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + union iwreq_data wrqu; + int err; + u8 buf[88]; + u8 *ie; + + if (!priv->has_wpa) + return; + + err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, + sizeof(buf), NULL, &buf); + if (err != 0) + return; + + ie = orinoco_get_wpa_ie(buf, sizeof(buf)); + if (ie) { + int rem = sizeof(buf) - (ie - &buf[0]); + wrqu.data.length = ie[1] + 2; + if (wrqu.data.length > rem) + wrqu.data.length = rem; + + if (wrqu.data.length) + /* Send event to user space */ + wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie); + } } +static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + union iwreq_data wrqu; + int err; + u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */ + u8 *ie; + + if (!priv->has_wpa) + return; + + err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, + sizeof(buf), NULL, &buf); + if (err != 0) + return; + + ie = orinoco_get_wpa_ie(buf, sizeof(buf)); + if (ie) { + int rem = sizeof(buf) - (ie - &buf[0]); + wrqu.data.length = ie[1] + 2; + if (wrqu.data.length > rem) + wrqu.data.length = rem; + + if (wrqu.data.length) + /* Send event to user space */ + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie); + } +} + +static void orinoco_send_wevents(struct work_struct *work) +{ + struct orinoco_private *priv = + container_of(work, struct orinoco_private, wevent_work); + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return; + + orinoco_send_assocreqie_wevent(priv); + orinoco_send_assocrespie_wevent(priv); + orinoco_send_bssid_wevent(priv); + + orinoco_unlock(priv, &flags); +} static inline void orinoco_clear_scan_results(struct orinoco_private *priv, unsigned long scan_age) { - bss_element *bss; - bss_element *tmp_bss; - - /* Blow away current list of scan results */ - list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { - if (!scan_age || - time_after(jiffies, bss->last_scanned + scan_age)) { - list_move_tail(&bss->list, &priv->bss_free_list); - /* Don't blow away ->list, just BSS data */ - memset(bss, 0, sizeof(bss->bss)); - bss->last_scanned = 0; + if (priv->has_ext_scan) { + struct xbss_element *bss; + struct xbss_element *tmp_bss; + + /* Blow away current list of scan results */ + list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { + if (!scan_age || + time_after(jiffies, bss->last_scanned + scan_age)) { + list_move_tail(&bss->list, + &priv->bss_free_list); + /* Don't blow away ->list, just BSS data */ + memset(&bss->bss, 0, sizeof(bss->bss)); + bss->last_scanned = 0; + } + } + } else { + struct bss_element *bss; + struct bss_element *tmp_bss; + + /* Blow away current list of scan results */ + list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { + if (!scan_age || + time_after(jiffies, bss->last_scanned + scan_age)) { + list_move_tail(&bss->list, + &priv->bss_free_list); + /* Don't blow away ->list, just BSS data */ + memset(&bss->bss, 0, sizeof(bss->bss)); + bss->last_scanned = 0; + } } } } +static void orinoco_add_ext_scan_result(struct orinoco_private *priv, + struct agere_ext_scan_info *atom) +{ + struct xbss_element *bss = NULL; + int found = 0; + + /* Try to update an existing bss first */ + list_for_each_entry(bss, &priv->bss_list, list) { + if (compare_ether_addr(bss->bss.bssid, atom->bssid)) + continue; + /* ESSID lengths */ + if (bss->bss.data[1] != atom->data[1]) + continue; + if (memcmp(&bss->bss.data[2], &atom->data[2], + atom->data[1])) + continue; + found = 1; + break; + } + + /* Grab a bss off the free list */ + if (!found && !list_empty(&priv->bss_free_list)) { + bss = list_entry(priv->bss_free_list.next, + struct xbss_element, list); + list_del(priv->bss_free_list.next); + + list_add_tail(&bss->list, &priv->bss_list); + } + + if (bss) { + /* Always update the BSS to get latest beacon info */ + memcpy(&bss->bss, atom, sizeof(bss->bss)); + bss->last_scanned = jiffies; + } +} + static int orinoco_process_scan_results(struct net_device *dev, unsigned char *buf, int len) @@ -1194,7 +1903,7 @@ static int orinoco_process_scan_results(struct net_device *dev, /* Read the entries one by one */ for (; offset + atom_len <= len; offset += atom_len) { int found = 0; - bss_element *bss = NULL; + struct bss_element *bss = NULL; /* Get next atom */ atom = (union hermes_scan_info *) (buf + offset); @@ -1216,7 +1925,7 @@ static int orinoco_process_scan_results(struct net_device *dev, /* Grab a bss off the free list */ if (!found && !list_empty(&priv->bss_free_list)) { bss = list_entry(priv->bss_free_list.next, - bss_element, list); + struct bss_element, list); list_del(priv->bss_free_list.next); list_add_tail(&bss->list, &priv->bss_list); @@ -1404,6 +2113,63 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) kfree(buf); } break; + case HERMES_INQ_CHANNELINFO: + { + struct agere_ext_scan_info *bss; + + if (!priv->scan_inprogress) { + printk(KERN_DEBUG "%s: Got chaninfo without scan, " + "len=%d\n", dev->name, len); + break; + } + + /* An empty result indicates that the scan is complete */ + if (len == 0) { + union iwreq_data wrqu; + + /* Scan is no longer in progress */ + priv->scan_inprogress = 0; + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + break; + } + + /* Sanity check */ + else if (len > sizeof(*bss)) { + printk(KERN_WARNING + "%s: Ext scan results too large (%d bytes). " + "Truncating results to %zd bytes.\n", + dev->name, len, sizeof(*bss)); + len = sizeof(*bss); + } else if (len < (offsetof(struct agere_ext_scan_info, + data) + 2)) { + /* Drop this result now so we don't have to + * keep checking later */ + printk(KERN_WARNING + "%s: Ext scan results too short (%d bytes)\n", + dev->name, len); + break; + } + + bss = kmalloc(sizeof(*bss), GFP_ATOMIC); + if (bss == NULL) + break; + + /* Read scan data */ + err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, + infofid, sizeof(info)); + if (err) { + kfree(bss); + break; + } + + orinoco_add_ext_scan_result(priv, bss); + + kfree(bss); + break; + } case HERMES_INQ_SEC_STAT_AGERE: /* Security status (Agere specific) */ /* Ignore this frame for now */ @@ -1586,7 +2352,7 @@ static int __orinoco_hw_set_wap(struct orinoco_private *priv) } /* Change the WEP keys and/or the current keys. Can be called - * either from __orinoco_hw_setup_wep() or directly from + * either from __orinoco_hw_setup_enc() or directly from * orinoco_ioctl_setiwencode(). In the later case the association * with the AP is not broken (if the firmware can handle it), * which is needed for 802.1x implementations. */ @@ -1646,14 +2412,16 @@ static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) return 0; } -static int __orinoco_hw_setup_wep(struct orinoco_private *priv) +static int __orinoco_hw_setup_enc(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; int err = 0; int master_wep_flag; int auth_flag; + int enc_flag; - if (priv->wep_on) + /* Setup WEP keys for WEP and WPA */ + if (priv->encode_alg) __orinoco_hw_setup_wepkeys(priv); if (priv->wep_restrict) @@ -1661,9 +2429,16 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) else auth_flag = HERMES_AUTH_OPEN; + if (priv->wpa_enabled) + enc_flag = 2; + else if (priv->encode_alg == IW_ENCODE_ALG_WEP) + enc_flag = 1; + else + enc_flag = 0; + switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->wep_on) { + if (priv->encode_alg == IW_ENCODE_ALG_WEP) { /* Enable the shared-key authentication. */ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFAUTHENTICATION_AGERE, @@ -1671,14 +2446,24 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) } err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPENABLED_AGERE, - priv->wep_on); + enc_flag); if (err) return err; + + if (priv->has_wpa) { + /* Set WPA key management */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, + priv->key_mgmt); + if (err) + return err; + } + break; case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->wep_on) { + if (priv->encode_alg == IW_ENCODE_ALG_WEP) { if (priv->wep_restrict || (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | @@ -1710,6 +2495,84 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) return 0; } +/* key must be 32 bytes, including the tx and rx MIC keys. + * rsc must be 8 bytes + * tsc must be 8 bytes or NULL + */ +static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, + u8 *key, u8 *rsc, u8 *tsc) +{ + struct { + __le16 idx; + u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; + u8 key[TKIP_KEYLEN]; + u8 tx_mic[MIC_KEYLEN]; + u8 rx_mic[MIC_KEYLEN]; + u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; + } __attribute__ ((packed)) buf; + int ret; + int err; + int k; + u16 xmitting; + + key_idx &= 0x3; + + if (set_tx) + key_idx |= 0x8000; + + buf.idx = cpu_to_le16(key_idx); + memcpy(buf.key, key, + sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); + + if (rsc == NULL) + memset(buf.rsc, 0, sizeof(buf.rsc)); + else + memcpy(buf.rsc, rsc, sizeof(buf.rsc)); + + if (tsc == NULL) { + memset(buf.tsc, 0, sizeof(buf.tsc)); + buf.tsc[4] = 0x10; + } else { + memcpy(buf.tsc, tsc, sizeof(buf.tsc)); + } + + /* Wait upto 100ms for tx queue to empty */ + k = 100; + do { + k--; + udelay(1000); + ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, + &xmitting); + if (ret) + break; + } while ((k > 0) && xmitting); + + if (k == 0) + ret = -ETIMEDOUT; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, + &buf); + + return ret ? ret : err; +} + +static int orinoco_clear_tkip_key(struct orinoco_private *priv, + int key_idx) +{ + hermes_t *hw = &priv->hw; + int err; + + memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, + key_idx); + if (err) + printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", + priv->ndev->name, err, key_idx); + return err; +} + static int __orinoco_program_rids(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); @@ -1906,10 +2769,10 @@ static int __orinoco_program_rids(struct net_device *dev) } /* Set up encryption */ - if (priv->has_wep) { - err = __orinoco_hw_setup_wep(priv); + if (priv->has_wep || priv->has_wpa) { + err = __orinoco_hw_setup_enc(priv); if (err) { - printk(KERN_ERR "%s: Error %d activating WEP\n", + printk(KERN_ERR "%s: Error %d activating encryption\n", dev->name, err); return err; } @@ -2047,6 +2910,12 @@ static void orinoco_reset(struct work_struct *work) } } + if (priv->do_fw_download) { + err = orinoco_download(priv); + if (err) + priv->do_fw_download = 0; + } + err = orinoco_reinit_firmware(dev); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", @@ -2258,6 +3127,10 @@ static int determine_firmware(struct net_device *dev) priv->has_ibss = 1; priv->has_wep = 0; priv->has_big_wep = 0; + priv->has_alt_txcntl = 0; + priv->has_ext_scan = 0; + priv->has_wpa = 0; + priv->do_fw_download = 0; /* Determine capabilities from the firmware version */ switch (priv->firmware_type) { @@ -2277,8 +3150,11 @@ static int determine_firmware(struct net_device *dev) priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ priv->ibss_port = 1; priv->has_hostscan = (firmver >= 0x8000a); + priv->do_fw_download = 1; priv->broken_monitor = (firmver >= 0x80000); - + priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ + priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ + priv->has_wpa = (firmver >= 0x9002a); /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II * Tested CableTron firmware : 4.32 => Anton */ @@ -2321,6 +3197,21 @@ static int determine_firmware(struct net_device *dev) firmver >= 0x31000; priv->has_preamble = (firmver >= 0x20000); priv->ibss_port = 4; + + /* Symbol firmware is found on various cards, but + * there has been no attempt to check firmware + * download on non-spectrum_cs based cards. + * + * Given that the Agere firmware download works + * differently, we should avoid doing a firmware + * download with the Symbol algorithm on non-spectrum + * cards. + * + * For now we can identify a spectrum_cs based card + * because it has a firmware reset function. + */ + priv->do_fw_download = (priv->stop_fw != NULL); + priv->broken_disableport = (firmver == 0x25013) || (firmver >= 0x30000 && firmver <= 0x31000); priv->has_hostscan = (firmver >= 0x31001) || @@ -2391,6 +3282,20 @@ static int orinoco_init(struct net_device *dev) goto out; } + if (priv->do_fw_download) { + err = orinoco_download(priv); + if (err) + priv->do_fw_download = 0; + + /* Check firmware version again */ + err = determine_firmware(dev); + if (err != 0) { + printk(KERN_ERR "%s: Incompatible firmware, aborting\n", + dev->name); + goto out; + } + } + if (priv->has_port3) printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); if (priv->has_ibss) @@ -2403,6 +3308,20 @@ static int orinoco_init(struct net_device *dev) else printk("40-bit key\n"); } + if (priv->has_wpa) { + printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name); + if (orinoco_mic_init(priv)) { + printk(KERN_ERR "%s: Failed to setup MIC crypto " + "algorithm. Disabling WPA support\n", dev->name); + priv->has_wpa = 0; + } + } + + /* Now we have the firmware capabilities, allocate appropiate + * sized scan buffers */ + if (orinoco_bss_data_allocate(priv)) + goto out; + orinoco_bss_data_init(priv); /* Get the MAC address */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, @@ -2518,8 +3437,13 @@ static int orinoco_init(struct net_device *dev) priv->channel = 0; /* use firmware default */ priv->promiscuous = 0; - priv->wep_on = 0; + priv->encode_alg = IW_ENCODE_ALG_NONE; priv->tx_key = 0; + priv->wpa_enabled = 0; + priv->tkip_cm_active = 0; + priv->key_mgmt = 0; + priv->wpa_ie_len = 0; + priv->wpa_ie = NULL; /* Make the hardware available, as long as it hasn't been * removed elsewhere (e.g. by PCMCIA hot unplug) */ @@ -2533,8 +3457,11 @@ static int orinoco_init(struct net_device *dev) return err; } -struct net_device *alloc_orinocodev(int sizeof_card, - int (*hard_reset)(struct orinoco_private *)) +struct net_device +*alloc_orinocodev(int sizeof_card, + struct device *device, + int (*hard_reset)(struct orinoco_private *), + int (*stop_fw)(struct orinoco_private *, int)) { struct net_device *dev; struct orinoco_private *priv; @@ -2549,10 +3476,7 @@ struct net_device *alloc_orinocodev(int sizeof_card, + sizeof(struct orinoco_private)); else priv->card = NULL; - - if (orinoco_bss_data_allocate(priv)) - goto err_out_free; - orinoco_bss_data_init(priv); + priv->dev = device; /* Setup / override net_device fields */ dev->init = orinoco_init; @@ -2570,10 +3494,14 @@ struct net_device *alloc_orinocodev(int sizeof_card, dev->set_multicast_list = orinoco_set_multicast_list; /* we use the default eth_mac_addr for setting the MAC addr */ + /* Reserve space in skb for the SNAP header */ + dev->hard_header_len += ENCAPS_OVERHEAD; + /* Set up default callbacks */ dev->open = orinoco_open; dev->stop = orinoco_stop; priv->hard_reset = hard_reset; + priv->stop_fw = stop_fw; spin_lock_init(&priv->lock); priv->open = 0; @@ -2584,20 +3512,27 @@ struct net_device *alloc_orinocodev(int sizeof_card, INIT_WORK(&priv->join_work, orinoco_join_ap); INIT_WORK(&priv->wevent_work, orinoco_send_wevents); + INIT_LIST_HEAD(&priv->rx_list); + tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, + (unsigned long) dev); + netif_carrier_off(dev); priv->last_linkstatus = 0xffff; return dev; - -err_out_free: - free_netdev(dev); - return NULL; } void free_orinocodev(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); + /* No need to empty priv->rx_list: if the tasklet is scheduled + * when we call tasklet_kill it will run one final time, + * emptying the list */ + tasklet_kill(&priv->rx_tasklet); + priv->wpa_ie_len = 0; + kfree(priv->wpa_ie); + orinoco_mic_free(priv); orinoco_bss_data_free(priv); free_netdev(dev); } @@ -2909,7 +3844,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, memset(range, 0, sizeof(struct iw_range)); range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 14; + range->we_version_source = 22; /* Set available channels/frequencies */ range->num_channels = NUM_CHANNELS; @@ -2939,6 +3874,9 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, } } + if (priv->has_wpa) + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; + if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){ /* Quality stats meaningless in ad-hoc mode */ } else { @@ -2986,6 +3924,11 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, range->min_r_time = 0; range->max_r_time = 65535 * 1000; /* ??? */ + if (priv->firmware_type == FIRMWARE_TYPE_AGERE) + range->scan_capa = IW_SCAN_CAPA_ESSID; + else + range->scan_capa = IW_SCAN_CAPA_NONE; + /* Event capability (kernel) */ IW_EVENT_CAPA_SET_KERNEL(range->event_capa); /* Event capability (driver) */ @@ -3005,7 +3948,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct orinoco_private *priv = netdev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; - int enable = priv->wep_on; + int encode_alg = priv->encode_alg; int restricted = priv->wep_restrict; u16 xlen = 0; int err = -EINPROGRESS; /* Call commit handler */ @@ -3026,6 +3969,10 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, if (orinoco_lock(priv, &flags) != 0) return -EBUSY; + /* Clear any TKIP key we have */ + if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) + (void) orinoco_clear_tkip_key(priv, setindex); + if (erq->length > 0) { if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; @@ -3039,9 +3986,9 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, xlen = 0; /* Switch on WEP if off */ - if ((!enable) && (xlen > 0)) { + if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) { setindex = index; - enable = 1; + encode_alg = IW_ENCODE_ALG_WEP; } } else { /* Important note : if the user do "iwconfig eth0 enc off", @@ -3063,7 +4010,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, } if (erq->flags & IW_ENCODE_DISABLED) - enable = 0; + encode_alg = IW_ENCODE_ALG_NONE; if (erq->flags & IW_ENCODE_OPEN) restricted = 0; if (erq->flags & IW_ENCODE_RESTRICTED) @@ -3078,14 +4025,15 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, priv->tx_key = setindex; /* Try fast key change if connected and only keys are changed */ - if (priv->wep_on && enable && (priv->wep_restrict == restricted) && + if ((priv->encode_alg == encode_alg) && + (priv->wep_restrict == restricted) && netif_carrier_ok(dev)) { err = __orinoco_hw_setup_wepkeys(priv); /* No need to commit if successful */ goto out; } - priv->wep_on = enable; + priv->encode_alg = encode_alg; priv->wep_restrict = restricted; out: @@ -3114,7 +4062,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, index = priv->tx_key; erq->flags = 0; - if (! priv->wep_on) + if (!priv->encode_alg) erq->flags |= IW_ENCODE_DISABLED; erq->flags |= index + 1; @@ -3689,6 +4637,399 @@ static int orinoco_ioctl_getpower(struct net_device *dev, return err; } +static int orinoco_ioctl_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int idx, alg = ext->alg, set_key = 1; + unsigned long flags; + int err = -EINVAL; + u16 key_len; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + /* Determine and validate the key index */ + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if ((idx < 1) || (idx > WEP_KEYS)) + goto out; + idx--; + } else + idx = priv->tx_key; + + if (encoding->flags & IW_ENCODE_DISABLED) + alg = IW_ENCODE_ALG_NONE; + + if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { + /* Clear any TKIP TX key we had */ + (void) orinoco_clear_tkip_key(priv, priv->tx_key); + } + + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + priv->tx_key = idx; + set_key = ((alg == IW_ENCODE_ALG_TKIP) || + (ext->key_len > 0)) ? 1 : 0; + } + + if (set_key) { + /* Set the requested key first */ + switch (alg) { + case IW_ENCODE_ALG_NONE: + priv->encode_alg = alg; + priv->keys[idx].len = 0; + break; + + case IW_ENCODE_ALG_WEP: + if (ext->key_len > SMALL_KEY_SIZE) + key_len = LARGE_KEY_SIZE; + else if (ext->key_len > 0) + key_len = SMALL_KEY_SIZE; + else + goto out; + + priv->encode_alg = alg; + priv->keys[idx].len = cpu_to_le16(key_len); + + key_len = min(ext->key_len, key_len); + + memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); + memcpy(priv->keys[idx].data, ext->key, key_len); + break; + + case IW_ENCODE_ALG_TKIP: + { + hermes_t *hw = &priv->hw; + u8 *tkip_iv = NULL; + + if (!priv->has_wpa || + (ext->key_len > sizeof(priv->tkip_key[0]))) + goto out; + + priv->encode_alg = alg; + memset(&priv->tkip_key[idx], 0, + sizeof(priv->tkip_key[idx])); + memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); + + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) + tkip_iv = &ext->rx_seq[0]; + + err = __orinoco_hw_set_tkip_key(hw, idx, + ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, + (u8 *) &priv->tkip_key[idx], + tkip_iv, NULL); + if (err) + printk(KERN_ERR "%s: Error %d setting TKIP key" + "\n", dev->name, err); + + goto out; + } + default: + goto out; + } + } + err = -EINPROGRESS; + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int idx, max_key_len; + unsigned long flags; + int err; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + err = -EINVAL; + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + goto out; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if ((idx < 1) || (idx > WEP_KEYS)) + goto out; + idx--; + } else + idx = priv->tx_key; + + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + ext->alg = priv->encode_alg; + switch (priv->encode_alg) { + case IW_ENCODE_ALG_NONE: + ext->key_len = 0; + encoding->flags |= IW_ENCODE_DISABLED; + break; + case IW_ENCODE_ALG_WEP: + ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), + max_key_len); + memcpy(ext->key, priv->keys[idx].data, ext->key_len); + encoding->flags |= IW_ENCODE_ENABLED; + break; + case IW_ENCODE_ALG_TKIP: + ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), + max_key_len); + memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); + encoding->flags |= IW_ENCODE_ENABLED; + break; + } + + err = 0; + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + struct iw_param *param = &wrqu->param; + unsigned long flags; + int ret = -EINPROGRESS; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_PRIVACY_INVOKED: + case IW_AUTH_DROP_UNENCRYPTED: + /* + * orinoco does not use these parameters + */ + break; + + case IW_AUTH_KEY_MGMT: + /* wl_lkm implies value 2 == PSK for Hermes I + * which ties in with WEXT + * no other hints tho :( + */ + priv->key_mgmt = param->value; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + /* When countermeasures are enabled, shut down the + * card; when disabled, re-enable the card. This must + * take effect immediately. + * + * TODO: Make sure that the EAPOL message is getting + * out before card disabled + */ + if (param->value) { + priv->tkip_cm_active = 1; + ret = hermes_enable_port(hw, 0); + } else { + priv->tkip_cm_active = 0; + ret = hermes_disable_port(hw, 0); + } + break; + + case IW_AUTH_80211_AUTH_ALG: + if (param->value & IW_AUTH_ALG_SHARED_KEY) + priv->wep_restrict = 1; + else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) + priv->wep_restrict = 0; + else + ret = -EINVAL; + break; + + case IW_AUTH_WPA_ENABLED: + if (priv->has_wpa) { + priv->wpa_enabled = param->value ? 1 : 0; + } else { + if (param->value) + ret = -EOPNOTSUPP; + /* else silently accept disable of WPA */ + priv->wpa_enabled = 0; + } + break; + + default: + ret = -EOPNOTSUPP; + } + + orinoco_unlock(priv, &flags); + return ret; +} + +static int orinoco_ioctl_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct iw_param *param = &wrqu->param; + unsigned long flags; + int ret = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_KEY_MGMT: + param->value = priv->key_mgmt; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + param->value = priv->tkip_cm_active; + break; + + case IW_AUTH_80211_AUTH_ALG: + if (priv->wep_restrict) + param->value = IW_AUTH_ALG_SHARED_KEY; + else + param->value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + + case IW_AUTH_WPA_ENABLED: + param->value = priv->wpa_enabled; + break; + + default: + ret = -EOPNOTSUPP; + } + + orinoco_unlock(priv, &flags); + return ret; +} + +static int orinoco_ioctl_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + u8 *buf; + unsigned long flags; + int err = 0; + + if ((wrqu->data.length > MAX_WPA_IE_LEN) || + (wrqu->data.length && (extra == NULL))) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if (wrqu->data.length) { + buf = kmalloc(wrqu->data.length, GFP_KERNEL); + if (buf == NULL) { + err = -ENOMEM; + goto out; + } + + memcpy(buf, extra, wrqu->data.length); + kfree(priv->wpa_ie); + priv->wpa_ie = buf; + priv->wpa_ie_len = wrqu->data.length; + } else { + kfree(priv->wpa_ie); + priv->wpa_ie = NULL; + priv->wpa_ie_len = 0; + } + + if (priv->wpa_ie) { + /* Looks like wl_lkm wants to check the auth alg, and + * somehow pass it to the firmware. + * Instead it just calls the key mgmt rid + * - we do this in set auth. + */ + } + +out: + orinoco_unlock(priv, &flags); + return err; +} + +static int orinoco_ioctl_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { + wrqu->data.length = 0; + goto out; + } + + if (wrqu->data.length < priv->wpa_ie_len) { + err = -E2BIG; + goto out; + } + + wrqu->data.length = priv->wpa_ie_len; + memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); + +out: + orinoco_unlock(priv, &flags); + return err; +} + +static int orinoco_ioctl_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + struct iw_mlme *mlme = (struct iw_mlme *)extra; + unsigned long flags; + int ret = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + /* silently ignore */ + break; + + case IW_MLME_DISASSOC: + { + struct { + u8 addr[ETH_ALEN]; + __le16 reason_code; + } __attribute__ ((packed)) buf; + + memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); + buf.reason_code = cpu_to_le16(mlme->reason_code); + ret = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFDISASSOCIATE, + &buf); + break; + } + default: + ret = -EOPNOTSUPP; + } + + orinoco_unlock(priv, &flags); + return ret; +} + static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, @@ -3947,14 +5288,15 @@ static int orinoco_ioctl_getrid(struct net_device *dev, return err; } -/* Trigger a scan (look for other cells in the vicinity */ +/* Trigger a scan (look for other cells in the vicinity) */ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *srq, + struct iw_point *srq, char *extra) { struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; + struct iw_scan_req *si = (struct iw_scan_req *) extra; int err = 0; unsigned long flags; @@ -3986,7 +5328,6 @@ static int orinoco_ioctl_setscan(struct net_device *dev, * we access scan variables in priv is critical. * o scan_inprogress : not touched by irq handler * o scan_mode : not touched by irq handler - * o scan_len : synchronised with scan_result * Before modifying anything on those variables, please think hard ! * Jean II */ @@ -4016,13 +5357,43 @@ static int orinoco_ioctl_setscan(struct net_device *dev, } break; case FIRMWARE_TYPE_AGERE: - err = hermes_write_wordrec(hw, USER_BAP, + if (priv->scan_mode & IW_SCAN_THIS_ESSID) { + struct hermes_idstring idbuf; + size_t len = min(sizeof(idbuf.val), + (size_t) si->essid_len); + idbuf.len = cpu_to_le16(len); + memcpy(idbuf.val, si->essid, len); + + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFSCANSSID_AGERE, + HERMES_BYTES_TO_RECLEN(len + 2), + &idbuf); + } else + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSCANSSID_AGERE, 0); /* Any ESSID */ if (err) break; - err = hermes_inquire(hw, HERMES_INQ_SCAN); + if (priv->has_ext_scan) { + /* Clear scan results at the start of + * an extended scan */ + orinoco_clear_scan_results(priv, + msecs_to_jiffies(15000)); + + /* TODO: Is this available on older firmware? + * Can we use it to scan specific channels + * for IW_SCAN_THIS_FREQ? */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSCANCHANNELS2GHZ, + 0x7FFF); + if (err) + goto out; + + err = hermes_inquire(hw, + HERMES_INQ_CHANNELINFO); + } else + err = hermes_inquire(hw, HERMES_INQ_SCAN); break; } } else @@ -4040,8 +5411,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, #define MAX_CUSTOM_LEN 64 /* Translate scan data returned from the card to a card independant - * format that the Wireless Tools will understand - Jean II - * Return message length or -errno for fatal errors */ + * format that the Wireless Tools will understand - Jean II */ static inline char *orinoco_translate_scan(struct net_device *dev, struct iw_request_info *info, char *current_ev, @@ -4053,9 +5423,10 @@ static inline char *orinoco_translate_scan(struct net_device *dev, u16 capabilities; u16 channel; struct iw_event iwe; /* Temporary buffer */ - char *p; char custom[MAX_CUSTOM_LEN]; + memset(&iwe, 0, sizeof(iwe)); + /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; @@ -4077,8 +5448,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev, /* Add mode */ iwe.cmd = SIOCGIWMODE; capabilities = le16_to_cpu(bss->a.capabilities); - if (capabilities & 0x3) { - if (capabilities & 0x1) + if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + if (capabilities & WLAN_CAPABILITY_ESS) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; @@ -4088,17 +5459,22 @@ static inline char *orinoco_translate_scan(struct net_device *dev, channel = bss->s.channel; if ((channel >= 1) && (channel <= NUM_CHANNELS)) { - /* Add frequency */ + /* Add channel and frequency */ iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = channel; + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + iwe.u.freq.m = channel_frequency[channel-1] * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } - /* Add quality statistics */ + /* Add quality statistics. level and noise in dB. No link quality */ iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = 0x10; /* no link quality */ + iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95; iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95; /* Wireless tools prior to 27.pre22 will show link quality @@ -4112,25 +5488,13 @@ static inline char *orinoco_translate_scan(struct net_device *dev, /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; - if (capabilities & 0x10) + if (capabilities & WLAN_CAPABILITY_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->a.essid); - - /* Add EXTRA: Age to display seconds since last beacon/probe response - * for given network. */ - iwe.cmd = IWEVCUSTOM; - p = custom; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), - " Last beacon: %dms ago", - jiffies_to_msecs(jiffies - last_scanned)); - iwe.u.data.length = p - custom; - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); + &iwe, NULL); /* Bit rate is not available in Lucent/Agere firmwares */ if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { @@ -4152,7 +5516,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev, if (bss->p.rates[i] == 0x0) break; /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000); + iwe.u.bitrate.value = + ((bss->p.rates[i] & 0x7f) * 500000); current_val = iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe, @@ -4163,6 +5528,199 @@ static inline char *orinoco_translate_scan(struct net_device *dev, current_ev = current_val; } + /* Beacon interval */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "bcn_int=%d", + le16_to_cpu(bss->a.beacon_interv)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Capabilites */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "capab=0x%04x", + capabilities); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - last_scanned)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + return current_ev; +} + +static inline char *orinoco_translate_ext_scan(struct net_device *dev, + struct iw_request_info *info, + char *current_ev, + char *end_buf, + struct agere_ext_scan_info *bss, + unsigned int last_scanned) +{ + u16 capabilities; + u16 channel; + struct iw_event iwe; /* Temporary buffer */ + char custom[MAX_CUSTOM_LEN]; + u8 *ie; + + memset(&iwe, 0, sizeof(iwe)); + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_ADDR_LEN); + + /* Other entries will be displayed in the order we give them */ + + /* Add the ESSID */ + ie = bss->data; + iwe.u.data.length = ie[1]; + if (iwe.u.data.length) { + if (iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, &ie[2]); + } + + /* Add mode */ + capabilities = le16_to_cpu(bss->capabilities); + if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + iwe.cmd = SIOCGIWMODE; + if (capabilities & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); + } + + ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET); + channel = ie ? ie[2] : 0; + if ((channel >= 1) && (channel <= NUM_CHANNELS)) { + /* Add channel and frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = channel; + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + + iwe.u.freq.m = channel_frequency[channel-1] * 100000; + iwe.u.freq.e = 1; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + } + + /* Add quality statistics. level and noise in dB. No link quality */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; + iwe.u.qual.level = bss->level - 0x95; + iwe.u.qual.noise = bss->noise - 0x95; + /* Wireless tools prior to 27.pre22 will show link quality + * anyway, so we provide a reasonable value. */ + if (iwe.u.qual.level > iwe.u.qual.noise) + iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; + else + iwe.u.qual.qual = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (capabilities & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, NULL); + + /* WPA IE */ + ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data)); + if (ie) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie[1] + 2; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ie); + } + + /* RSN IE */ + ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN); + if (ie) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie[1] + 2; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ie); + } + + ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES); + if (ie) { + char *p = current_ev + iwe_stream_lcp_len(info); + int i; + + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + + for (i = 2; i < (ie[1] + 2); i++) { + iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000); + p = iwe_stream_add_value(info, current_ev, p, end_buf, + &iwe, IW_EV_PARAM_LEN); + } + /* Check if we added any event */ + if (p > (current_ev + iwe_stream_lcp_len(info))) + current_ev = p; + } + + /* Timestamp */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = + snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx", + (unsigned long long) le64_to_cpu(bss->timestamp)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Beacon interval */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "bcn_int=%d", + le16_to_cpu(bss->beacon_interval)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Capabilites */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "capab=0x%04x", + capabilities); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - last_scanned)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + return current_ev; } @@ -4173,7 +5731,6 @@ static int orinoco_ioctl_getscan(struct net_device *dev, char *extra) { struct orinoco_private *priv = netdev_priv(dev); - bss_element *bss; int err = 0; unsigned long flags; char *current_ev = extra; @@ -4193,18 +5750,47 @@ static int orinoco_ioctl_getscan(struct net_device *dev, goto out; } - list_for_each_entry(bss, &priv->bss_list, list) { - /* Translate to WE format this entry */ - current_ev = orinoco_translate_scan(dev, info, current_ev, - extra + srq->length, - &bss->bss, - bss->last_scanned); - - /* Check if there is space for one more entry */ - if ((extra + srq->length - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - err = -E2BIG; - goto out; + if (priv->has_ext_scan) { + struct xbss_element *bss; + + list_for_each_entry(bss, &priv->bss_list, list) { + /* Translate this entry to WE format */ + current_ev = + orinoco_translate_ext_scan(dev, info, + current_ev, + extra + srq->length, + &bss->bss, + bss->last_scanned); + + /* Check if there is space for one more entry */ + if ((extra + srq->length - current_ev) + <= IW_EV_ADDR_LEN) { + /* Ask user space to try again with a + * bigger buffer */ + err = -E2BIG; + goto out; + } + } + + } else { + struct bss_element *bss; + + list_for_each_entry(bss, &priv->bss_list, list) { + /* Translate this entry to WE format */ + current_ev = orinoco_translate_scan(dev, info, + current_ev, + extra + srq->length, + &bss->bss, + bss->last_scanned); + + /* Check if there is space for one more entry */ + if ((extra + srq->length - current_ev) + <= IW_EV_ADDR_LEN) { + /* Ask user space to try again with a + * bigger buffer */ + err = -E2BIG; + goto out; + } } } @@ -4295,39 +5881,48 @@ static const struct iw_priv_args orinoco_privtab[] = { * Structures to export the Wireless Handlers */ +#define STD_IW_HANDLER(id, func) \ + [IW_IOCTL_IDX(id)] = (iw_handler) func static const iw_handler orinoco_handler[] = { - [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_commit, - [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getname, - [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfreq, - [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfreq, - [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setmode, - [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getmode, - [SIOCSIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setsens, - [SIOCGIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getsens, - [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwrange, - [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy, - [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy, - [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy, - [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy, - [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap, - [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap, - [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan, - [SIOCGIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getscan, - [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setessid, - [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getessid, - [SIOCSIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setnick, - [SIOCGIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getnick, - [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrate, - [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrate, - [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrts, - [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrts, - [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfrag, - [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfrag, - [SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getretry, - [SIOCSIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setiwencode, - [SIOCGIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwencode, - [SIOCSIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setpower, - [SIOCGIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getpower, + STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), + STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname), + STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), + STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), + STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode), + STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode), + STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), + STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), + STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange), + STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), + STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), + STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), + STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), + STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), + STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), + STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan), + STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan), + STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), + STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), + STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), + STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick), + STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), + STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), + STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts), + STD_IW_HANDLER(SIOCGIWRTS, orinoco_ioctl_getrts), + STD_IW_HANDLER(SIOCSIWFRAG, orinoco_ioctl_setfrag), + STD_IW_HANDLER(SIOCGIWFRAG, orinoco_ioctl_getfrag), + STD_IW_HANDLER(SIOCGIWRETRY, orinoco_ioctl_getretry), + STD_IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode), + STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), + STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), + STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), + STD_IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), + STD_IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), + STD_IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), + STD_IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), + STD_IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), + STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), + STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), }; diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index c6b1858abde..981570bd3b9 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -9,6 +9,7 @@ #define DRIVER_VERSION "0.15" +#include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/wireless.h> #include <net/iw_handler.h> @@ -30,27 +31,57 @@ struct orinoco_key { char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); +#define TKIP_KEYLEN 16 +#define MIC_KEYLEN 8 + +struct orinoco_tkip_key { + u8 tkip[TKIP_KEYLEN]; + u8 tx_mic[MIC_KEYLEN]; + u8 rx_mic[MIC_KEYLEN]; +}; + typedef enum { FIRMWARE_TYPE_AGERE, FIRMWARE_TYPE_INTERSIL, FIRMWARE_TYPE_SYMBOL } fwtype_t; -typedef struct { +struct bss_element { union hermes_scan_info bss; unsigned long last_scanned; struct list_head list; -} bss_element; +}; + +struct xbss_element { + struct agere_ext_scan_info bss; + unsigned long last_scanned; + struct list_head list; +}; + +struct hermes_rx_descriptor; + +struct orinoco_rx_data { + struct hermes_rx_descriptor *desc; + struct sk_buff *skb; + struct list_head list; +}; struct orinoco_private { void *card; /* Pointer to card dependent structure */ + struct device *dev; int (*hard_reset)(struct orinoco_private *); + int (*stop_fw)(struct orinoco_private *, int); /* Synchronisation stuff */ spinlock_t lock; int hw_unavailable; struct work_struct reset_work; + /* Interrupt tasklets */ + struct tasklet_struct rx_tasklet; + struct list_head rx_list; + struct orinoco_rx_data *rx_data; + /* driver state */ int open; u16 last_linkstatus; @@ -83,13 +114,17 @@ struct orinoco_private { unsigned int has_preamble:1; unsigned int has_sensitivity:1; unsigned int has_hostscan:1; + unsigned int has_alt_txcntl:1; + unsigned int has_ext_scan:1; + unsigned int has_wpa:1; + unsigned int do_fw_download:1; unsigned int broken_disableport:1; unsigned int broken_monitor:1; /* Configuration paramaters */ u32 iw_mode; int prefer_port3; - u16 wep_on, wep_restrict, tx_key; + u16 encode_alg, wep_restrict, tx_key; struct orinoco_key keys[ORINOCO_MAX_KEYS]; int bitratemode; char nick[IW_ESSID_MAX_SIZE+1]; @@ -113,10 +148,22 @@ struct orinoco_private { /* Scanning support */ struct list_head bss_list; struct list_head bss_free_list; - bss_element *bss_data; + void *bss_xbss_data; int scan_inprogress; /* Scan pending... */ u32 scan_mode; /* Type of scan done */ + + /* WPA support */ + u8 *wpa_ie; + int wpa_ie_len; + + struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS]; + struct crypto_hash *rx_tfm_mic; + struct crypto_hash *tx_tfm_mic; + + unsigned int wpa_enabled:1; + unsigned int tkip_cm_active:1; + unsigned int key_mgmt:3; }; #ifdef ORINOCO_DEBUG @@ -130,8 +177,10 @@ extern int orinoco_debug; /* Exported prototypes */ /********************************************************************/ -extern struct net_device *alloc_orinocodev(int sizeof_card, - int (*hard_reset)(struct orinoco_private *)); +extern struct net_device *alloc_orinocodev( + int sizeof_card, struct device *device, + int (*hard_reset)(struct orinoco_private *), + int (*stop_fw)(struct orinoco_private *, int)); extern void free_orinocodev(struct net_device *dev); extern int __orinoco_up(struct net_device *dev); extern int __orinoco_down(struct net_device *dev); diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 1c216e015f6..6fcf2bda7cd 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -80,7 +80,7 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) /* We need atomic ops here, because we're not holding the lock */ set_bit(0, &card->hard_reset_in_progress); - err = pcmcia_reset_card(link, NULL); + err = pcmcia_reset_card(link->socket); if (err) return err; @@ -109,7 +109,8 @@ orinoco_cs_probe(struct pcmcia_device *link) struct orinoco_private *priv; struct orinoco_pccard *card; - dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); + dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + orinoco_cs_hard_reset, NULL); if (! dev) return -ENOMEM; priv = netdev_priv(dev); @@ -120,7 +121,7 @@ orinoco_cs_probe(struct pcmcia_device *link) link->priv = dev; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = orinoco_interrupt; link->irq.Instance = dev; @@ -164,6 +165,70 @@ static void orinoco_cs_detach(struct pcmcia_device *link) last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ } while (0) +static int orinoco_cs_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->index == 0) + goto next_entry; + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* Do we need to allocate an interrupt? */ + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + goto next_entry; + } + return 0; + +next_entry: + pcmcia_disable_device(p_dev); + return -ENODEV; +}; + static int orinoco_cs_config(struct pcmcia_device *link) { @@ -172,16 +237,8 @@ orinoco_cs_config(struct pcmcia_device *link) struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; int last_fn, last_ret; - u_char buf[64]; - config_info_t conf; - tuple_t tuple; - cisparse_t parse; void __iomem *mem; - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link, &conf)); - /* * In this loop, we scan the CIS for configuration table * entries, each of which describes a valid card @@ -196,94 +253,14 @@ orinoco_cs_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - cistpl_cftable_entry_t dflt = { .index = 0 }; - - if ( (pcmcia_get_tuple_data(link, &tuple) != 0) - || (pcmcia_parse_tuple(link, &tuple, &parse) != 0)) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, cfg CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, dflt CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); - if(!ignore_cis_vcc) - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = - (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = - io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = - link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - } - - - /* If we got this far, we're cool! */ - - break; - - next_entry: - pcmcia_disable_device(link); - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret == CS_NO_MORE_ITEMS) { + last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); + if (last_ret) { + if (!ignore_cis_vcc) printk(KERN_ERR PFX "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " "ignore_cis_vcc=1 parameter.\n"); - goto cs_failed; - } + cs_error(link, RequestIO, last_ret); + goto failed; } /* @@ -334,7 +311,6 @@ orinoco_cs_config(struct pcmcia_device *link) "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); - return 0; cs_failed: @@ -402,6 +378,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link) struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; int err = 0; + unsigned long flags; if (! test_bit(0, &card->hard_reset_in_progress)) { err = orinoco_reinit_firmware(dev); @@ -411,7 +388,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link) return -EIO; } - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); netif_device_attach(dev); priv->hw_unavailable--; @@ -423,7 +400,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link) dev->name, err); } - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); } return err; diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c index 35ec5fcf81a..2fc86596302 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco_nortel.c @@ -182,7 +182,8 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), orinoco_nortel_cor_reset); + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_nortel_cor_reset, NULL); if (!dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 2547d5dac0d..4ebd638a073 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -139,7 +139,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset); + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_pci_cor_reset, NULL); if (!dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 98fe165337d..ef761857bb3 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -221,7 +221,8 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), orinoco_plx_cor_reset); + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_plx_cor_reset, NULL); if (!dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index df493185a4a..ede24ec309c 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -124,7 +124,8 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset); + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_tmd_cor_reset, NULL); if (!dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 4801a363507..1d0704fe146 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -1,5 +1,5 @@ -#ifndef PRISM54_H -#define PRISM54_H +#ifndef P54_H +#define P54_H /* * Shared defines for all mac80211 Prism54 code @@ -19,13 +19,24 @@ enum control_frame_types { P54_CONTROL_TYPE_CHANNEL_CHANGE, P54_CONTROL_TYPE_FREQDONE, P54_CONTROL_TYPE_DCFINIT, - P54_CONTROL_TYPE_FREEQUEUE = 7, + P54_CONTROL_TYPE_ENCRYPTION, + P54_CONTROL_TYPE_TIM, + P54_CONTROL_TYPE_POWERMGT, + P54_CONTROL_TYPE_FREEQUEUE, P54_CONTROL_TYPE_TXDONE, P54_CONTROL_TYPE_PING, P54_CONTROL_TYPE_STAT_READBACK, P54_CONTROL_TYPE_BBP, P54_CONTROL_TYPE_EEPROM_READBACK, - P54_CONTROL_TYPE_LED + P54_CONTROL_TYPE_LED, + P54_CONTROL_TYPE_GPIO, + P54_CONTROL_TYPE_TIMER, + P54_CONTROL_TYPE_MODULATION, + P54_CONTROL_TYPE_SYNTH_CONFIG, + P54_CONTROL_TYPE_DETECTOR_VALUE, + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + P54_CONTROL_TYPE_CCE_QUIET, + P54_CONTROL_TYPE_PSM_STA_UNLOCK, }; struct p54_control_hdr { @@ -38,11 +49,15 @@ struct p54_control_hdr { u8 data[0]; } __attribute__ ((packed)); -#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */) -#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 ) +#define EEPROM_READBACK_LEN 0x3fc #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 +#define FW_FMAC 0x464d4143 +#define FW_LM86 0x4c4d3836 +#define FW_LM87 0x4c4d3837 +#define FW_LM20 0x4c4d3230 + struct p54_common { u32 rx_start; u32 rx_end; @@ -53,27 +68,43 @@ struct p54_common { void (*stop)(struct ieee80211_hw *dev); int mode; u16 seqno; + u16 rx_mtu; + u8 headroom; + u8 tailroom; struct mutex conf_mutex; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; + __le16 filter_type; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; unsigned int output_limit_len; struct pda_pa_curve_data *curve_data; - __le16 rxhw; + unsigned int filter_flags; + u16 rxhw; u8 version; + u8 rx_antenna; unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; - struct ieee80211_tx_queue_stats tx_stats[4]; + unsigned int fw_interface; + unsigned int output_power; + u32 tsf_low32; + u32 tsf_high32; + struct ieee80211_tx_queue_stats tx_stats[8]; + struct ieee80211_low_level_stats stats; + struct timer_list stats_timer; + struct completion stats_comp; + void *cached_stats; + int noise; + void *eeprom; + struct completion eeprom_comp; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); -void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); -int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len); -void p54_fill_eeprom_readback(struct p54_control_hdr *hdr); +int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); +int p54_read_eeprom(struct ieee80211_hw *dev); struct ieee80211_hw *p54_init_common(size_t priv_data_len); void p54_free_common(struct ieee80211_hw *dev); -#endif /* PRISM54_H */ +#endif /* P54_H */ diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 29be3dc8ee0..117c7d3a52b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54common"); -static struct ieee80211_rate p54_rates[] = { +static struct ieee80211_rate p54_bgrates[] = { { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, @@ -42,7 +42,7 @@ static struct ieee80211_rate p54_rates[] = { { .bitrate = 540, .hw_value = 11, }, }; -static struct ieee80211_channel p54_channels[] = { +static struct ieee80211_channel p54_bgchannels[] = { { .center_freq = 2412, .hw_value = 1, }, { .center_freq = 2417, .hw_value = 2, }, { .center_freq = 2422, .hw_value = 3, }, @@ -60,14 +60,69 @@ static struct ieee80211_channel p54_channels[] = { }; static struct ieee80211_supported_band band_2GHz = { - .channels = p54_channels, - .n_channels = ARRAY_SIZE(p54_channels), - .bitrates = p54_rates, - .n_bitrates = ARRAY_SIZE(p54_rates), + .channels = p54_bgchannels, + .n_channels = ARRAY_SIZE(p54_bgchannels), + .bitrates = p54_bgrates, + .n_bitrates = ARRAY_SIZE(p54_bgrates), }; +static struct ieee80211_rate p54_arates[] = { + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static struct ieee80211_channel p54_achannels[] = { + { .center_freq = 4920 }, + { .center_freq = 4940 }, + { .center_freq = 4960 }, + { .center_freq = 4980 }, + { .center_freq = 5040 }, + { .center_freq = 5060 }, + { .center_freq = 5080 }, + { .center_freq = 5170 }, + { .center_freq = 5180 }, + { .center_freq = 5190 }, + { .center_freq = 5200 }, + { .center_freq = 5210 }, + { .center_freq = 5220 }, + { .center_freq = 5230 }, + { .center_freq = 5240 }, + { .center_freq = 5260 }, + { .center_freq = 5280 }, + { .center_freq = 5300 }, + { .center_freq = 5320 }, + { .center_freq = 5500 }, + { .center_freq = 5520 }, + { .center_freq = 5540 }, + { .center_freq = 5560 }, + { .center_freq = 5580 }, + { .center_freq = 5600 }, + { .center_freq = 5620 }, + { .center_freq = 5640 }, + { .center_freq = 5660 }, + { .center_freq = 5680 }, + { .center_freq = 5700 }, + { .center_freq = 5745 }, + { .center_freq = 5765 }, + { .center_freq = 5785 }, + { .center_freq = 5805 }, + { .center_freq = 5825 }, +}; + +static struct ieee80211_supported_band band_5GHz = { + .channels = p54_achannels, + .n_channels = ARRAY_SIZE(p54_achannels), + .bitrates = p54_arates, + .n_bitrates = ARRAY_SIZE(p54_arates), +}; -void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) +int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) { struct p54_common *priv = dev->priv; struct bootrec_exp_if *exp_if; @@ -79,7 +134,7 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) int i; if (priv->rx_start) - return; + return 0; while (data < end_data && *data) data++; @@ -94,7 +149,9 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) u32 code = le32_to_cpu(bootrec->code); switch (code) { case BR_CODE_COMPONENT_ID: - switch (be32_to_cpu(*(__be32 *)bootrec->data)) { + priv->fw_interface = be32_to_cpup((__be32 *) + bootrec->data); + switch (priv->fw_interface) { case FW_FMAC: printk(KERN_INFO "p54: FreeMAC firmware\n"); break; @@ -105,7 +162,7 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) printk(KERN_INFO "p54: LM86 firmware\n"); break; case FW_LM87: - printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n"); + printk(KERN_INFO "p54: LM87 firmware\n"); break; default: printk(KERN_INFO "p54: unknown firmware\n"); @@ -117,11 +174,21 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (strnlen((unsigned char*)bootrec->data, 24) < 24) fw_version = (unsigned char*)bootrec->data; break; - case BR_CODE_DESCR: - priv->rx_start = le32_to_cpu(((__le32 *)bootrec->data)[1]); + case BR_CODE_DESCR: { + struct bootrec_desc *desc = + (struct bootrec_desc *)bootrec->data; + priv->rx_start = le32_to_cpu(desc->rx_start); /* FIXME add sanity checking */ - priv->rx_end = le32_to_cpu(((__le32 *)bootrec->data)[2]) - 0x3500; + priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; + priv->headroom = desc->headroom; + priv->tailroom = desc->tailroom; + if (le32_to_cpu(bootrec->len) == 11) + priv->rx_mtu = le16_to_cpu(bootrec->rx_mtu); + else + priv->rx_mtu = (size_t) + 0x620 - priv->tx_hdr_len; break; + } case BR_CODE_EXPOSED_IF: exp_if = (struct bootrec_exp_if *) bootrec->data; for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) @@ -146,23 +213,25 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ - priv->tx_stats[0].limit = 3; - priv->tx_stats[1].limit = 4; - priv->tx_stats[2].limit = 3; - priv->tx_stats[3].limit = 1; + priv->tx_stats[4].limit = 3; + priv->tx_stats[5].limit = 4; + priv->tx_stats[6].limit = 3; + priv->tx_stats[7].limit = 1; dev->queues = 4; } + + return 0; } EXPORT_SYMBOL_GPL(p54_parse_firmware); -static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) +static int p54_convert_rev0(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) { struct p54_common *priv = dev->priv; - struct pda_pa_curve_data_sample_rev1 *rev1; - struct pda_pa_curve_data_sample_rev0 *rev0; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev0 *src; size_t cd_len = sizeof(*curve_data) + - (curve_data->points_per_channel*sizeof(*rev1) + 2) * + (curve_data->points_per_channel*sizeof(*dst) + 2) * curve_data->channels; unsigned int i, j; void *source, *target; @@ -180,28 +249,68 @@ static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev, *((__le16 *)target) = *freq; target += sizeof(__le16); for (j = 0; j < curve_data->points_per_channel; j++) { - rev1 = target; - rev0 = source; + dst = target; + src = source; - rev1->rf_power = rev0->rf_power; - rev1->pa_detector = rev0->pa_detector; - rev1->data_64qam = rev0->pcv; + dst->rf_power = src->rf_power; + dst->pa_detector = src->pa_detector; + dst->data_64qam = src->pcv; /* "invent" the points for the other modulations */ #define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y) - rev1->data_16qam = SUB(rev0->pcv, 12); - rev1->data_qpsk = SUB(rev1->data_16qam, 12); - rev1->data_bpsk = SUB(rev1->data_qpsk, 12); - rev1->data_barker= SUB(rev1->data_bpsk, 14); + dst->data_16qam = SUB(src->pcv, 12); + dst->data_qpsk = SUB(dst->data_16qam, 12); + dst->data_bpsk = SUB(dst->data_qpsk, 12); + dst->data_barker = SUB(dst->data_bpsk, 14); #undef SUB - target += sizeof(*rev1); - source += sizeof(*rev0); + target += sizeof(*dst); + source += sizeof(*src); } } return 0; } -int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) +static int p54_convert_rev1(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) +{ + struct p54_common *priv = dev->priv; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev1 *src; + size_t cd_len = sizeof(*curve_data) + + (curve_data->points_per_channel*sizeof(*dst) + 2) * + curve_data->channels; + unsigned int i, j; + void *source, *target; + + priv->curve_data = kmalloc(cd_len, GFP_KERNEL); + if (!priv->curve_data) + return -ENOMEM; + + memcpy(priv->curve_data, curve_data, sizeof(*curve_data)); + source = curve_data->data; + target = priv->curve_data->data; + for (i = 0; i < curve_data->channels; i++) { + __le16 *freq = source; + source += sizeof(__le16); + *((__le16 *)target) = *freq; + target += sizeof(__le16); + for (j = 0; j < curve_data->points_per_channel; j++) { + memcpy(target, source, sizeof(*src)); + + target += sizeof(*dst); + source += sizeof(*src); + } + source++; + } + + return 0; +} + +static const char *p54_rf_chips[] = { "NULL", "Indigo?", "Duette", + "Frisbee", "Xbow", "Longbow" }; +static int p54_init_xbow_synth(struct ieee80211_hw *dev); + +static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; struct eeprom_pda_wrap *wrap = NULL; @@ -210,6 +319,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) void *tmp; int err; u8 *end = (u8 *)eeprom + len; + DECLARE_MAC_BUF(mac); wrap = (struct eeprom_pda_wrap *) eeprom; entry = (void *)wrap->data + le16_to_cpu(wrap->len); @@ -250,27 +360,32 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) entry->data[1]*sizeof(*priv->output_limit)); priv->output_limit_len = entry->data[1]; break; - case PDR_PRISM_PA_CAL_CURVE_DATA: - if (data_len < sizeof(struct pda_pa_curve_data)) { + case PDR_PRISM_PA_CAL_CURVE_DATA: { + struct pda_pa_curve_data *curve_data = + (struct pda_pa_curve_data *)entry->data; + if (data_len < sizeof(*curve_data)) { err = -EINVAL; goto err; } - if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) { - priv->curve_data = kmalloc(data_len, GFP_KERNEL); - if (!priv->curve_data) { - err = -ENOMEM; - goto err; - } - - memcpy(priv->curve_data, entry->data, data_len); - } else { - err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data); - if (err) - goto err; + switch (curve_data->cal_method_rev) { + case 0: + err = p54_convert_rev0(dev, curve_data); + break; + case 1: + err = p54_convert_rev1(dev, curve_data); + break; + default: + printk(KERN_ERR "p54: unknown curve data " + "revision %d\n", + curve_data->cal_method_rev); + err = -ENODEV; + break; } + if (err) + goto err; - break; + } case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); if (!priv->iq_autocal) { @@ -286,7 +401,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) while ((u8 *)tmp < entry->data + data_len) { struct bootrec_exp_if *exp_if = tmp; if (le16_to_cpu(exp_if->if_id) == 0xF) - priv->rxhw = exp_if->variant & cpu_to_le16(0x07); + priv->rxhw = le16_to_cpu(exp_if->variant) & 0x07; tmp += sizeof(struct bootrec_exp_if); } break; @@ -312,6 +427,37 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) goto err; } + switch (priv->rxhw) { + case 4: /* XBow */ + p54_init_xbow_synth(dev); + case 1: /* Indigo? */ + case 2: /* Duette */ + dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; + case 3: /* Frisbee */ + case 5: /* Longbow */ + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; + break; + default: + printk(KERN_ERR "%s: unsupported RF-Chip\n", + wiphy_name(dev->wiphy)); + err = -EINVAL; + goto err; + } + + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + u8 perm_addr[ETH_ALEN]; + + printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n", + wiphy_name(dev->wiphy)); + random_ether_addr(perm_addr); + SET_IEEE80211_PERM_ADDR(dev, perm_addr); + } + + printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n", + wiphy_name(dev->wiphy), + print_mac(mac, dev->wiphy->perm_addr), + priv->version, p54_rf_chips[priv->rxhw]); + return 0; err: @@ -333,42 +479,56 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) printk(KERN_ERR "p54: eeprom parse failed!\n"); return err; } -EXPORT_SYMBOL_GPL(p54_parse_eeprom); -void p54_fill_eeprom_readback(struct p54_control_hdr *hdr) +static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) { - struct p54_eeprom_lm86 *eeprom_hdr; - - hdr->magic1 = cpu_to_le16(0x8000); - hdr->len = cpu_to_le16(sizeof(*eeprom_hdr) + 0x2000); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK); - hdr->retry1 = hdr->retry2 = 0; - eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data; - eeprom_hdr->offset = 0x0; - eeprom_hdr->len = cpu_to_le16(0x2000); + /* TODO: get the rssi_add & rssi_mul data from the eeprom */ + return ((rssi * 0x83) / 64 - 400) / 4; } -EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback); -static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) +static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { + struct p54_common *priv = dev->priv; struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; struct ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); + size_t header_len = sizeof(*hdr); + u32 tsf32; + + if (!(hdr->magic & cpu_to_le16(0x0001))) { + if (priv->filter_flags & FIF_FCSFAIL) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + else + return 0; + } - rx_status.signal = hdr->rssi; + rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); + rx_status.noise = priv->noise; /* XX correct? */ rx_status.qual = (100 * hdr->rssi) / 127; - rx_status.rate_idx = hdr->rate & 0xf; + rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ? + hdr->rate : (hdr->rate - 4)) & 0xf; rx_status.freq = freq; - rx_status.band = IEEE80211_BAND_2GHZ; + rx_status.band = dev->conf.channel->band; rx_status.antenna = hdr->antenna; - rx_status.mactime = le64_to_cpu(hdr->timestamp); + + tsf32 = le32_to_cpu(hdr->tsf32); + if (tsf32 < priv->tsf_low32) + priv->tsf_high32++; + rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32; + priv->tsf_low32 = tsf32; + rx_status.flag |= RX_FLAG_TSFT; - skb_pull(skb, sizeof(*hdr)); + if (hdr->magic & cpu_to_le16(0x4000)) + header_len += hdr->align[0]; + + skb_pull(skb, header_len); skb_trim(skb, le16_to_cpu(hdr->len)); ieee80211_rx_irqsafe(dev, skb, &rx_status); + + return -1; } static void inline p54_wake_free_queues(struct ieee80211_hw *dev) @@ -377,7 +537,7 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) int i; for (i = 0; i < dev->queues; i++) - if (priv->tx_stats[i].len < priv->tx_stats[i].limit) + if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit) ieee80211_wake_queue(dev, i); } @@ -387,11 +547,13 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data; struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next; - u32 addr = le32_to_cpu(hdr->req_id) - 0x70; + u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; struct memrecord *range = NULL; u32 freed = 0; u32 last_addr = priv->rx_start; + unsigned long flags; + spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); range = (void *)info->driver_data; @@ -412,13 +574,15 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + memset(&info->status, 0, sizeof(info->status)); entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) pad = entry_data->align[0]; - priv->tx_stats[entry_data->hw_queue - 4].len--; + priv->tx_stats[entry_data->hw_queue].len--; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (!(payload->status & 0x01)) info->flags |= IEEE80211_TX_STAT_ACK; @@ -426,21 +590,60 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) info->status.excessive_retries = 1; } info->status.retry_count = payload->retries - 1; - info->status.ack_signal = le16_to_cpu(payload->ack_rssi); + info->status.ack_signal = p54_rssi_to_dbm(dev, + le16_to_cpu(payload->ack_rssi)); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); ieee80211_tx_status_irqsafe(dev, entry); - break; + goto out; } else last_addr = range->end_addr; entry = entry->next; } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); +out: if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 + sizeof(struct p54_control_hdr)) p54_wake_free_queues(dev); } -static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) +static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, + struct sk_buff *skb) +{ + struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; + struct p54_common *priv = dev->priv; + + if (!priv->eeprom) + return ; + + memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len)); + + complete(&priv->eeprom_comp); +} + +static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_statistics *stats = (struct p54_statistics *) hdr->data; + u32 tsf32 = le32_to_cpu(stats->tsf32); + + if (tsf32 < priv->tsf_low32) + priv->tsf_high32++; + priv->tsf_low32 = tsf32; + + priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail); + priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success); + priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); + + priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); + complete(&priv->stats_comp); + + mod_timer(&priv->stats_timer, jiffies + 5 * HZ); +} + +static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; @@ -450,36 +653,30 @@ static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) break; case P54_CONTROL_TYPE_BBP: break; + case P54_CONTROL_TYPE_STAT_READBACK: + p54_rx_stats(dev, skb); + break; + case P54_CONTROL_TYPE_EEPROM_READBACK: + p54_rx_eeprom_readback(dev, skb); + break; default: printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n", wiphy_name(dev->wiphy), le16_to_cpu(hdr->type)); break; } + + return 0; } /* returns zero if skb can be reused */ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) { u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8; - switch (type) { - case 0x00: - case 0x01: - p54_rx_data(dev, skb); - return -1; - case 0x4d: - /* TODO: do something better... but then again, I've never seen this happen */ - printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n", - wiphy_name(dev->wiphy)); - break; - case 0x80: - p54_rx_control(dev, skb); - break; - default: - printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n", - wiphy_name(dev->wiphy), type); - break; - } - return 0; + + if (type == 0x80) + return p54_rx_control(dev, skb); + else + return p54_rx_data(dev, skb); } EXPORT_SYMBOL_GPL(p54_rx); @@ -503,7 +700,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, u32 target_addr = priv->rx_start; unsigned long flags; unsigned int left; - len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */ + len = (len + priv->headroom + priv->tailroom + 3) & ~0x3; spin_lock_irqsave(&priv->tx_queue.lock, flags); left = skb_queue_len(&priv->tx_queue); @@ -538,14 +735,74 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, range->start_addr = target_addr; range->end_addr = target_addr + len; __skb_queue_after(&priv->tx_queue, target_skb, skb); - if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 + + if (largest_hole < priv->rx_mtu + priv->headroom + + priv->tailroom + sizeof(struct p54_control_hdr)) ieee80211_stop_queues(dev); } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - data->req_id = cpu_to_le32(target_addr + 0x70); + data->req_id = cpu_to_le32(target_addr + priv->headroom); +} + +int p54_read_eeprom(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr = NULL; + struct p54_eeprom_lm86 *eeprom_hdr; + size_t eeprom_size = 0x2020, offset = 0, blocksize; + int ret = -ENOMEM; + void *eeprom = NULL; + + hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) + + sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL); + if (!hdr) + goto free; + + priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL); + if (!priv->eeprom) + goto free; + + eeprom = kzalloc(eeprom_size, GFP_KERNEL); + if (!eeprom) + goto free; + + hdr->magic1 = cpu_to_le16(0x8000); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK); + hdr->retry1 = hdr->retry2 = 0; + eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data; + + while (eeprom_size) { + blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN); + hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr)); + eeprom_hdr->offset = cpu_to_le16(offset); + eeprom_hdr->len = cpu_to_le16(blocksize); + p54_assign_address(dev, NULL, hdr, le16_to_cpu(hdr->len) + + sizeof(*hdr)); + priv->tx(dev, hdr, le16_to_cpu(hdr->len) + sizeof(*hdr), 0); + + if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { + printk(KERN_ERR "%s: device does not respond!\n", + wiphy_name(dev->wiphy)); + ret = -EBUSY; + goto free; + } + + memcpy(eeprom + offset, priv->eeprom, blocksize); + offset += blocksize; + eeprom_size -= blocksize; + } + + ret = p54_parse_eeprom(dev, eeprom, offset); +free: + kfree(priv->eeprom); + priv->eeprom = NULL; + kfree(hdr); + kfree(eeprom); + + return ret; } +EXPORT_SYMBOL_GPL(p54_read_eeprom); static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { @@ -559,7 +816,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) u8 rate; u8 cts_rate = 0x20; - current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; @@ -601,7 +858,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; - txhdr->output_power = 0x7f; // HW Maximum + txhdr->output_power = priv->output_power; txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cts_rate; if (padding) @@ -628,12 +885,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) } static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, - const u8 *dst, const u8 *src, u8 antenna, - u32 magic3, u32 magic8, u32 magic9) + const u8 *bssid) { struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; struct p54_tx_control_filter *filter; + size_t data_len; hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + priv->tx_hdr_len, GFP_ATOMIC); @@ -644,25 +901,35 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, filter = (struct p54_tx_control_filter *) hdr->data; hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*filter)); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); - filter->filter_type = cpu_to_le16(filter_type); - memcpy(filter->dst, dst, ETH_ALEN); - if (!src) - memset(filter->src, ~0, ETH_ALEN); + priv->filter_type = filter->filter_type = cpu_to_le16(filter_type); + memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN); + if (!bssid) + memset(filter->bssid, ~0, ETH_ALEN); else - memcpy(filter->src, src, ETH_ALEN); - filter->antenna = antenna; - filter->magic3 = cpu_to_le32(magic3); - filter->rx_addr = cpu_to_le32(priv->rx_end); - filter->max_rx = cpu_to_le16(0x0620); /* FIXME: for usb ver 1.. maybe */ - filter->rxhw = priv->rxhw; - filter->magic8 = cpu_to_le16(magic8); - filter->magic9 = cpu_to_le16(magic9); - - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1); + memcpy(filter->bssid, bssid, ETH_ALEN); + + filter->rx_antenna = priv->rx_antenna; + + if (priv->fw_var < 0x500) { + data_len = P54_TX_CONTROL_FILTER_V1_LEN; + filter->v1.basic_rate_mask = cpu_to_le32(0x15F); + filter->v1.rx_addr = cpu_to_le32(priv->rx_end); + filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); + filter->v1.rxhw = cpu_to_le16(priv->rxhw); + filter->v1.wakeup_timer = cpu_to_le16(500); + } else { + data_len = P54_TX_CONTROL_FILTER_V2_LEN; + filter->v2.rx_addr = cpu_to_le32(priv->rx_end); + filter->v2.max_rx = cpu_to_le16(priv->rx_mtu); + filter->v2.rxhw = cpu_to_le16(priv->rxhw); + filter->v2.timer = cpu_to_le16(1000); + } + + hdr->len = cpu_to_le16(data_len); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); + priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); return 0; } @@ -672,12 +939,10 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) struct p54_control_hdr *hdr; struct p54_tx_control_channel *chan; unsigned int i; - size_t payload_len = sizeof(*chan) + sizeof(u32)*2 + - sizeof(*chan->curve_data) * - priv->curve_data->points_per_channel; + size_t data_len; void *entry; - hdr = kzalloc(sizeof(*hdr) + payload_len + + hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + priv->tx_hdr_len, GFP_KERNEL); if (!hdr) return -ENOMEM; @@ -687,12 +952,11 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) chan = (struct p54_tx_control_channel *) hdr->data; hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*chan)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len); - chan->magic1 = cpu_to_le16(0x1); - chan->magic2 = cpu_to_le16(0x0); + chan->flags = cpu_to_le16(0x1); + chan->dwell = cpu_to_le16(0x0); for (i = 0; i < priv->iq_autocal_len; i++) { if (priv->iq_autocal[i].freq != freq) @@ -710,35 +974,51 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) continue; chan->val_barker = 0x38; - chan->val_bpsk = priv->output_limit[i].val_bpsk; - chan->val_qpsk = priv->output_limit[i].val_qpsk; - chan->val_16qam = priv->output_limit[i].val_16qam; - chan->val_64qam = priv->output_limit[i].val_64qam; + chan->val_bpsk = chan->dup_bpsk = + priv->output_limit[i].val_bpsk; + chan->val_qpsk = chan->dup_qpsk = + priv->output_limit[i].val_qpsk; + chan->val_16qam = chan->dup_16qam = + priv->output_limit[i].val_16qam; + chan->val_64qam = chan->dup_64qam = + priv->output_limit[i].val_64qam; break; } if (i == priv->output_limit_len) goto err; - chan->pa_points_per_curve = priv->curve_data->points_per_channel; - entry = priv->curve_data->data; for (i = 0; i < priv->curve_data->channels; i++) { if (*((__le16 *)entry) != freq) { entry += sizeof(__le16); - entry += sizeof(struct pda_pa_curve_data_sample_rev1) * - chan->pa_points_per_curve; + entry += sizeof(struct p54_pa_curve_data_sample) * + priv->curve_data->points_per_channel; continue; } entry += sizeof(__le16); + chan->pa_points_per_curve = + min(priv->curve_data->points_per_channel, (u8) 8); + memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) * chan->pa_points_per_curve); break; } - memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4); + if (priv->fw_var < 0x500) { + data_len = P54_TX_CONTROL_CHANNEL_V1_LEN; + chan->v1.rssical_mul = cpu_to_le16(130); + chan->v1.rssical_add = cpu_to_le16(0xfe70); + } else { + data_len = P54_TX_CONTROL_CHANNEL_V2_LEN; + chan->v2.rssical_mul = cpu_to_le16(130); + chan->v2.rssical_add = cpu_to_le16(0xfe70); + chan->v2.basic_rate_mask = cpu_to_le32(0x15f); + } - priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1); + hdr->len = cpu_to_le16(data_len); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); + priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); return 0; err: @@ -846,12 +1126,25 @@ static int p54_start(struct ieee80211_hw *dev) return -ENOMEM; } + if (!priv->cached_stats) { + priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + + priv->tx_hdr_len + sizeof(struct p54_control_hdr), + GFP_KERNEL); + + if (!priv->cached_stats) { + kfree(priv->cached_vdcf); + priv->cached_vdcf = NULL; + return -ENOMEM; + } + } + err = priv->open(dev); if (!err) - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; p54_init_vdcf(dev); + mod_timer(&priv->stats_timer, jiffies + HZ); return err; } @@ -859,10 +1152,13 @@ static void p54_stop(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct sk_buff *skb; + + del_timer(&priv->stats_timer); while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); priv->stop(dev); - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->tsf_high32 = priv->tsf_low32 = 0; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; } static int p54_add_interface(struct ieee80211_hw *dev, @@ -870,11 +1166,11 @@ static int p54_add_interface(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MNTR) + if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: @@ -883,12 +1179,11 @@ static int p54_add_interface(struct ieee80211_hw *dev, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642); - p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642); + p54_set_filter(dev, 0, NULL); switch (conf->type) { - case IEEE80211_IF_TYPE_STA: - p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0); + case NL80211_IFTYPE_STATION: + p54_set_filter(dev, 1, NULL); break; default: BUG(); /* impossible */ @@ -904,9 +1199,9 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0); + p54_set_filter(dev, 0, NULL); } static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) @@ -915,6 +1210,9 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); + priv->rx_antenna = (conf->antenna_sel_rx == 0) ? + 2 : conf->antenna_sel_tx - 1; + priv->output_power = conf->power_level << 2; ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); p54_set_vdcf(dev); mutex_unlock(&priv->conf_mutex); @@ -928,8 +1226,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); - p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642); - p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0); + p54_set_filter(dev, 0, conf->bssid); p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); memcpy(priv->bssid, conf->bssid, ETH_ALEN); mutex_unlock(&priv->conf_mutex); @@ -943,15 +1240,28 @@ static void p54_configure_filter(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - *total_flags &= FIF_BCN_PRBRESP_PROMISC; + *total_flags &= FIF_BCN_PRBRESP_PROMISC | + FIF_PROMISC_IN_BSS | + FIF_FCSFAIL; + + priv->filter_flags = *total_flags; if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_set_filter(dev, 0, priv->mac_addr, - NULL, 2, 0, 0, 0); + p54_set_filter(dev, le16_to_cpu(priv->filter_type), + NULL); + else + p54_set_filter(dev, le16_to_cpu(priv->filter_type), + priv->bssid); + } + + if (changed_flags & FIF_PROMISC_IN_BSS) { + if (*total_flags & FIF_PROMISC_IN_BSS) + p54_set_filter(dev, le16_to_cpu(priv->filter_type) | + 0x8, NULL); else - p54_set_filter(dev, 0, priv->mac_addr, - priv->bssid, 2, 0, 0, 0); + p54_set_filter(dev, le16_to_cpu(priv->filter_type) & + ~0x8, priv->bssid); } } @@ -975,10 +1285,67 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, return 0; } +static int p54_init_xbow_synth(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_xbow_synth *xbow; + + hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) + + priv->tx_hdr_len, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr = (void *)hdr + priv->tx_hdr_len; + hdr->magic1 = cpu_to_le16(0x8001); + hdr->len = cpu_to_le16(sizeof(*xbow)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow)); + + xbow = (struct p54_tx_control_xbow_synth *) hdr->data; + xbow->magic1 = cpu_to_le16(0x1); + xbow->magic2 = cpu_to_le16(0x2); + xbow->freq = cpu_to_le16(5390); + + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1); + + return 0; +} + +static void p54_statistics_timer(unsigned long data) +{ + struct ieee80211_hw *dev = (struct ieee80211_hw *) data; + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_statistics *stats; + + BUG_ON(!priv->cached_stats); + + hdr = (void *)priv->cached_stats + priv->tx_hdr_len; + hdr->magic1 = cpu_to_le16(0x8000); + hdr->len = cpu_to_le16(sizeof(*stats)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); + + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); +} + static int p54_get_stats(struct ieee80211_hw *dev, struct ieee80211_low_level_stats *stats) { - /* TODO */ + struct p54_common *priv = dev->priv; + + del_timer(&priv->stats_timer); + p54_statistics_timer((unsigned long)dev); + + if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) { + printk(KERN_ERR "%s: device does not respond!\n", + wiphy_name(dev->wiphy)); + return -EBUSY; + } + + memcpy(stats, &priv->stats, sizeof(*stats)); + return 0; } @@ -987,7 +1354,7 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - memcpy(stats, &priv->tx_stats, sizeof(stats[0]) * dev->queues); + memcpy(stats, &priv->tx_stats[4], sizeof(stats[0]) * dev->queues); return 0; } @@ -1016,22 +1383,32 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) return NULL; priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; skb_queue_head_init(&priv->tx_queue); - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_UNSPEC; + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + dev->channel_change_time = 1000; /* TODO: find actual value */ - dev->max_signal = 127; - priv->tx_stats[0].limit = 5; + priv->tx_stats[0].limit = 1; + priv->tx_stats[1].limit = 1; + priv->tx_stats[2].limit = 1; + priv->tx_stats[3].limit = 1; + priv->tx_stats[4].limit = 5; dev->queues = 1; - + priv->noise = -94; dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + sizeof(struct p54_tx_control_allocdata); mutex_init(&priv->conf_mutex); + init_completion(&priv->eeprom_comp); + init_completion(&priv->stats_comp); + setup_timer(&priv->stats_timer, p54_statistics_timer, + (unsigned long)dev); return dev; } @@ -1040,6 +1417,7 @@ EXPORT_SYMBOL_GPL(p54_init_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; + kfree(priv->cached_stats); kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 8db6c0e8e54..2fa994cfcfe 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -1,5 +1,5 @@ -#ifndef PRISM54COMMON_H -#define PRISM54COMMON_H +#ifndef P54COMMON_H +#define P54COMMON_H /* * Common code specific definitions for mac80211 Prism54 drivers @@ -18,7 +18,8 @@ struct bootrec { __le32 code; __le32 len; - u32 data[0]; + u32 data[10]; + __le16 rx_mtu; } __attribute__((packed)); struct bootrec_exp_if { @@ -29,6 +30,17 @@ struct bootrec_exp_if { __le16 top_compat; } __attribute__((packed)); +struct bootrec_desc { + __le16 modes; + __le16 flags; + __le32 rx_start; + __le32 rx_end; + u8 headroom; + u8 tailroom; + u8 unimportant[6]; + u8 rates[16]; +} __attribute__((packed)); + #define BR_CODE_MIN 0x80000000 #define BR_CODE_COMPONENT_ID 0x80000001 #define BR_CODE_COMPONENT_VERSION 0x80000002 @@ -39,11 +51,6 @@ struct bootrec_exp_if { #define BR_CODE_END_OF_BRA 0xFF0000FF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF -#define FW_FMAC 0x464d4143 -#define FW_LM86 0x4c4d3836 -#define FW_LM87 0x4c4d3837 -#define FW_LM20 0x4c4d3230 - /* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ struct pda_entry { @@ -89,6 +96,16 @@ struct pda_pa_curve_data_sample_rev1 { u8 data_qpsk; u8 data_16qam; u8 data_64qam; +} __attribute__ ((packed)); + +struct p54_pa_curve_data_sample { + u8 rf_power; + u8 pa_detector; + u8 data_barker; + u8 data_bpsk; + u8 data_qpsk; + u8 data_16qam; + u8 data_64qam; u8 padding; } __attribute__ ((packed)); @@ -169,8 +186,9 @@ struct p54_rx_hdr { u8 rssi; u8 quality; u16 unknown2; - __le64 timestamp; - u8 data[0]; + __le32 tsf32; + __le32 unalloc0; + u8 align[0]; } __attribute__ ((packed)); struct p54_frame_sent_hdr { @@ -198,22 +216,37 @@ struct p54_tx_control_allocdata { struct p54_tx_control_filter { __le16 filter_type; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - u8 antenna; - u8 debug; - __le32 magic3; - u8 rates[8]; // FIXME: what's this for? - __le32 rx_addr; - __le16 max_rx; - __le16 rxhw; - __le16 magic8; - __le16 magic9; + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 rx_antenna; + u8 rx_align; + union { + struct { + __le32 basic_rate_mask; + u8 rts_rates[8]; + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 wakeup_timer; + __le16 unalloc0; + } v1 __attribute__ ((packed)); + struct { + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 timer; + __le16 unalloc0; + __le32 unalloc1; + } v2 __attribute__ ((packed)); + } __attribute__ ((packed)); } __attribute__ ((packed)); +#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter)) +#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8) + struct p54_tx_control_channel { - __le16 magic1; - __le16 magic2; + __le16 flags; + __le16 dwell; u8 padding1[20]; struct pda_iq_autocal_entry iq_autocal; u8 pa_points_per_curve; @@ -222,10 +255,29 @@ struct p54_tx_control_channel { u8 val_qpsk; u8 val_16qam; u8 val_64qam; - struct pda_pa_curve_data_sample_rev1 curve_data[0]; - /* additional padding/data after curve_data */ + struct p54_pa_curve_data_sample curve_data[8]; + u8 dup_bpsk; + u8 dup_qpsk; + u8 dup_16qam; + u8 dup_64qam; + union { + struct { + __le16 rssical_mul; + __le16 rssical_add; + } v1 __attribute__ ((packed)); + + struct { + __le32 basic_rate_mask; + u8 rts_rates[8]; + __le16 rssical_mul; + __le16 rssical_add; + } v2 __attribute__ ((packed)); + } __attribute__ ((packed)); } __attribute__ ((packed)); +#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12) +#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel)) + struct p54_tx_control_led { __le16 mode; __le16 led_temporary; @@ -250,4 +302,24 @@ struct p54_tx_control_vdcf { __le16 frameburst; } __attribute__ ((packed)); -#endif /* PRISM54COMMON_H */ +struct p54_statistics { + __le32 rx_success; + __le32 rx_bad_fcs; + __le32 rx_abort; + __le32 rx_abort_phy; + __le32 rts_success; + __le32 rts_fail; + __le32 tsf32; + __le32 airtime; + __le32 noise; + __le32 unkn[10]; /* CCE / CCA / RADAR */ +} __attribute__ ((packed)); + +struct p54_tx_control_xbow_synth { + __le16 magic1; + __le16 magic2; + __le16 freq; + u32 padding[5]; +} __attribute__ ((packed)); + +#endif /* P54COMMON_H */ diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 7dd4add4bf4..1c2a02a741a 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -3,6 +3,7 @@ * Linux device driver for PCI based Prism54 * * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> + * Copyright (c) 2008, Christian Lamparter <chunkeey@web.de> * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al. @@ -71,16 +72,18 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_WRITE(ctrl_stat, reg); wmb(); - mdelay(50); - err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); if (err) { - printk(KERN_ERR "%s (prism54pci): cannot find firmware " + printk(KERN_ERR "%s (p54pci): cannot find firmware " "(isl3886)\n", pci_name(priv->pdev)); return err; } - p54_parse_firmware(dev, fw_entry); + err = p54_parse_firmware(dev, fw_entry); + if (err) { + release_firmware(fw_entry); + return err; + } data = (__le32 *) fw_entry->data; remains = fw_entry->size; @@ -121,162 +124,147 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) wmb(); udelay(10); + /* wait for the firmware to boot properly */ + mdelay(100); + return 0; } -static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id) +static void p54p_refill_rx_ring(struct ieee80211_hw *dev, + int ring_index, struct p54p_desc *ring, u32 ring_limit, + struct sk_buff **rx_buf) { - struct p54p_priv *priv = (struct p54p_priv *) dev_id; - __le32 reg; - - reg = P54P_READ(int_ident); - P54P_WRITE(int_ack, reg); + struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; + u32 limit, idx, i; - if (reg & P54P_READ(int_enable)) - complete(&priv->boot_comp); + idx = le32_to_cpu(ring_control->host_idx[ring_index]); + limit = idx; + limit -= le32_to_cpu(ring_control->device_idx[ring_index]); + limit = ring_limit - limit; - return IRQ_HANDLED; -} + i = idx % ring_limit; + while (limit-- > 1) { + struct p54p_desc *desc = &ring[i]; -static int p54p_read_eeprom(struct ieee80211_hw *dev) -{ - struct p54p_priv *priv = dev->priv; - struct p54p_ring_control *ring_control = priv->ring_control; - int err; - struct p54_control_hdr *hdr; - void *eeprom; - dma_addr_t rx_mapping, tx_mapping; - u16 alen; + if (!desc->host_addr) { + struct sk_buff *skb; + dma_addr_t mapping; + skb = dev_alloc_skb(priv->common.rx_mtu + 32); + if (!skb) + break; - init_completion(&priv->boot_comp); - err = request_irq(priv->pdev->irq, &p54p_simple_interrupt, - IRQF_SHARED, "prism54pci", priv); - if (err) { - printk(KERN_ERR "%s (prism54pci): failed to register IRQ handler\n", - pci_name(priv->pdev)); - return err; - } + mapping = pci_map_single(priv->pdev, + skb_tail_pointer(skb), + priv->common.rx_mtu + 32, + PCI_DMA_FROMDEVICE); + desc->host_addr = cpu_to_le32(mapping); + desc->device_addr = 0; // FIXME: necessary? + desc->len = cpu_to_le16(priv->common.rx_mtu + 32); + desc->flags = 0; + rx_buf[i] = skb; + } - eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL); - if (!eeprom) { - printk(KERN_ERR "%s (prism54pci): no memory for eeprom!\n", - pci_name(priv->pdev)); - err = -ENOMEM; - goto out; + i++; + idx++; + i %= ring_limit; } - memset(ring_control, 0, sizeof(*ring_control)); - P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma)); - P54P_READ(ring_control_base); - udelay(10); - - P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT)); - P54P_READ(int_enable); - udelay(10); + wmb(); + ring_control->host_idx[ring_index] = cpu_to_le32(idx); +} - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); +static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, + int ring_index, struct p54p_desc *ring, u32 ring_limit, + struct sk_buff **rx_buf) +{ + struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; + struct p54p_desc *desc; + u32 idx, i; + + i = (*index) % ring_limit; + (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]); + idx %= ring_limit; + while (i != idx) { + u16 len; + struct sk_buff *skb; + desc = &ring[i]; + len = le16_to_cpu(desc->len); + skb = rx_buf[i]; + + if (!skb) { + i++; + i %= ring_limit; + continue; + } + skb_put(skb, len); + + if (p54_rx(dev, skb)) { + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + priv->common.rx_mtu + 32, + PCI_DMA_FROMDEVICE); + rx_buf[i] = NULL; + desc->host_addr = 0; + } else { + skb_trim(skb, 0); + desc->len = cpu_to_le16(priv->common.rx_mtu + 32); + } - if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { - printk(KERN_ERR "%s (prism54pci): Cannot boot firmware!\n", - pci_name(priv->pdev)); - err = -EINVAL; - goto out; + i++; + i %= ring_limit; } - P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); - P54P_READ(int_enable); + p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf); +} - hdr = eeprom + 0x2010; - p54_fill_eeprom_readback(hdr); - hdr->req_id = cpu_to_le32(priv->common.rx_start); +/* caller must hold priv->lock */ +static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, + int ring_index, struct p54p_desc *ring, u32 ring_limit, + void **tx_buf) +{ + struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; + struct p54p_desc *desc; + u32 idx, i; - rx_mapping = pci_map_single(priv->pdev, eeprom, - 0x2010, PCI_DMA_FROMDEVICE); - tx_mapping = pci_map_single(priv->pdev, (void *)hdr, - EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); + i = (*index) % ring_limit; + (*index) = idx = le32_to_cpu(ring_control->device_idx[1]); + idx %= ring_limit; - ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping); - ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010); - ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping); - ring_control->tx_data[0].device_addr = hdr->req_id; - ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN); + while (i != idx) { + desc = &ring[i]; + kfree(tx_buf[i]); + tx_buf[i] = NULL; - ring_control->host_idx[2] = cpu_to_le32(1); - ring_control->host_idx[1] = cpu_to_le32(1); + pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - wmb(); - mdelay(100); - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); + desc->host_addr = 0; + desc->device_addr = 0; + desc->len = 0; + desc->flags = 0; - wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); - wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); - - pci_unmap_single(priv->pdev, tx_mapping, - EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); - pci_unmap_single(priv->pdev, rx_mapping, - 0x2010, PCI_DMA_FROMDEVICE); - - alen = le16_to_cpu(ring_control->rx_mgmt[0].len); - if (le32_to_cpu(ring_control->device_idx[2]) != 1 || - alen < 0x10) { - printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n", - pci_name(priv->pdev)); - err = -EINVAL; - goto out; + i++; + i %= ring_limit; } - - p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10); - - out: - kfree(eeprom); - P54P_WRITE(int_enable, cpu_to_le32(0)); - P54P_READ(int_enable); - udelay(10); - free_irq(priv->pdev->irq, priv); - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); - return err; } -static void p54p_refill_rx_ring(struct ieee80211_hw *dev) +static void p54p_rx_tasklet(unsigned long dev_id) { + struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id; struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; - u32 limit, host_idx, idx; - host_idx = le32_to_cpu(ring_control->host_idx[0]); - limit = host_idx; - limit -= le32_to_cpu(ring_control->device_idx[0]); - limit = ARRAY_SIZE(ring_control->rx_data) - limit; - - idx = host_idx % ARRAY_SIZE(ring_control->rx_data); - while (limit-- > 1) { - struct p54p_desc *desc = &ring_control->rx_data[idx]; - - if (!desc->host_addr) { - struct sk_buff *skb; - dma_addr_t mapping; - skb = dev_alloc_skb(MAX_RX_SIZE); - if (!skb) - break; - - mapping = pci_map_single(priv->pdev, - skb_tail_pointer(skb), - MAX_RX_SIZE, - PCI_DMA_FROMDEVICE); - desc->host_addr = cpu_to_le32(mapping); - desc->device_addr = 0; // FIXME: necessary? - desc->len = cpu_to_le16(MAX_RX_SIZE); - desc->flags = 0; - priv->rx_buf[idx] = skb; - } + p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt, + ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt); - idx++; - host_idx++; - idx %= ARRAY_SIZE(ring_control->rx_data); - } + p54p_check_rx_ring(dev, &priv->rx_idx_data, 0, ring_control->rx_data, + ARRAY_SIZE(ring_control->rx_data), priv->rx_buf_data); wmb(); - ring_control->host_idx[0] = cpu_to_le32(host_idx); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); } static irqreturn_t p54p_interrupt(int irq, void *dev_id) @@ -298,65 +286,18 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) reg &= P54P_READ(int_enable); if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { - struct p54p_desc *desc; - u32 idx, i; - i = priv->tx_idx; - i %= ARRAY_SIZE(ring_control->tx_data); - priv->tx_idx = idx = le32_to_cpu(ring_control->device_idx[1]); - idx %= ARRAY_SIZE(ring_control->tx_data); - - while (i != idx) { - desc = &ring_control->tx_data[i]; - if (priv->tx_buf[i]) { - kfree(priv->tx_buf[i]); - priv->tx_buf[i] = NULL; - } - - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - - desc->host_addr = 0; - desc->device_addr = 0; - desc->len = 0; - desc->flags = 0; - - i++; - i %= ARRAY_SIZE(ring_control->tx_data); - } - - i = priv->rx_idx; - i %= ARRAY_SIZE(ring_control->rx_data); - priv->rx_idx = idx = le32_to_cpu(ring_control->device_idx[0]); - idx %= ARRAY_SIZE(ring_control->rx_data); - while (i != idx) { - u16 len; - struct sk_buff *skb; - desc = &ring_control->rx_data[i]; - len = le16_to_cpu(desc->len); - skb = priv->rx_buf[i]; + p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, + 3, ring_control->tx_mgmt, + ARRAY_SIZE(ring_control->tx_mgmt), + priv->tx_buf_mgmt); - skb_put(skb, len); + p54p_check_tx_ring(dev, &priv->tx_idx_data, + 1, ring_control->tx_data, + ARRAY_SIZE(ring_control->tx_data), + priv->tx_buf_data); - if (p54_rx(dev, skb)) { - pci_unmap_single(priv->pdev, - le32_to_cpu(desc->host_addr), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + tasklet_schedule(&priv->rx_tasklet); - priv->rx_buf[i] = NULL; - desc->host_addr = 0; - } else { - skb_trim(skb, 0); - desc->len = cpu_to_le16(MAX_RX_SIZE); - } - - i++; - i %= ARRAY_SIZE(ring_control->rx_data); - } - - p54p_refill_rx_ring(dev); - - wmb(); - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) complete(&priv->boot_comp); @@ -392,7 +333,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, ring_control->host_idx[1] = cpu_to_le32(idx + 1); if (free_on_tx) - priv->tx_buf[i] = data; + priv->tx_buf_data[i] = data; spin_unlock_irqrestore(&priv->lock, flags); @@ -412,7 +353,7 @@ static int p54p_open(struct ieee80211_hw *dev) init_completion(&priv->boot_comp); err = request_irq(priv->pdev->irq, &p54p_interrupt, - IRQF_SHARED, "prism54pci", dev); + IRQF_SHARED, "p54pci", dev); if (err) { printk(KERN_ERR "%s: failed to register IRQ handler\n", wiphy_name(dev->wiphy)); @@ -420,10 +361,19 @@ static int p54p_open(struct ieee80211_hw *dev) } memset(priv->ring_control, 0, sizeof(*priv->ring_control)); - priv->rx_idx = priv->tx_idx = 0; - p54p_refill_rx_ring(dev); + err = p54p_upload_firmware(dev); + if (err) { + free_irq(priv->pdev->irq, dev); + return err; + } + priv->rx_idx_data = priv->tx_idx_data = 0; + priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0; + + p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data, + ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data); - p54p_upload_firmware(dev); + p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt, + ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt); P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma)); P54P_READ(ring_control_base); @@ -465,6 +415,8 @@ static void p54p_stop(struct ieee80211_hw *dev) unsigned int i; struct p54p_desc *desc; + tasklet_kill(&priv->rx_tasklet); + P54P_WRITE(int_enable, cpu_to_le32(0)); P54P_READ(int_enable); udelay(10); @@ -473,26 +425,53 @@ static void p54p_stop(struct ieee80211_hw *dev) P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); - for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) { + for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) { desc = &ring_control->rx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - kfree_skb(priv->rx_buf[i]); - priv->rx_buf[i] = NULL; + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + priv->common.rx_mtu + 32, + PCI_DMA_FROMDEVICE); + kfree_skb(priv->rx_buf_data[i]); + priv->rx_buf_data[i] = NULL; + } + + for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) { + desc = &ring_control->rx_mgmt[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + priv->common.rx_mtu + 32, + PCI_DMA_FROMDEVICE); + kfree_skb(priv->rx_buf_mgmt[i]); + priv->rx_buf_mgmt[i] = NULL; } - for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) { + for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) { desc = &ring_control->tx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), + PCI_DMA_TODEVICE); - kfree(priv->tx_buf[i]); - priv->tx_buf[i] = NULL; + kfree(priv->tx_buf_data[i]); + priv->tx_buf_data[i] = NULL; } - memset(ring_control, 0, sizeof(ring_control)); + for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) { + desc = &ring_control->tx_mgmt[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), + PCI_DMA_TODEVICE); + + kfree(priv->tx_buf_mgmt[i]); + priv->tx_buf_mgmt[i] = NULL; + } + + memset(ring_control, 0, sizeof(*ring_control)); } static int __devinit p54p_probe(struct pci_dev *pdev, @@ -506,7 +485,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err = pci_enable_device(pdev); if (err) { - printk(KERN_ERR "%s (prism54pci): Cannot enable new PCI device\n", + printk(KERN_ERR "%s (p54pci): Cannot enable new PCI device\n", pci_name(pdev)); return err; } @@ -514,22 +493,22 @@ static int __devinit p54p_probe(struct pci_dev *pdev, mem_addr = pci_resource_start(pdev, 0); mem_len = pci_resource_len(pdev, 0); if (mem_len < sizeof(struct p54p_csr)) { - printk(KERN_ERR "%s (prism54pci): Too short PCI resources\n", + printk(KERN_ERR "%s (p54pci): Too short PCI resources\n", pci_name(pdev)); pci_disable_device(pdev); return err; } - err = pci_request_regions(pdev, "prism54pci"); + err = pci_request_regions(pdev, "p54pci"); if (err) { - printk(KERN_ERR "%s (prism54pci): Cannot obtain PCI resources\n", + printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n", pci_name(pdev)); return err; } if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { - printk(KERN_ERR "%s (prism54pci): No suitable DMA available\n", + printk(KERN_ERR "%s (p54pci): No suitable DMA available\n", pci_name(pdev)); goto err_free_reg; } @@ -542,7 +521,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, dev = p54_init_common(sizeof(*priv)); if (!dev) { - printk(KERN_ERR "%s (prism54pci): ieee80211 alloc failed\n", + printk(KERN_ERR "%s (p54pci): ieee80211 alloc failed\n", pci_name(pdev)); err = -ENOMEM; goto err_free_reg; @@ -556,7 +535,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, priv->map = ioremap(mem_addr, mem_len); if (!priv->map) { - printk(KERN_ERR "%s (prism54pci): Cannot map device memory\n", + printk(KERN_ERR "%s (p54pci): Cannot map device memory\n", pci_name(pdev)); err = -EINVAL; // TODO: use a better error code? goto err_free_dev; @@ -565,39 +544,31 @@ static int __devinit p54p_probe(struct pci_dev *pdev, priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control), &priv->ring_control_dma); if (!priv->ring_control) { - printk(KERN_ERR "%s (prism54pci): Cannot allocate rings\n", + printk(KERN_ERR "%s (p54pci): Cannot allocate rings\n", pci_name(pdev)); err = -ENOMEM; goto err_iounmap; } - memset(priv->ring_control, 0, sizeof(*priv->ring_control)); - - err = p54p_upload_firmware(dev); - if (err) - goto err_free_desc; - - err = p54p_read_eeprom(dev); - if (err) - goto err_free_desc; - priv->common.open = p54p_open; priv->common.stop = p54p_stop; priv->common.tx = p54p_tx; spin_lock_init(&priv->lock); + tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); + + p54p_open(dev); + err = p54_read_eeprom(dev); + p54p_stop(dev); + if (err) + goto err_free_desc; err = ieee80211_register_hw(dev); if (err) { - printk(KERN_ERR "%s (prism54pci): Cannot register netdevice\n", + printk(KERN_ERR "%s (p54pci): Cannot register netdevice\n", pci_name(pdev)); goto err_free_common; } - printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n", - wiphy_name(dev->wiphy), - print_mac(mac, dev->wiphy->perm_addr), - priv->common.version); - return 0; err_free_common: @@ -645,7 +616,7 @@ static int p54p_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct p54p_priv *priv = dev->priv; - if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { + if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) { ieee80211_stop_queues(dev); p54p_stop(dev); } @@ -663,7 +634,7 @@ static int p54p_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { + if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) { p54p_open(dev); ieee80211_wake_queues(dev); } @@ -673,7 +644,7 @@ static int p54p_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ static struct pci_driver p54p_driver = { - .name = "prism54pci", + .name = "p54pci", .id_table = p54p_table, .probe = p54p_probe, .remove = __devexit_p(p54p_remove), diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 5bedd7af385..4a6778070af 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -1,5 +1,5 @@ -#ifndef PRISM54PCI_H -#define PRISM54PCI_H +#ifndef P54PCI_H +#define P54PCI_H /* * Defines for PCI based mac80211 Prism54 driver @@ -68,7 +68,7 @@ struct p54p_csr { } __attribute__ ((packed)); /* usb backend only needs the register defines above */ -#ifndef PRISM54USB_H +#ifndef P54USB_H struct p54p_desc { __le32 host_addr; __le32 device_addr; @@ -92,15 +92,19 @@ struct p54p_priv { struct p54_common common; struct pci_dev *pdev; struct p54p_csr __iomem *map; + struct tasklet_struct rx_tasklet; spinlock_t lock; struct p54p_ring_control *ring_control; dma_addr_t ring_control_dma; - u32 rx_idx, tx_idx; - struct sk_buff *rx_buf[8]; - void *tx_buf[32]; + u32 rx_idx_data, tx_idx_data; + u32 rx_idx_mgmt, tx_idx_mgmt; + struct sk_buff *rx_buf_data[8]; + struct sk_buff *rx_buf_mgmt[4]; + void *tx_buf_data[32]; + void *tx_buf_mgmt[4]; struct completion boot_comp; }; -#endif /* PRISM54USB_H */ -#endif /* PRISM54PCI_H */ +#endif /* P54USB_H */ +#endif /* P54PCI_H */ diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index cbaca23a945..75d749bccb0 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -39,6 +39,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */ {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ + {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ @@ -63,8 +64,8 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */ {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ - {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */ + {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */ {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */ {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ @@ -91,11 +92,16 @@ static void p54u_rx_cb(struct urb *urb) skb_unlink(skb, &priv->rx_queue); skb_put(skb, urb->actual_length); - if (!priv->hw_type) - skb_pull(skb, sizeof(struct net2280_tx_hdr)); + + if (priv->hw_type == P54U_NET2280) + skb_pull(skb, priv->common.tx_hdr_len); + if (priv->common.fw_interface == FW_LM87) { + skb_pull(skb, 4); + skb_put(skb, 4); + } if (p54_rx(dev, skb)) { - skb = dev_alloc_skb(MAX_RX_SIZE); + skb = dev_alloc_skb(priv->common.rx_mtu + 32); if (unlikely(!skb)) { usb_free_urb(urb); /* TODO check rx queue length and refill *somewhere* */ @@ -109,9 +115,12 @@ static void p54u_rx_cb(struct urb *urb) urb->context = skb; skb_queue_tail(&priv->rx_queue, skb); } else { - if (!priv->hw_type) - skb_push(skb, sizeof(struct net2280_tx_hdr)); - + if (priv->hw_type == P54U_NET2280) + skb_push(skb, priv->common.tx_hdr_len); + if (priv->common.fw_interface == FW_LM87) { + skb_push(skb, 4); + skb_put(skb, 4); + } skb_reset_tail_pointer(skb); skb_trim(skb, 0); if (urb->transfer_buffer != skb_tail_pointer(skb)) { @@ -145,7 +154,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) struct p54u_rx_info *info; while (skb_queue_len(&priv->rx_queue) < 32) { - skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL); + skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL); if (!skb) break; entry = usb_alloc_urb(0, GFP_KERNEL); @@ -153,7 +162,10 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) kfree_skb(skb); break; } - usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb); + usb_fill_bulk_urb(entry, priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), + skb_tail_pointer(skb), + priv->common.rx_mtu + 32, p54u_rx_cb, skb); info = (struct p54u_rx_info *) skb->cb; info->urb = entry; info->dev = dev; @@ -207,6 +219,42 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, usb_submit_urb(data_urb, GFP_ATOMIC); } +static __le32 p54u_lm87_chksum(const u32 *data, size_t length) +{ + u32 chk = 0; + + length >>= 2; + while (length--) { + chk ^= *data++; + chk = (chk >> 5) ^ (chk << 3); + } + + return cpu_to_le32(chk); +} + +static void p54u_tx_lm87(struct ieee80211_hw *dev, + struct p54_control_hdr *data, + size_t len, int free_on_tx) +{ + struct p54u_priv *priv = dev->priv; + struct urb *data_urb; + struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr); + + data_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!data_urb) + return; + + hdr->chksum = p54u_lm87_chksum((u32 *)data, len); + hdr->device_addr = data->req_id; + + usb_fill_bulk_urb(data_urb, priv->udev, + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, + len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, + dev); + + usb_submit_urb(data_urb, GFP_ATOMIC); +} + static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, size_t len, int free_on_tx) { @@ -312,73 +360,6 @@ static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, data, len, &alen, 2000); } -static int p54u_read_eeprom(struct ieee80211_hw *dev) -{ - struct p54u_priv *priv = dev->priv; - void *buf; - struct p54_control_hdr *hdr; - int err, alen; - size_t offset = priv->hw_type ? 0x10 : 0x20; - - buf = kmalloc(0x2020, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "prism54usb: cannot allocate memory for " - "eeprom readback!\n"); - return -ENOMEM; - } - - if (priv->hw_type) { - *((u32 *) buf) = priv->common.rx_start; - err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); - if (err) { - printk(KERN_ERR "prism54usb: addr send failed\n"); - goto fail; - } - } else { - struct net2280_reg_write *reg = buf; - reg->port = cpu_to_le16(NET2280_DEV_U32); - reg->addr = cpu_to_le32(P54U_DEV_BASE); - reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); - err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg)); - if (err) { - printk(KERN_ERR "prism54usb: dev_int send failed\n"); - goto fail; - } - } - - hdr = buf + priv->common.tx_hdr_len; - p54_fill_eeprom_readback(hdr); - hdr->req_id = cpu_to_le32(priv->common.rx_start); - if (priv->common.tx_hdr_len) { - struct net2280_tx_hdr *tx_hdr = buf; - tx_hdr->device_addr = hdr->req_id; - tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN); - } - - /* we can just pretend to send 0x2000 bytes of nothing in the headers */ - err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, - EEPROM_READBACK_LEN + priv->common.tx_hdr_len); - if (err) { - printk(KERN_ERR "prism54usb: eeprom req send failed\n"); - goto fail; - } - - err = usb_bulk_msg(priv->udev, - usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), - buf, 0x2020, &alen, 1000); - if (!err && alen > offset) { - p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset); - } else { - printk(KERN_ERR "prism54usb: eeprom read failed!\n"); - err = -EINVAL; - goto fail; - } - - fail: - kfree(buf); - return err; -} - static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) { static char start_string[] = "~~~~<\r"; @@ -412,7 +393,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) goto err_req_fw_failed; } - p54_parse_firmware(dev, fw_entry); + err = p54_parse_firmware(dev, fw_entry); + if (err) + goto err_upload_failed; left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); strcpy(buf, start_string); @@ -458,7 +441,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size); if (err) { - printk(KERN_ERR "prism54usb: firmware upload failed!\n"); + printk(KERN_ERR "p54usb: firmware upload failed!\n"); goto err_upload_failed; } @@ -469,7 +452,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); if (err) { - printk(KERN_ERR "prism54usb: firmware upload failed!\n"); + printk(KERN_ERR "p54usb: firmware upload failed!\n"); goto err_upload_failed; } @@ -480,13 +463,13 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) break; if (alen > 5 && !memcmp(buf, "ERROR", 5)) { - printk(KERN_INFO "prism54usb: firmware upload failed!\n"); + printk(KERN_INFO "p54usb: firmware upload failed!\n"); err = -EINVAL; break; } if (time_after(jiffies, timeout)) { - printk(KERN_ERR "prism54usb: firmware boot timed out!\n"); + printk(KERN_ERR "p54usb: firmware boot timed out!\n"); err = -ETIMEDOUT; break; } @@ -498,7 +481,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) buf[1] = '\r'; err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); if (err) { - printk(KERN_ERR "prism54usb: firmware boot failed!\n"); + printk(KERN_ERR "p54usb: firmware boot failed!\n"); goto err_upload_failed; } @@ -549,7 +532,12 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) return err; } - p54_parse_firmware(dev, fw_entry); + err = p54_parse_firmware(dev, fw_entry); + if (err) { + kfree(buf); + release_firmware(fw_entry); + return err; + } #define P54U_WRITE(type, addr, data) \ do {\ @@ -660,7 +648,7 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len); if (err) { - printk(KERN_ERR "prism54usb: firmware block upload " + printk(KERN_ERR "p54usb: firmware block upload " "failed\n"); goto fail; } @@ -694,7 +682,7 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) 0x002C | (unsigned long)&devreg->direct_mem_win); if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { - printk(KERN_ERR "prism54usb: firmware DMA transfer " + printk(KERN_ERR "p54usb: firmware DMA transfer " "failed\n"); goto fail; } @@ -802,7 +790,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, dev = p54_init_common(sizeof(*priv)); if (!dev) { - printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n"); + printk(KERN_ERR "p54usb: ieee80211 alloc failed\n"); return -ENOMEM; } @@ -833,49 +821,40 @@ static int __devinit p54u_probe(struct usb_interface *intf, } } priv->common.open = p54u_open; - + priv->common.stop = p54u_stop; if (recognized_pipes < P54U_PIPE_NUMBER) { priv->hw_type = P54U_3887; - priv->common.tx = p54u_tx_3887; + err = p54u_upload_firmware_3887(dev); + if (priv->common.fw_interface == FW_LM87) { + dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr); + priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr); + priv->common.tx = p54u_tx_lm87; + } else + priv->common.tx = p54u_tx_3887; } else { + priv->hw_type = P54U_NET2280; dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr); priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr); priv->common.tx = p54u_tx_net2280; - } - priv->common.stop = p54u_stop; - - if (priv->hw_type) - err = p54u_upload_firmware_3887(dev); - else err = p54u_upload_firmware_net2280(dev); + } if (err) goto err_free_dev; - err = p54u_read_eeprom(dev); + skb_queue_head_init(&priv->rx_queue); + + p54u_open(dev); + err = p54_read_eeprom(dev); + p54u_stop(dev); if (err) goto err_free_dev; - if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { - u8 perm_addr[ETH_ALEN]; - - printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n"); - random_ether_addr(perm_addr); - SET_IEEE80211_PERM_ADDR(dev, perm_addr); - } - - skb_queue_head_init(&priv->rx_queue); - err = ieee80211_register_hw(dev); if (err) { - printk(KERN_ERR "prism54usb: Cannot register netdevice\n"); + printk(KERN_ERR "p54usb: Cannot register netdevice\n"); goto err_free_dev; } - printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n", - wiphy_name(dev->wiphy), - print_mac(mac, dev->wiphy->perm_addr), - priv->common.version); - return 0; err_free_dev: @@ -902,7 +881,7 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) } static struct usb_driver p54u_driver = { - .name = "prism54usb", + .name = "p54usb", .id_table = p54u_table, .probe = p54u_probe, .disconnect = p54u_disconnect, diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index d1896b396c1..5b8fe91379c 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h @@ -1,5 +1,5 @@ -#ifndef PRISM54USB_H -#define PRISM54USB_H +#ifndef P54USB_H +#define P54USB_H /* * Defines for USB based mac80211 Prism54 driver @@ -72,6 +72,11 @@ struct net2280_tx_hdr { u8 padding[8]; } __attribute__((packed)); +struct lm87_tx_hdr { + __le32 device_addr; + __le32 chksum; +} __attribute__((packed)); + /* Some flags for the isl hardware registers controlling DMA inside the * chip */ #define ISL38XX_DMA_STATUS_DONE 0x00000001 @@ -130,4 +135,4 @@ struct p54u_priv { struct sk_buff_head rx_queue; }; -#endif /* PRISM54USB_H */ +#endif /* P54USB_H */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 3d75a7137d3..16e68f4b654 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -71,7 +71,7 @@ prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { printk(KERN_DEBUG "%s(): Sorry, Repeater mode and Secondary mode " - "are not yet supported by this driver.\n", __FUNCTION__); + "are not yet supported by this driver.\n", __func__); return -EINVAL; } @@ -333,7 +333,7 @@ prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { printk(KERN_DEBUG "%s: %s() You passed a non-valid init_mode.\n", - priv->ndev->name, __FUNCTION__); + priv->ndev->name, __func__); return -EINVAL; } @@ -1234,7 +1234,7 @@ prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, /* don't know how to disable radio */ printk(KERN_DEBUG "%s: %s() disabling radio is not yet supported.\n", - priv->ndev->name, __FUNCTION__); + priv->ndev->name, __func__); return -ENOTSUPP; } else if (vwrq->fixed) /* currently only fixed value is supported */ @@ -1242,7 +1242,7 @@ prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, else { printk(KERN_DEBUG "%s: %s() auto power will be implemented later.\n", - priv->ndev->name, __FUNCTION__); + priv->ndev->name, __func__); return -ENOTSUPP; } } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 963960dc30f..1404a571752 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -325,7 +325,7 @@ static int ray_probe(struct pcmcia_device *p_dev) p_dev->io.IOAddrLines = 5; /* Interrupt setup. For PCMCIA, driver takes what's given */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = &ray_interrupt; @@ -798,9 +798,9 @@ static void ray_release(struct pcmcia_device *link) iounmap(local->amem); /* Do bother checking to see if these succeed or not */ i = pcmcia_release_window(local->amem_handle); - if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); + if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); i = pcmcia_release_window(local->rmem_handle); - if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); + if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); pcmcia_disable_device(link); DEBUG(2,"ray_release ending\n"); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 00e965b9da7..2b414899dfa 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1627,7 +1627,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, static int rndis_iw_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct iw_param *param = &wrqu->param; struct usbnet *usbdev = dev->priv; union iwreq_data evt; int ret = -EINVAL; @@ -1635,7 +1634,7 @@ static int rndis_iw_set_scan(struct net_device *dev, devdbg(usbdev, "SIOCSIWSCAN"); - if (param->flags == 0) { + if (wrqu->data.flags == 0) { tmp = ccpu2(1); ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, sizeof(tmp)); diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index d485a86bba7..f839ce044af 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -1,5 +1,5 @@ -config RT2X00 - tristate "Ralink driver support" +menuconfig RT2X00 + bool "Ralink driver support" depends on MAC80211 && WLAN_80211 && EXPERIMENTAL ---help--- This will enable the experimental support for the Ralink drivers, @@ -17,31 +17,6 @@ config RT2X00 if RT2X00 -config RT2X00_LIB - tristate - -config RT2X00_LIB_PCI - tristate - select RT2X00_LIB - -config RT2X00_LIB_USB - tristate - select RT2X00_LIB - -config RT2X00_LIB_FIRMWARE - boolean - depends on RT2X00_LIB - select FW_LOADER - -config RT2X00_LIB_RFKILL - boolean - depends on RT2X00_LIB - select RFKILL - -config RT2X00_LIB_LEDS - boolean - depends on RT2X00_LIB && NEW_LEDS - config RT2400PCI tristate "Ralink rt2400 (PCI/PCMCIA) support" depends on PCI @@ -53,23 +28,6 @@ config RT2400PCI When compiled as a module, this driver will be called "rt2400pci.ko". -config RT2400PCI_RFKILL - bool "Ralink rt2400 rfkill support" - depends on RT2400PCI - select RT2X00_LIB_RFKILL - ---help--- - This adds support for integrated rt2400 hardware that features a - hardware button to control the radio state. - This feature depends on the RF switch subsystem rfkill. - -config RT2400PCI_LEDS - bool "Ralink rt2400 leds support" - depends on RT2400PCI && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. - config RT2500PCI tristate "Ralink rt2500 (PCI/PCMCIA) support" depends on PCI @@ -81,28 +39,12 @@ config RT2500PCI When compiled as a module, this driver will be called "rt2500pci.ko". -config RT2500PCI_RFKILL - bool "Ralink rt2500 rfkill support" - depends on RT2500PCI - select RT2X00_LIB_RFKILL - ---help--- - This adds support for integrated rt2500 hardware that features a - hardware button to control the radio state. - This feature depends on the RF switch subsystem rfkill. - -config RT2500PCI_LEDS - bool "Ralink rt2500 leds support" - depends on RT2500PCI && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. - config RT61PCI tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support" depends on PCI select RT2X00_LIB_PCI select RT2X00_LIB_FIRMWARE + select RT2X00_LIB_CRYPTO select CRC_ITU_T select EEPROM_93CX6 ---help--- @@ -111,23 +53,6 @@ config RT61PCI When compiled as a module, this driver will be called "rt61pci.ko". -config RT61PCI_RFKILL - bool "Ralink rt2501/rt61 rfkill support" - depends on RT61PCI - select RT2X00_LIB_RFKILL - ---help--- - This adds support for integrated rt61 hardware that features a - hardware button to control the radio state. - This feature depends on the RF switch subsystem rfkill. - -config RT61PCI_LEDS - bool "Ralink rt2501/rt61 leds support" - depends on RT61PCI && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. - config RT2500USB tristate "Ralink rt2500 (USB) support" depends on USB @@ -138,19 +63,12 @@ config RT2500USB When compiled as a module, this driver will be called "rt2500usb.ko". -config RT2500USB_LEDS - bool "Ralink rt2500 leds support" - depends on RT2500USB && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. - config RT73USB tristate "Ralink rt2501/rt73 (USB) support" depends on USB select RT2X00_LIB_USB select RT2X00_LIB_FIRMWARE + select RT2X00_LIB_CRYPTO select CRC_ITU_T ---help--- This adds support for rt2501 wireless chipset family. @@ -158,13 +76,37 @@ config RT73USB When compiled as a module, this driver will be called "rt73usb.ko". -config RT73USB_LEDS - bool "Ralink rt2501/rt73 leds support" - depends on RT73USB && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. +config RT2X00_LIB_PCI + tristate + select RT2X00_LIB + +config RT2X00_LIB_USB + tristate + select RT2X00_LIB + +config RT2X00_LIB + tristate + +config RT2X00_LIB_FIRMWARE + boolean + select FW_LOADER + +config RT2X00_LIB_CRYPTO + boolean + +config RT2X00_LIB_RFKILL + boolean + default y if (RT2X00_LIB=y && RFKILL=y) || (RT2X00_LIB=m && RFKILL!=n) + +comment "rt2x00 rfkill support disabled due to modularized RFKILL and built-in rt2x00" + depends on RT2X00_LIB=y && RFKILL=m + +config RT2X00_LIB_LEDS + boolean + default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) + +comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00" + depends on RT2X00_LIB=y && LEDS_CLASS=m config RT2X00_LIB_DEBUGFS bool "Ralink debugfs support" diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 1087dbcf1a0..917cb4f3b03 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -3,6 +3,7 @@ rt2x00lib-y += rt2x00mac.o rt2x00lib-y += rt2x00config.o rt2x00lib-y += rt2x00queue.o rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o +rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 4c0538d6099..08cb9eec16a 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -231,7 +231,7 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2400PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -241,9 +241,9 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) } #else #define rt2400pci_rfkill_poll NULL -#endif /* CONFIG_RT2400PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ -#ifdef CONFIG_RT2400PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt2400pci_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -288,7 +288,7 @@ static void rt2400pci_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt2400pci_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT2400PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. @@ -1241,7 +1241,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) if (!reg) return IRQ_NONE; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; /* @@ -1374,22 +1374,22 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led mode, for correct led behaviour. */ -#ifdef CONFIG_RT2400PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); if (value == LED_MODE_TXRX_ACTIVITY) rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_ACTIVITY); -#endif /* CONFIG_RT2400PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2400PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2400PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1404,7 +1404,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * RF value list for RF2420 & RF2421 * Supports: 2.4 GHz */ -static const struct rf_channel rf_vals_bg[] = { +static const struct rf_channel rf_vals_b[] = { { 1, 0x00022058, 0x000c1fda, 0x00000101, 0 }, { 2, 0x00022058, 0x000c1fee, 0x00000101, 0 }, { 3, 0x00022058, 0x000c2002, 0x00000101, 0 }, @@ -1421,10 +1421,11 @@ static const struct rf_channel rf_vals_bg[] = { { 14, 0x00022058, 0x000c20fa, 0x00000101, 0 }, }; -static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -1440,23 +1441,28 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) EEPROM_MAC_ADDR_0)); /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; - spec->num_channels = ARRAY_SIZE(rf_vals_bg); - spec->channels = rf_vals_bg; + spec->num_channels = ARRAY_SIZE(rf_vals_b); + spec->channels = rf_vals_b; + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + return 0; } static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -1477,7 +1483,9 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt2400pci_probe_hw_mode(rt2x00dev); + retval = rt2400pci_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires the atim queue and DMA-mapped skbs. diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index bc556425822..bbff381ce39 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -938,19 +938,13 @@ #define MAX_TXPOWER 62 #define DEFAULT_TXPOWER 39 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \ - ((__txpower) < MIN_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \ - (((__txpower) - MAX_TXPOWER) + MIN_TXPOWER); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - (__txpower) += MIN_TXPOWER; \ - ((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER : \ - (MAX_TXPOWER - ((__txpower) - MIN_TXPOWER))); \ -}) +#define __CLAMP_TX(__txpower) \ + clamp_t(char, (__txpower), MIN_TXPOWER, MAX_TXPOWER) + +#define TXPOWER_FROM_DEV(__txpower) \ + ((__CLAMP_TX(__txpower) - MAX_TXPOWER) + MIN_TXPOWER) + +#define TXPOWER_TO_DEV(__txpower) \ + MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER) #endif /* RT2400PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 181a146b476..ef42cc04a2d 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -231,7 +231,7 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2500PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -241,9 +241,9 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) } #else #define rt2500pci_rfkill_poll NULL -#endif /* CONFIG_RT2500PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ -#ifdef CONFIG_RT2500PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt2500pci_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -288,7 +288,7 @@ static void rt2500pci_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt2500pci_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT2500PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. @@ -1316,6 +1316,8 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; } @@ -1377,7 +1379,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) if (!reg) return IRQ_NONE; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; /* @@ -1531,22 +1533,22 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led mode, for correct led behaviour. */ -#ifdef CONFIG_RT2500PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); if (value == LED_MODE_TXRX_ACTIVITY) rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_ACTIVITY); -#endif /* CONFIG_RT2500PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2500PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2500PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1721,10 +1723,11 @@ static const struct rf_channel rf_vals_5222[] = { { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 }, }; -static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -1741,20 +1744,10 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) EEPROM_MAC_ADDR_0)); /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); @@ -1776,6 +1769,26 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; } + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + if (spec->num_channels > 14) { + for (i = 14; i < spec->num_channels; i++) + info[i].tx_power1 = DEFAULT_TXPOWER; + } + + return 0; } static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -1796,7 +1809,9 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt2500pci_probe_hw_mode(rt2x00dev); + retval = rt2500pci_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires the atim queue and DMA-mapped skbs. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 42f376929ea..8c26bef6cf4 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -1223,17 +1223,10 @@ #define MAX_TXPOWER 31 #define DEFAULT_TXPOWER 24 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? \ - DEFAULT_TXPOWER : (__txpower); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ - (__txpower)); \ -}) +#define TXPOWER_FROM_DEV(__txpower) \ + (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER) #endif /* RT2500PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index cd5af656932..d3bf7bba611 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -288,7 +288,7 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2500USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt2500usb_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -333,7 +333,7 @@ static void rt2500usb_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt2500usb_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT2500USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. @@ -384,7 +384,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, bcn_preload >> 6); rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, - 2 * (conf->type != IEEE80211_IF_TYPE_STA)); + 2 * (conf->type != NL80211_IFTYPE_STATION)); rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg); /* @@ -1114,8 +1114,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, - skb->len - skbdesc->desc_len); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } @@ -1134,7 +1133,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) int pipe = usb_sndbulkpipe(usb_dev, 1); int length; u16 reg; - u32 word, len; /* * Add the descriptor in front of the skb. @@ -1144,17 +1142,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) skbdesc->desc = entry->skb->data; /* - * Adjust the beacon databyte count. The current number is - * calculated before this function gets called, but falsely - * assumes that the descriptor was already present in the SKB. - */ - rt2x00_desc_read(skbdesc->desc, 0, &word); - len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); - len += skbdesc->desc_len; - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); - rt2x00_desc_write(skbdesc->desc, 0, word); - - /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ @@ -1280,6 +1267,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; @@ -1297,7 +1286,7 @@ static void rt2500usb_beacondone(struct urb *urb) struct queue_entry *entry = (struct queue_entry *)urb->context; struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; - if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) return; /* @@ -1484,14 +1473,14 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led mode, for correct led behaviour. */ -#ifdef CONFIG_RT2500USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); if (value == LED_MODE_TXRX_ACTIVITY) rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_ACTIVITY); -#endif /* CONFIG_RT2500USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Check if the BBP tuning should be disabled. @@ -1665,10 +1654,11 @@ static const struct rf_channel rf_vals_5222[] = { { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 }, }; -static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -1687,20 +1677,10 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) EEPROM_MAC_ADDR_0)); /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); @@ -1722,6 +1702,26 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; } + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + if (spec->num_channels > 14) { + for (i = 14; i < spec->num_channels; i++) + info[i].tx_power1 = DEFAULT_TXPOWER; + } + + return 0; } static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -1742,7 +1742,9 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt2500usb_probe_hw_mode(rt2x00dev); + retval = rt2500usb_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires the atim queue diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 4769ffeb4cc..89e5ed24e4f 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -825,17 +825,10 @@ #define MAX_TXPOWER 31 #define DEFAULT_TXPOWER 24 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? \ - DEFAULT_TXPOWER : (__txpower); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ - (__txpower)); \ -}) +#define TXPOWER_FROM_DEV(__txpower) \ + (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER) #endif /* RT2500USB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 8b10ea41b20..1359a376840 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -44,7 +44,7 @@ /* * Module information. */ -#define DRV_VERSION "2.1.8" +#define DRV_VERSION "2.2.1" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* @@ -53,11 +53,11 @@ */ #define DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, __args...) \ printk(__kernlvl "%s -> %s: %s - " __msg, \ - wiphy_name((__dev)->hw->wiphy), __FUNCTION__, __lvl, ##__args) + wiphy_name((__dev)->hw->wiphy), __func__, __lvl, ##__args) #define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...) \ printk(__kernlvl "%s -> %s: %s - " __msg, \ - KBUILD_MODNAME, __FUNCTION__, __lvl, ##__args) + KBUILD_MODNAME, __func__, __lvl, ##__args) #ifdef CONFIG_RT2X00_DEBUG #define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \ @@ -144,6 +144,17 @@ struct rf_channel { }; /* + * Channel information structure + */ +struct channel_info { + unsigned int flags; +#define GEOGRAPHY_ALLOWED 0x00000001 + + short tx_power1; + short tx_power2; +}; + +/* * Antenna setup values. */ struct antenna_setup { @@ -394,10 +405,7 @@ static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) * @num_channels: Number of supported channels. This is used as array size * for @tx_power_a, @tx_power_bg and @channels. * @channels: Device/chipset specific channel values (See &struct rf_channel). - * @tx_power_a: TX power values for all 5.2GHz channels (may be NULL). - * @tx_power_bg: TX power values for all 2.4GHz channels (may be NULL). - * @tx_power_default: Default TX power value to use when either - * @tx_power_a or @tx_power_bg is missing. + * @channels_info: Additional information for channels (See &struct channel_info). */ struct hw_mode_spec { unsigned int supported_bands; @@ -410,10 +418,7 @@ struct hw_mode_spec { unsigned int num_channels; const struct rf_channel *channels; - - const u8 *tx_power_a; - const u8 *tx_power_bg; - u8 tx_power_default; + const struct channel_info *channels_info; }; /* @@ -425,7 +430,9 @@ struct hw_mode_spec { */ struct rt2x00lib_conf { struct ieee80211_conf *conf; + struct rf_channel rf; + struct channel_info channel; struct antenna_setup ant; @@ -452,6 +459,23 @@ struct rt2x00lib_erp { }; /* + * Configuration structure for hardware encryption. + */ +struct rt2x00lib_crypto { + enum cipher cipher; + + enum set_key_cmd cmd; + const u8 *address; + + u32 bssidx; + u32 aid; + + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +}; + +/* * Configuration structure wrapper around the * rt2x00 interface configuration handler. */ @@ -459,7 +483,7 @@ struct rt2x00intf_conf { /* * Interface type */ - enum ieee80211_if_types type; + enum nl80211_iftype type; /* * TSF sync value, this is dependant on the operation type. @@ -547,6 +571,12 @@ struct rt2x00lib_ops { /* * Configuration handlers. */ + int (*config_shared_key) (struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key); + int (*config_pairwise_key) (struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key); void (*config_filter) (struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags); void (*config_intf) (struct rt2x00_dev *rt2x00dev, @@ -599,17 +629,16 @@ enum rt2x00_flags { /* * Device state flags */ - DEVICE_PRESENT, - DEVICE_REGISTERED_HW, - DEVICE_INITIALIZED, - DEVICE_STARTED, - DEVICE_STARTED_SUSPEND, - DEVICE_ENABLED_RADIO, - DEVICE_DISABLED_RADIO_HW, - DEVICE_DIRTY_CONFIG, + DEVICE_STATE_PRESENT, + DEVICE_STATE_REGISTERED_HW, + DEVICE_STATE_INITIALIZED, + DEVICE_STATE_STARTED, + DEVICE_STATE_STARTED_SUSPEND, + DEVICE_STATE_ENABLED_RADIO, + DEVICE_STATE_DISABLED_RADIO_HW, /* - * Driver features + * Driver requirements */ DRIVER_REQUIRE_FIRMWARE, DRIVER_REQUIRE_BEACON_GUARD, @@ -618,9 +647,14 @@ enum rt2x00_flags { DRIVER_REQUIRE_DMA, /* - * Driver configuration + * Driver features */ CONFIG_SUPPORT_HW_BUTTON, + CONFIG_SUPPORT_HW_CRYPTO, + + /* + * Driver configuration + */ CONFIG_FRAME_TYPE, CONFIG_RF_SEQUENCE, CONFIG_EXTERNAL_LNA_A, @@ -769,6 +803,11 @@ struct rt2x00_dev { u32 *rf; /* + * LNA gain + */ + short lna_gain; + + /* * USB Max frame size (for rt2500usb & rt73usb). */ u16 usb_maxpacket; @@ -966,6 +1005,13 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list); +#ifdef CONFIG_RT2X00_LIB_CRYPTO +int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key); +#else +#define rt2x00mac_set_key NULL +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index d134c3be539..4d5e87b015a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -31,7 +31,7 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, - enum ieee80211_if_types type, + enum nl80211_iftype type, u8 *mac, u8 *bssid) { struct rt2x00intf_conf conf; @@ -40,11 +40,11 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, conf.type = type; switch (type) { - case IEEE80211_IF_TYPE_IBSS: - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: conf.sync = TSF_SYNC_BEACON; break; - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: conf.sync = TSF_SYNC_INFRA; break; default: @@ -121,7 +121,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * Antenna setup changes require the RX to be disabled, * else the changes will be ignored by the device. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK); /* @@ -136,7 +136,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00dev->link.ant.active.rx = libconf.ant.rx; rt2x00dev->link.ant.active.tx = libconf.ant.tx; - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); } @@ -245,6 +245,10 @@ config: memcpy(&libconf.rf, &rt2x00dev->spec.channels[conf->channel->hw_value], sizeof(libconf.rf)); + + memcpy(&libconf.channel, + &rt2x00dev->spec.channels_info[conf->channel->hw_value], + sizeof(libconf.channel)); } if (flags & CONFIG_UPDATE_ANTENNA) { diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c new file mode 100644 index 00000000000..5a858e5106c --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -0,0 +1,215 @@ +/* + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project + <http://rt2x00.serialmonkey.com> + + 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; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 crypto specific routines. + */ + +#include <linux/kernel.h> +#include <linux/module.h> + +#include "rt2x00.h" +#include "rt2x00lib.h" + +enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) +{ + switch (key->alg) { + case ALG_WEP: + if (key->keylen == LEN_WEP40) + return CIPHER_WEP64; + else + return CIPHER_WEP128; + case ALG_TKIP: + return CIPHER_TKIP; + case ALG_CCMP: + return CIPHER_AES; + default: + return CIPHER_NONE; + } +} + +unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) +{ + struct ieee80211_key_conf *key = tx_info->control.hw_key; + unsigned int overhead = 0; + + /* + * Extend frame length to include IV/EIV/ICV/MMIC, + * note that these lengths should only be added when + * mac80211 does not generate it. + */ + overhead += key->icv_len; + + if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) + overhead += key->iv_len; + + if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { + if (key->alg == ALG_TKIP) + overhead += 8; + } + + return overhead; +} + +void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); + + if (unlikely(!iv_len)) + return; + + /* Copy IV/EIV data */ + if (iv_len >= 4) + memcpy(&skbdesc->iv, skb->data + header_length, 4); + if (iv_len >= 8) + memcpy(&skbdesc->eiv, skb->data + header_length + 4, 4); + + /* Move ieee80211 header */ + memmove(skb->data + iv_len, skb->data, header_length); + + /* Pull buffer to correct size */ + skb_pull(skb, iv_len); + + /* IV/EIV data has officially be stripped */ + skbdesc->flags |= FRAME_DESC_IV_STRIPPED; +} + +void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); + const unsigned int iv_len = + ((!!(skbdesc->iv)) * 4) + ((!!(skbdesc->eiv)) * 4); + + if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED)) + return; + + skb_push(skb, iv_len); + + /* Move ieee80211 header */ + memmove(skb->data, skb->data + iv_len, header_length); + + /* Copy IV/EIV data */ + if (iv_len >= 4) + memcpy(skb->data + header_length, &skbdesc->iv, 4); + if (iv_len >= 8) + memcpy(skb->data + header_length + 4, &skbdesc->eiv, 4); + + /* IV/EIV data has returned into the frame */ + skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED; +} + +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, + unsigned int header_length, + struct rxdone_entry_desc *rxdesc) +{ + unsigned int payload_len = rxdesc->size - header_length; + unsigned int iv_len; + unsigned int icv_len; + unsigned int transfer = 0; + + /* + * WEP64/WEP128: Provides IV & ICV + * TKIP: Provides IV/EIV & ICV + * AES: Provies IV/EIV & ICV + */ + switch (rxdesc->cipher) { + case CIPHER_WEP64: + case CIPHER_WEP128: + iv_len = 4; + icv_len = 4; + break; + case CIPHER_TKIP: + iv_len = 8; + icv_len = 4; + break; + case CIPHER_AES: + iv_len = 8; + icv_len = 8; + break; + default: + /* Unsupport type */ + return; + } + + /* + * Make room for new data, note that we increase both + * headsize and tailsize when required. The tailsize is + * only needed when ICV data needs to be inserted and + * the padding is smaller then the ICV data. + * When alignment requirements is greater then the + * ICV data we must trim the skb to the correct size + * because we need to remove the extra bytes. + */ + skb_push(skb, iv_len + align); + if (align < icv_len) + skb_put(skb, icv_len - align); + else if (align > icv_len) + skb_trim(skb, rxdesc->size + iv_len + icv_len); + + /* Move ieee80211 header */ + memmove(skb->data + transfer, + skb->data + transfer + iv_len + align, + header_length); + transfer += header_length; + + /* Copy IV data */ + if (iv_len >= 4) { + memcpy(skb->data + transfer, &rxdesc->iv, 4); + transfer += 4; + } + + /* Copy EIV data */ + if (iv_len >= 8) { + memcpy(skb->data + transfer, &rxdesc->eiv, 4); + transfer += 4; + } + + /* Move payload */ + if (align) { + memmove(skb->data + transfer, + skb->data + transfer + align, + payload_len); + } + + /* + * NOTE: Always count the payload as transfered, + * even when alignment was set to zero. This is required + * for determining the correct offset for the ICV data. + */ + transfer += payload_len; + + /* Copy ICV data */ + if (icv_len >= 4) { + memcpy(skb->data + transfer, &rxdesc->icv, 4); + /* + * AES appends 8 bytes, we can't fill the upper + * 4 bytes, but mac80211 doesn't care about what + * we provide here anyway and strips it immediately. + */ + transfer += icv_len; + } + + /* IV/EIV/ICV has been inserted into frame */ + rxdesc->size = transfer; + rxdesc->flags &= ~RX_FLAG_IV_STRIPPED; +} diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 6bee1d611bb..5cf4c859e39 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -35,6 +35,13 @@ #define MAX_LINE_LENGTH 64 +struct rt2x00debug_crypto { + unsigned long success; + unsigned long icv_error; + unsigned long mic_error; + unsigned long key_error; +}; + struct rt2x00debug_intf { /* * Pointer to driver structure where @@ -63,6 +70,7 @@ struct rt2x00debug_intf { * - queue folder * - frame dump file * - queue stats file + * - crypto stats file */ struct dentry *driver_folder; struct dentry *driver_entry; @@ -80,6 +88,7 @@ struct rt2x00debug_intf { struct dentry *queue_folder; struct dentry *queue_frame_dump_entry; struct dentry *queue_stats_entry; + struct dentry *crypto_stats_entry; /* * The frame dump file only allows a single reader, @@ -98,6 +107,12 @@ struct rt2x00debug_intf { wait_queue_head_t frame_dump_waitqueue; /* + * HW crypto statistics. + * All statistics are stored seperately per cipher type. + */ + struct rt2x00debug_crypto crypto_stats[CIPHER_MAX]; + + /* * Driver and chipset files will use a data buffer * that has been created in advance. This will simplify * the code since we can use the debugfs functions. @@ -114,6 +129,25 @@ struct rt2x00debug_intf { unsigned int offset_rf; }; +void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, + enum cipher cipher, enum rx_crypto status) +{ + struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; + + if (cipher == CIPHER_TKIP_NO_MIC) + cipher = CIPHER_TKIP; + if (cipher == CIPHER_NONE || cipher > CIPHER_MAX) + return; + + /* Remove CIPHER_NONE index */ + cipher--; + + intf->crypto_stats[cipher].success += (status == RX_CRYPTO_SUCCESS); + intf->crypto_stats[cipher].icv_error += (status == RX_CRYPTO_FAIL_ICV); + intf->crypto_stats[cipher].mic_error += (status == RX_CRYPTO_FAIL_MIC); + intf->crypto_stats[cipher].key_error += (status == RX_CRYPTO_FAIL_KEY); +} + void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, enum rt2x00_dump_type type, struct sk_buff *skb) { @@ -327,6 +361,59 @@ static const struct file_operations rt2x00debug_fop_queue_stats = { .release = rt2x00debug_file_release, }; +#ifdef CONFIG_RT2X00_LIB_CRYPTO +static ssize_t rt2x00debug_read_crypto_stats(struct file *file, + char __user *buf, + size_t length, + loff_t *offset) +{ + struct rt2x00debug_intf *intf = file->private_data; + char *name[] = { "WEP64", "WEP128", "TKIP", "AES" }; + char *data; + char *temp; + size_t size; + unsigned int i; + + if (*offset) + return 0; + + data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL); + if (!data) + return -ENOMEM; + + temp = data; + temp += sprintf(data, "cipher\tsuccess\ticv err\tmic err\tkey err\n"); + + for (i = 0; i < CIPHER_MAX; i++) { + temp += sprintf(temp, "%s\t%lu\t%lu\t%lu\t%lu\n", name[i], + intf->crypto_stats[i].success, + intf->crypto_stats[i].icv_error, + intf->crypto_stats[i].mic_error, + intf->crypto_stats[i].key_error); + } + + size = strlen(data); + size = min(size, length); + + if (copy_to_user(buf, data, size)) { + kfree(data); + return -EFAULT; + } + + kfree(data); + + *offset += size; + return size; +} + +static const struct file_operations rt2x00debug_fop_crypto_stats = { + .owner = THIS_MODULE, + .read = rt2x00debug_read_crypto_stats, + .open = rt2x00debug_file_open, + .release = rt2x00debug_file_release, +}; +#endif + #define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ static ssize_t rt2x00debug_read_##__name(struct file *file, \ char __user *buf, \ @@ -569,6 +656,13 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) debugfs_create_file("queue", S_IRUSR, intf->queue_folder, intf, &rt2x00debug_fop_queue_stats); +#ifdef CONFIG_RT2X00_LIB_CRYPTO + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + intf->crypto_stats_entry = + debugfs_create_file("crypto", S_IRUGO, intf->queue_folder, + intf, &rt2x00debug_fop_crypto_stats); +#endif + return; exit: @@ -587,6 +681,9 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) skb_queue_purge(&intf->frame_dump_skbqueue); +#ifdef CONFIG_RT2X00_LIB_CRYPTO + debugfs_remove(intf->crypto_stats_entry); +#endif debugfs_remove(intf->queue_stats_entry); debugfs_remove(intf->queue_frame_dump_entry); debugfs_remove(intf->queue_folder); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f42283ad7b0..86840e3585e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -34,7 +34,7 @@ */ void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; /* @@ -94,8 +94,8 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) * Don't enable the radio twice. * And check if the hardware button has been disabled. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || + test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags)) return 0; /* @@ -117,7 +117,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) rt2x00leds_led_radio(rt2x00dev, true); rt2x00led_led_activity(rt2x00dev, true); - __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags); + set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); /* * Enable RX. @@ -134,7 +134,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) { - if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; /* @@ -354,7 +354,7 @@ static void rt2x00lib_link_tuner(struct work_struct *work) * When the radio is shutting down we should * immediately cease all link tuning. */ - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; /* @@ -431,7 +431,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, * note that in the spinlock protected area above the delayed_flags * have been cleared correctly. */ - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; if (delayed_flags & DELAYED_UPDATE_BEACON) @@ -467,8 +467,8 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); - if (vif->type != IEEE80211_IF_TYPE_AP && - vif->type != IEEE80211_IF_TYPE_IBSS) + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_ADHOC) return; /* @@ -484,7 +484,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, @@ -508,6 +508,15 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00queue_unmap_skb(rt2x00dev, entry->skb); /* + * If the IV/EIV data was stripped from the frame before it was + * passed to the hardware, we should now reinsert it again because + * mac80211 will expect the the same data to be present it the + * frame as it was passed to us. + */ + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + rt2x00crypto_tx_insert_iv(entry->skb); + + /* * Send frame to debugfs immediately, after this call is completed * we are going to overwrite the skb->cb array. */ @@ -563,7 +572,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry); - __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); /* @@ -585,7 +594,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; const struct rt2x00_rate *rate; - unsigned int header_size; + unsigned int header_length; unsigned int align; unsigned int i; int idx = -1; @@ -613,10 +622,19 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. */ - header_size = ieee80211_get_hdrlen_from_skb(entry->skb); - align = ((unsigned long)(entry->skb->data + header_size)) & 3; + header_length = ieee80211_get_hdrlen_from_skb(entry->skb); + align = ((unsigned long)(entry->skb->data + header_length)) & 3; - if (align) { + /* + * Hardware might have stripped the IV/EIV/ICV data, + * in that case it is possible that the data was + * provided seperately (through hardware descriptor) + * in which case we should reinsert the data into the frame. + */ + if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) { + rt2x00crypto_rx_insert_iv(entry->skb, align, + header_length, &rxdesc); + } else if (align) { skb_push(entry->skb, align); /* Move entire frame in 1 command */ memmove(entry->skb->data, entry->skb->data + align, @@ -635,7 +653,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && (rate->plcp == rxdesc.signal)) || - (!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && + ((rxdesc.dev_flags & RXDONE_SIGNAL_BITRATE) && (rate->bitrate == rxdesc.signal))) { idx = i; break; @@ -657,6 +675,10 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, (rxdesc.dev_flags & RXDONE_MY_BSS)) rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi); + rt2x00debug_update_crypto(rt2x00dev, + rxdesc.cipher, + rxdesc.cipher_status); + rt2x00dev->link.qual.rx_success++; rx_status->mactime = rxdesc.timestamp; @@ -796,7 +818,6 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, struct ieee80211_rate *rates; unsigned int num_rates; unsigned int i; - unsigned char tx_power; num_rates = 0; if (spec->supported_rates & SUPPORT_RATE_CCK) @@ -822,20 +843,9 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, * Initialize Channel list. */ for (i = 0; i < spec->num_channels; i++) { - if (spec->channels[i].channel <= 14) { - if (spec->tx_power_bg) - tx_power = spec->tx_power_bg[i]; - else - tx_power = spec->tx_power_default; - } else { - if (spec->tx_power_a) - tx_power = spec->tx_power_a[i]; - else - tx_power = spec->tx_power_default; - } - rt2x00lib_channel(&channels[i], - spec->channels[i].channel, tx_power, i); + spec->channels[i].channel, + spec->channels_info[i].tx_power1, i); } /* @@ -878,7 +888,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) { - if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags)) ieee80211_unregister_hw(rt2x00dev->hw); if (likely(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ])) { @@ -887,6 +897,8 @@ static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; } + + kfree(rt2x00dev->spec.channels_info); } static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -894,6 +906,9 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) struct hw_mode_spec *spec = &rt2x00dev->spec; int status; + if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags)) + return 0; + /* * Initialize HW modes. */ @@ -915,7 +930,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) return status; } - __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags); + set_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags); return 0; } @@ -925,7 +940,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) */ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) { - if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags)) return; /* @@ -948,7 +963,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) { int status; - if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags)) return 0; /* @@ -967,7 +982,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) return status; } - __set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags); + set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags); /* * Register the extra components. @@ -981,7 +996,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) { int retval; - if (test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return 0; /* @@ -999,28 +1014,18 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) if (retval) return retval; - /* - * Enable radio. - */ - retval = rt2x00lib_enable_radio(rt2x00dev); - if (retval) { - rt2x00lib_uninitialize(rt2x00dev); - return retval; - } - rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; - __set_bit(DEVICE_STARTED, &rt2x00dev->flags); - __set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); + set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); return 0; } void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return; /* @@ -1032,8 +1037,6 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; - - __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); } /* @@ -1049,6 +1052,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); + rt2x00dev->hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + /* * Let the driver probe the device to detect the capabilities. */ @@ -1088,7 +1096,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) rt2x00rfkill_allocate(rt2x00dev); rt2x00debug_register(rt2x00dev); - __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); + set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); return 0; @@ -1101,7 +1109,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) { - __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); + clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); /* * Disable radio. @@ -1146,14 +1154,15 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) int retval; NOTICE(rt2x00dev, "Going to sleep.\n"); - __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* * Only continue if mac80211 has open interfaces. */ - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || + !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) goto exit; - __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags); + + set_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags); /* * Disable radio. @@ -1203,8 +1212,8 @@ static void rt2x00lib_resume_intf(void *data, u8 *mac, /* * Master or Ad-hoc mode require a new beacon update. */ - if (vif->type == IEEE80211_IF_TYPE_AP || - vif->type == IEEE80211_IF_TYPE_IBSS) + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC) intf->delayed_flags |= DELAYED_UPDATE_BEACON; spin_unlock(&intf->lock); @@ -1225,7 +1234,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Only continue if mac80211 had open interfaces. */ - if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags)) return 0; /* @@ -1252,7 +1261,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * We are ready again to receive requests from mac80211. */ - __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); + set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); /* * It is possible that during that mac80211 has attempted @@ -1272,7 +1281,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) return 0; exit: - rt2x00lib_disable_radio(rt2x00dev); + rt2x00lib_stop(rt2x00dev); rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index c5fb3a72cf3..797eb619aa0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -88,7 +88,7 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev); */ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, - enum ieee80211_if_types type, + enum nl80211_iftype type, u8 *mac, u8 *bssid); void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, @@ -181,6 +181,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, enum rt2x00_dump_type type, struct sk_buff *skb); +void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, + enum cipher cipher, enum rx_crypto status); #else static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) { @@ -195,9 +197,54 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) { } + +static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, + enum cipher cipher, + enum rx_crypto status) +{ +} #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ /* + * Crypto handlers. + */ +#ifdef CONFIG_RT2X00_LIB_CRYPTO +enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key); +unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info); +void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len); +void rt2x00crypto_tx_insert_iv(struct sk_buff *skb); +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, + unsigned int header_length, + struct rxdone_entry_desc *rxdesc); +#else +static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) +{ + return CIPHER_NONE; +} + +static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) +{ + return 0; +} + +static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, + unsigned int iv_len) +{ +} + +static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) +{ +} + +static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, + unsigned int align, + unsigned int header_length, + struct rxdone_entry_desc *rxdesc) +{ +} +#endif + +/* * RFkill handlers. */ #ifdef CONFIG_RT2X00_LIB_RFKILL diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index d0650738863..2c6cc5c374f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -36,21 +36,22 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb); struct ieee80211_tx_info *rts_info; struct sk_buff *skb; - int size; + unsigned int data_length; + int retval = 0; if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) - size = sizeof(struct ieee80211_cts); + data_length = sizeof(struct ieee80211_cts); else - size = sizeof(struct ieee80211_rts); + data_length = sizeof(struct ieee80211_rts); - skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom); - if (!skb) { + skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom); + if (unlikely(!skb)) { WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n"); - return NETDEV_TX_BUSY; + return -ENOMEM; } skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); - skb_put(skb, size); + skb_put(skb, data_length); /* * Copy TX information over from original frame to @@ -63,7 +64,6 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, */ memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); rts_info = IEEE80211_SKB_CB(skb); - rts_info->control.hw_key = NULL; rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; @@ -73,22 +73,33 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, else rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; + skb->do_not_encrypt = 1; + + /* + * RTS/CTS frame should use the length of the frame plus any + * encryption overhead that will be added by the hardware. + */ +#ifdef CONFIG_RT2X00_LIB_CRYPTO + if (!frag_skb->do_not_encrypt) + data_length += rt2x00crypto_tx_overhead(tx_info); +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, - frag_skb->data, size, tx_info, + frag_skb->data, data_length, tx_info, (struct ieee80211_cts *)(skb->data)); else ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif, - frag_skb->data, size, tx_info, + frag_skb->data, data_length, tx_info, (struct ieee80211_rts *)(skb->data)); - if (rt2x00queue_write_tx_frame(queue, skb)) { + retval = rt2x00queue_write_tx_frame(queue, skb); + if (retval) { dev_kfree_skb_any(skb); WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); - return NETDEV_TX_BUSY; } - return NETDEV_TX_OK; + return retval; } int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) @@ -106,11 +117,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * Note that we can only stop the TX queues inside the TX path * due to possible race conditions in mac80211. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) { - ieee80211_stop_queues(hw); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + goto exit_fail; /* * Determine which queue to put packet on. @@ -141,26 +149,25 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS | IEEE80211_TX_CTL_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { - if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, qid); - return NETDEV_TX_BUSY; - } - - if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, qid); - return NETDEV_TX_BUSY; - } - } + if (rt2x00queue_available(queue) <= 1) + goto exit_fail; - if (rt2x00queue_write_tx_frame(queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, qid); - return NETDEV_TX_BUSY; + if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) + goto exit_fail; } + if (rt2x00queue_write_tx_frame(queue, skb)) + goto exit_fail; + if (rt2x00queue_threshold(queue)) ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_OK; + + exit_fail: + ieee80211_stop_queue(rt2x00dev->hw, qid); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(rt2x00mac_tx); @@ -168,7 +175,7 @@ int rt2x00mac_start(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; return rt2x00lib_start(rt2x00dev); @@ -179,7 +186,7 @@ void rt2x00mac_stop(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return; rt2x00lib_stop(rt2x00dev); @@ -199,12 +206,12 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, * Don't allow interfaces to be added * the device has disappeared. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || - !test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || + !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return -ENODEV; switch (conf->type) { - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: /* * We don't support mixed combinations of * sta and ap interfaces. @@ -220,8 +227,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, return -ENOBUFS; break; - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: /* * We don't support mixed combinations of * sta and ap interfaces. @@ -249,7 +256,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, */ for (i = 0; i < queue->limit; i++) { entry = &queue->entries[i]; - if (!__test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) + if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) break; } @@ -261,7 +268,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, * increase interface count and start initialization. */ - if (conf->type == IEEE80211_IF_TYPE_AP) + if (conf->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count++; else rt2x00dev->intf_sta_count++; @@ -270,7 +277,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, spin_lock_init(&intf->seqlock); intf->beacon = entry; - if (conf->type == IEEE80211_IF_TYPE_AP) + if (conf->type == NL80211_IFTYPE_AP) memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); @@ -303,12 +310,12 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * either the device has disappeared or when * no interface is present. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || - (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) || - (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || + (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || + (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) return; - if (conf->type == IEEE80211_IF_TYPE_AP) + if (conf->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count--; else rt2x00dev->intf_sta_count--; @@ -317,59 +324,59 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * Release beacon entry so it is available for * new interfaces again. */ - __clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); + clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); /* * Make sure the bssid and mac address registers * are cleared to prevent false ACKing of frames. */ rt2x00lib_config_intf(rt2x00dev, intf, - IEEE80211_IF_TYPE_INVALID, NULL, NULL); + NL80211_IFTYPE_UNSPECIFIED, NULL, NULL); } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; - int force_reconfig; + int radio_on; + int status; /* * Mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; /* - * Check if we need to disable the radio, - * if this is not the case, at least the RX must be disabled. + * Only change device state when the radio is enabled. It does not + * matter what parameters we have configured when the radio is disabled + * because we won't be able to send or receive anyway. Also note that + * some configuration parameters (e.g. channel and antenna values) can + * only be set when the radio is enabled. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) { - if (!conf->radio_enabled) - rt2x00lib_disable_radio(rt2x00dev); - else - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); - } + radio_on = test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); + if (conf->radio_enabled) { + /* For programming the values, we have to turn RX off */ + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); - /* - * When the DEVICE_DIRTY_CONFIG flag is set, the device has recently - * been started and the configuration must be forced upon the hardware. - * Otherwise registers will not be intialized correctly and could - * result in non-working hardware because essential registers aren't - * initialized. - */ - force_reconfig = - __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); + /* Enable the radio */ + status = rt2x00lib_enable_radio(rt2x00dev); + if (unlikely(status)) + return status; - rt2x00lib_config(rt2x00dev, conf, force_reconfig); + /* + * When we've just turned on the radio, we want to reprogram + * everything to ensure a consistent state + */ + rt2x00lib_config(rt2x00dev, conf, !radio_on); - /* - * Reenable RX only if the radio should be on. - */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + /* Turn RX back on */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - else if (conf->radio_enabled) - return rt2x00lib_enable_radio(rt2x00dev); + } else { + /* Disable the radio */ + rt2x00lib_disable_radio(rt2x00dev); + } return 0; } @@ -388,7 +395,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, * Mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; spin_lock(&intf->lock); @@ -467,6 +474,91 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); +#ifdef CONFIG_RT2X00_LIB_CRYPTO +int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + int (*set_key) (struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key); + struct rt2x00lib_crypto crypto; + + if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + return -EOPNOTSUPP; + else if (key->keylen > 32) + return -ENOSPC; + + memset(&crypto, 0, sizeof(crypto)); + + /* + * When in STA mode, bssidx is always 0 otherwise local_address[5] + * contains the bss number, see BSS_ID_MASK comments for details. + */ + if (rt2x00dev->intf_sta_count) + crypto.bssidx = 0; + else + crypto.bssidx = + local_address[5] & (rt2x00dev->ops->max_ap_intf - 1); + + crypto.cipher = rt2x00crypto_key_to_cipher(key); + if (crypto.cipher == CIPHER_NONE) + return -EOPNOTSUPP; + + crypto.cmd = cmd; + crypto.address = address; + + if (crypto.cipher == CIPHER_TKIP) { + if (key->keylen > NL80211_TKIP_DATA_OFFSET_ENCR_KEY) + memcpy(&crypto.key, + &key->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY], + sizeof(crypto.key)); + + if (key->keylen > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) + memcpy(&crypto.tx_mic, + &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], + sizeof(crypto.tx_mic)); + + if (key->keylen > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY) + memcpy(&crypto.rx_mic, + &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], + sizeof(crypto.rx_mic)); + } else + memcpy(&crypto.key, &key->key[0], key->keylen); + + /* + * Each BSS has a maximum of 4 shared keys. + * Shared key index values: + * 0) BSS0 key0 + * 1) BSS0 key1 + * ... + * 4) BSS1 key0 + * ... + * 8) BSS2 key0 + * ... + * Both pairwise as shared key indeces are determined by + * driver. This is required because the hardware requires + * keys to be assigned in correct order (When key 1 is + * provided but key 0 is not, then the key is not found + * by the hardware during RX). + */ + if (cmd == SET_KEY) + key->hw_key_idx = 0; + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + set_key = rt2x00dev->ops->lib->config_pairwise_key; + else + set_key = rt2x00dev->ops->lib->config_shared_key; + + if (!set_key) + return -EOPNOTSUPP; + + return set_key(rt2x00dev, &crypto, key); +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_key); +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ + int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { @@ -575,10 +667,11 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, queue->cw_max = 10; /* cw_min: 2^10 = 1024. */ queue->aifs = params->aifs; + queue->txop = params->txop; INFO(rt2x00dev, - "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", - queue_idx, queue->cw_min, queue->cw_max, queue->aifs); + "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n", + queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 898cdd7f57d..451d410ecda 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -33,10 +33,11 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - unsigned int frame_size; - unsigned int reserved_size; struct sk_buff *skb; struct skb_frame_desc *skbdesc; + unsigned int frame_size; + unsigned int head_size = 0; + unsigned int tail_size = 0; /* * The frame size includes descriptor size, because the @@ -49,16 +50,32 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, * this means we need at least 3 bytes for moving the frame * into the correct offset. */ - reserved_size = 4; + head_size = 4; + + /* + * For IV/EIV/ICV assembly we must make sure there is + * at least 8 bytes bytes available in headroom for IV/EIV + * and 4 bytes for ICV data as tailroon. + */ +#ifdef CONFIG_RT2X00_LIB_CRYPTO + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + head_size += 8; + tail_size += 4; + } +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * Allocate skbuffer. */ - skb = dev_alloc_skb(frame_size + reserved_size); + skb = dev_alloc_skb(frame_size + head_size + tail_size); if (!skb) return NULL; - skb_reserve(skb, reserved_size); + /* + * Make sure we not have a frame with the requested bytes + * available in the head and tail. + */ + skb_reserve(skb, head_size); skb_put(skb, frame_size); /* @@ -83,8 +100,21 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, - DMA_TO_DEVICE); + /* + * If device has requested headroom, we should make sure that + * is also mapped to the DMA so it can be used for transfering + * additional descriptor information to the hardware. + */ + skb_push(skb, rt2x00dev->hw->extra_tx_headroom); + + skbdesc->skb_dma = + dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); + + /* + * Restore data pointer to original location again. + */ + skb_pull(skb, rt2x00dev->hw->extra_tx_headroom); + skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; } EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); @@ -100,7 +130,12 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) } if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) { - dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, + /* + * Add headroom to the skb length, it has been removed + * by the driver, but it was actually mapped to DMA. + */ + dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, + skb->len + rt2x00dev->hw->extra_tx_headroom, DMA_TO_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; } @@ -120,7 +155,6 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); - struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; struct ieee80211_rate *rate = ieee80211_get_tx_rate(rt2x00dev->hw, tx_info); @@ -140,7 +174,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, txdesc->cw_max = entry->queue->cw_max; txdesc->aifs = entry->queue->aifs; - /* Data length should be extended with 4 bytes for CRC */ + /* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */ data_length = entry->skb->len + 4; /* @@ -149,6 +183,35 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) __set_bit(ENTRY_TXD_ACK, &txdesc->flags); +#ifdef CONFIG_RT2X00_LIB_CRYPTO + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) && + !entry->skb->do_not_encrypt) { + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; + + __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); + + txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key); + + if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags); + + txdesc->key_idx = hw_key->hw_key_idx; + txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); + + /* + * Extend frame length to include all encryption overhead + * that will be added by the hardware. + */ + data_length += rt2x00crypto_tx_overhead(tx_info); + + if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) + __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); + + if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) + __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags); + } +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ + /* * Check if this is a RTS/CTS frame */ @@ -214,16 +277,22 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * sequence counter given by mac80211. */ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - spin_lock_irqsave(&intf->seqlock, irqflags); + if (likely(tx_info->control.vif)) { + struct rt2x00_intf *intf; + + intf = vif_to_intf(tx_info->control.vif); - if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) - intf->seqno += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(intf->seqno); + spin_lock_irqsave(&intf->seqlock, irqflags); - spin_unlock_irqrestore(&intf->seqlock, irqflags); + if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) + intf->seqno += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(intf->seqno); - __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); + spin_unlock_irqrestore(&intf->seqlock, irqflags); + + __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); + } } /* @@ -305,11 +374,12 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; + unsigned int iv_len = 0; if (unlikely(rt2x00queue_full(queue))) return -EINVAL; - if (__test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { + if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { ERROR(queue->rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", @@ -325,22 +395,44 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) entry->skb = skb; rt2x00queue_create_tx_descriptor(entry, &txdesc); + if (IEEE80211_SKB_CB(skb)->control.hw_key != NULL) + iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; + /* - * skb->cb array is now ours and we are free to use it. + * All information is retreived from the skb->cb array, + * now we should claim ownership of the driver part of that + * array. */ skbdesc = get_skb_frame_desc(entry->skb); memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; + /* + * When hardware encryption is supported, and this frame + * is to be encrypted, we should strip the IV/EIV data from + * the frame so we can provide it to the driver seperately. + */ + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { + rt2x00crypto_tx_remove_iv(skb, iv_len); + } + + /* + * It could be possible that the queue was corrupted and this + * call failed. Just drop the frame, we cannot rollback and pass + * the frame to mac80211 because the skb->cb has now been tainted. + */ if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { - __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - return -EIO; + clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; + return 0; } if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) rt2x00queue_map_txskb(queue->rt2x00dev, skb); - __set_bit(ENTRY_DATA_PENDING, &entry->flags); + set_bit(ENTRY_DATA_PENDING, &entry->flags); rt2x00queue_index_inc(queue, Q_INDEX); rt2x00queue_write_tx_descriptor(entry, &txdesc); @@ -653,6 +745,7 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, queue->rt2x00dev = rt2x00dev; queue->qid = qid; + queue->txop = 0; queue->aifs = 2; queue->cw_min = 5; queue->cw_max = 10; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index ff78e52ce43..9dbf04f0f04 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -87,10 +87,13 @@ enum data_queue_qid { * * @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX + * @FRAME_DESC_IV_STRIPPED: Frame contained a IV/EIV provided by + * mac80211 but was stripped for processing by the driver. */ enum skb_frame_desc_flags { - SKBDESC_DMA_MAPPED_RX = (1 << 0), - SKBDESC_DMA_MAPPED_TX = (1 << 1), + SKBDESC_DMA_MAPPED_RX = 1 << 0, + SKBDESC_DMA_MAPPED_TX = 1 << 1, + FRAME_DESC_IV_STRIPPED = 1 << 2, }; /** @@ -104,6 +107,8 @@ enum skb_frame_desc_flags { * @desc: Pointer to descriptor part of the frame. * Note that this pointer could point to something outside * of the scope of the skb->data pointer. + * @iv: IV data used during encryption/decryption. + * @eiv: EIV data used during encryption/decryption. * @skb_dma: (PCI-only) the DMA address associated with the sk buffer. * @entry: The entry to which this sk buffer belongs. */ @@ -113,6 +118,9 @@ struct skb_frame_desc { unsigned int desc_len; void *desc; + __le32 iv; + __le32 eiv; + dma_addr_t skb_dma; struct queue_entry *entry; @@ -132,13 +140,14 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) /** * enum rxdone_entry_desc_flags: Flags for &struct rxdone_entry_desc * - * @RXDONE_SIGNAL_PLCP: Does the signal field contain the plcp value, - * or does it contain the bitrate itself. + * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value. + * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value. * @RXDONE_MY_BSS: Does this frame originate from device's BSS. */ enum rxdone_entry_desc_flags { RXDONE_SIGNAL_PLCP = 1 << 0, - RXDONE_MY_BSS = 1 << 1, + RXDONE_SIGNAL_BITRATE = 1 << 1, + RXDONE_MY_BSS = 1 << 2, }; /** @@ -152,7 +161,11 @@ enum rxdone_entry_desc_flags { * @size: Data size of the received frame. * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags). * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags). - + * @cipher: Cipher type used during decryption. + * @cipher_status: Decryption status. + * @iv: IV data used during decryption. + * @eiv: EIV data used during decryption. + * @icv: ICV data used during decryption. */ struct rxdone_entry_desc { u64 timestamp; @@ -161,6 +174,12 @@ struct rxdone_entry_desc { int size; int flags; int dev_flags; + u8 cipher; + u8 cipher_status; + + __le32 iv; + __le32 eiv; + __le32 icv; }; /** @@ -206,6 +225,10 @@ struct txdone_entry_desc { * @ENTRY_TXD_BURST: This frame belongs to the same burst event. * @ENTRY_TXD_ACK: An ACK is required for this frame. * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used. + * @ENTRY_TXD_ENCRYPT: This frame should be encrypted. + * @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared). + * @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware. + * @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware. */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, @@ -218,6 +241,10 @@ enum txentry_desc_flags { ENTRY_TXD_BURST, ENTRY_TXD_ACK, ENTRY_TXD_RETRY_MODE, + ENTRY_TXD_ENCRYPT, + ENTRY_TXD_ENCRYPT_PAIRWISE, + ENTRY_TXD_ENCRYPT_IV, + ENTRY_TXD_ENCRYPT_MMIC, }; /** @@ -236,6 +263,9 @@ enum txentry_desc_flags { * @ifs: IFS value. * @cw_min: cwmin value. * @cw_max: cwmax value. + * @cipher: Cipher type used for encryption. + * @key_idx: Key index used for encryption. + * @iv_offset: Position where IV should be inserted by hardware. */ struct txentry_desc { unsigned long flags; @@ -252,6 +282,10 @@ struct txentry_desc { short ifs; short cw_min; short cw_max; + + enum cipher cipher; + u16 key_idx; + u16 iv_offset; }; /** @@ -335,6 +369,7 @@ enum queue_index { * @length: Number of frames in queue. * @index: Index pointers to entry positions in the queue, * use &enum queue_index to get a specific index field. + * @txop: maximum burst time. * @aifs: The aifs value for outgoing frames (field ignored in RX queue). * @cw_min: The cw min value for outgoing frames (field ignored in RX queue). * @cw_max: The cw max value for outgoing frames (field ignored in RX queue). @@ -354,6 +389,7 @@ struct data_queue { unsigned short length; unsigned short index[Q_INDEX_MAX]; + unsigned short txop; unsigned short aifs; unsigned short cw_min; unsigned short cw_max; @@ -484,25 +520,51 @@ static inline int rt2x00queue_threshold(struct data_queue *queue) } /** - * rt2x00_desc_read - Read a word from the hardware descriptor. + * _rt2x00_desc_read - Read a word from the hardware descriptor. + * @desc: Base descriptor address + * @word: Word index from where the descriptor should be read. + * @value: Address where the descriptor value should be written into. + */ +static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value) +{ + *value = desc[word]; +} + +/** + * rt2x00_desc_read - Read a word from the hardware descriptor, this + * function will take care of the byte ordering. * @desc: Base descriptor address * @word: Word index from where the descriptor should be read. * @value: Address where the descriptor value should be written into. */ static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value) { - *value = le32_to_cpu(desc[word]); + __le32 tmp; + _rt2x00_desc_read(desc, word, &tmp); + *value = le32_to_cpu(tmp); +} + +/** + * rt2x00_desc_write - write a word to the hardware descriptor, this + * function will take care of the byte ordering. + * @desc: Base descriptor address + * @word: Word index from where the descriptor should be written. + * @value: Value that should be written into the descriptor. + */ +static inline void _rt2x00_desc_write(__le32 *desc, const u8 word, __le32 value) +{ + desc[word] = value; } /** - * rt2x00_desc_write - wrote a word to the hardware descriptor. + * rt2x00_desc_write - write a word to the hardware descriptor. * @desc: Base descriptor address * @word: Word index from where the descriptor should be written. * @value: Value that should be written into the descriptor. */ static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value) { - desc[word] = cpu_to_le32(value); + _rt2x00_desc_write(desc, word, cpu_to_le32(value)); } #endif /* RT2X00QUEUE_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 2ea7866abd5..c2fba7c9f05 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -27,6 +27,16 @@ #define RT2X00REG_H /* + * RX crypto status + */ +enum rx_crypto { + RX_CRYPTO_SUCCESS = 0, + RX_CRYPTO_FAIL_ICV = 1, + RX_CRYPTO_FAIL_MIC = 2, + RX_CRYPTO_FAIL_KEY = 3, +}; + +/* * Antenna values */ enum antenna { @@ -104,7 +114,14 @@ enum cipher { */ CIPHER_CKIP64 = 5, CIPHER_CKIP128 = 6, - CIPHER_TKIP_NO_MIC = 7, + CIPHER_TKIP_NO_MIC = 7, /* Don't send to device */ + +/* + * Max cipher type. + * Note that CIPHER_NONE isn't counted, and CKIP64 and CKIP128 + * are excluded due to limitations in mac80211. + */ + CIPHER_MAX = 4, }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index 04b29716d35..c3f53a92180 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -41,20 +41,19 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) /* * Only continue if there are enabled interfaces. */ - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return 0; if (state == RFKILL_STATE_UNBLOCKED) { - INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); - __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); + INFO(rt2x00dev, "RFKILL event: enabling radio.\n"); + clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); retval = rt2x00lib_enable_radio(rt2x00dev); } else if (state == RFKILL_STATE_SOFT_BLOCKED) { - INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); - __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); + INFO(rt2x00dev, "RFKILL event: disabling radio.\n"); + set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); rt2x00lib_disable_radio(rt2x00dev); } else { - WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n", - state); + WARNING(rt2x00dev, "RFKILL event: unknown state %d.\n", state); } return retval; @@ -64,7 +63,12 @@ static int rt2x00rfkill_get_state(void *data, enum rfkill_state *state) { struct rt2x00_dev *rt2x00dev = data; - *state = rt2x00dev->rfkill->state; + /* + * rfkill_poll reports 1 when the key has been pressed and the + * radio should be blocked. + */ + *state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? + RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; return 0; } @@ -73,19 +77,18 @@ static void rt2x00rfkill_poll(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, rfkill_work.work); - int state; + enum rfkill_state state; - if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) + if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) || + !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return; /* - * rfkill_poll reports 1 when the key has been pressed and the - * radio should be blocked. + * Poll latest state and report it to rfkill who should sort + * out if the state should be toggled or not. */ - state = !rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; - - rfkill_force_state(rt2x00dev->rfkill, state); + if (!rt2x00rfkill_get_state(rt2x00dev, &state)) + rfkill_force_state(rt2x00dev->rfkill, state); queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->rfkill_work, RFKILL_POLL_INTERVAL); @@ -93,8 +96,8 @@ static void rt2x00rfkill_poll(struct work_struct *work) void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || - !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) + if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || + test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) return; if (rfkill_register(rt2x00dev->rfkill)) { @@ -114,7 +117,7 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || + if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) return; @@ -127,21 +130,30 @@ void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + struct device *dev = wiphy_dev(rt2x00dev->hw->wiphy); + + if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) return; - rt2x00dev->rfkill = - rfkill_allocate(wiphy_dev(rt2x00dev->hw->wiphy), RFKILL_TYPE_WLAN); + rt2x00dev->rfkill = rfkill_allocate(dev, RFKILL_TYPE_WLAN); if (!rt2x00dev->rfkill) { ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); return; } + __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state); + rt2x00dev->rfkill->name = rt2x00dev->ops->name; rt2x00dev->rfkill->data = rt2x00dev; - rt2x00dev->rfkill->state = -1; rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; - rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; + if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) { + rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; + rt2x00dev->rfkill->state = + rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? + RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; + } else { + rt2x00dev->rfkill->state = RFKILL_STATE_UNBLOCKED; + } INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll); @@ -150,8 +162,7 @@ void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || - !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) + if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->flags)) return; cancel_delayed_work_sync(&rt2x00dev->rfkill_work); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 2050227ea53..b73a7e0aeed 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -163,16 +163,11 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct txdone_entry_desc txdesc; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* - * Remove the descriptor data from the buffer. - */ - skb_pull(entry->skb, entry->queue->desc_size); - - /* * Obtain the status about this packet. * Note that when the status is 0 it does not mean the * frame was send out correctly. It only means the frame @@ -224,6 +219,12 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry) entry->skb->data, length, rt2x00usb_interrupt_txdone, entry); + /* + * Make sure the skb->data pointer points to the frame, not the + * descriptor. + */ + skb_pull(entry->skb, entry->queue->desc_size); + return 0; } EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); @@ -232,7 +233,7 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) { struct queue_entry_priv_usb *entry_priv = entry->priv_data; - if (__test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) + if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } @@ -283,7 +284,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u8 rxd[32]; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; @@ -293,7 +294,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * a problem. */ if (urb->actual_length < entry->queue->desc_size || urb->status) { - __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); usb_submit_urb(urb, GFP_ATOMIC); return; } @@ -361,7 +362,7 @@ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, entry->skb->data, entry->skb->len, rt2x00usb_interrupt_rxdone, entry); - __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 087e90b328c..a461620b489 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -38,6 +38,13 @@ #include "rt61pci.h" /* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 0; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + +/* * Register access. * BBP and RF register require indirect register access, * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this. @@ -156,7 +163,7 @@ rf_write: rt2x00_rf_write(rt2x00dev, word, value); } -#ifdef CONFIG_RT61PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS /* * This function is only called from rt61pci_led_brightness() * make gcc happy by placing this function inside the @@ -188,7 +195,7 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); } -#endif /* CONFIG_RT61PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) { @@ -264,7 +271,7 @@ static const struct rt2x00debug rt61pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT61PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -274,9 +281,9 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) } #else #define rt61pci_rfkill_poll NULL -#endif /* CONFIG_RT61PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ -#ifdef CONFIG_RT61PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt61pci_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -341,11 +348,209 @@ static void rt61pci_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt61pci_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT61PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. */ +static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + struct rt2x00_field32 field; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for shared keys. We have 1 register + * with key valid bits. The goal is simple, read + * the register, if that is full we have no slots + * left. + * Note that each BSS is allowed to have up to 4 + * shared keys, so put a mask over the allowed + * entries. + */ + mask = (0xf << crypto->bssidx); + + rt2x00pci_register_read(rt2x00dev, SEC_CSR0, ®); + reg &= mask; + + if (reg && reg == mask) + return -ENOSPC; + + key->hw_key_idx += reg ? ffz(reg) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + reg = SHARED_KEY_ENTRY(key->hw_key_idx); + rt2x00pci_register_multiwrite(rt2x00dev, reg, + &key_entry, sizeof(key_entry)); + + /* + * The cipher types are stored over 2 registers. + * bssidx 0 and 1 keys are stored in SEC_CSR1 and + * bssidx 1 and 2 keys are stored in SEC_CSR5. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ + if (key->hw_key_idx < 8) { + field.bit_offset = (3 * key->hw_key_idx); + field.bit_mask = 0x7 << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, SEC_CSR1, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt2x00pci_register_write(rt2x00dev, SEC_CSR1, reg); + } else { + field.bit_offset = (3 * (key->hw_key_idx - 8)); + field.bit_mask = 0x7 << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, SEC_CSR5, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt2x00pci_register_write(rt2x00dev, SEC_CSR5, reg); + } + + /* + * The driver does not support the IV/EIV generation + * in hardware. However it doesn't support the IV/EIV + * inside the ieee80211 frame either, but requires it + * to be provided seperately for the descriptor. + * rt2x00lib will cut the IV/EIV data out of all frames + * given to us by mac80211, but we must tell mac80211 + * to generate the IV/EIV data. + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + + /* + * SEC_CSR0 contains only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + mask = 1 << key->hw_key_idx; + + rt2x00pci_register_read(rt2x00dev, SEC_CSR0, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt2x00pci_register_write(rt2x00dev, SEC_CSR0, reg); + + return 0; +} + +static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_pairwise_ta_entry addr_entry; + struct hw_key_entry key_entry; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for pairwise keys. We have 2 registers + * with key valid bits. The goal is simple, read + * the first register, if that is full move to + * the next register. + * When both registers are full, we drop the key, + * otherwise we use the first invalid entry. + */ + rt2x00pci_register_read(rt2x00dev, SEC_CSR2, ®); + if (reg && reg == ~0) { + key->hw_key_idx = 32; + rt2x00pci_register_read(rt2x00dev, SEC_CSR3, ®); + if (reg && reg == ~0) + return -ENOSPC; + } + + key->hw_key_idx += reg ? ffz(reg) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + memset(&addr_entry, 0, sizeof(addr_entry)); + memcpy(&addr_entry, crypto->address, ETH_ALEN); + addr_entry.cipher = crypto->cipher; + + reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx); + rt2x00pci_register_multiwrite(rt2x00dev, reg, + &key_entry, sizeof(key_entry)); + + reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); + rt2x00pci_register_multiwrite(rt2x00dev, reg, + &addr_entry, sizeof(addr_entry)); + + /* + * Enable pairwise lookup table for given BSS idx, + * without this received frames will not be decrypted + * by the hardware. + */ + rt2x00pci_register_read(rt2x00dev, SEC_CSR4, ®); + reg |= (1 << crypto->bssidx); + rt2x00pci_register_write(rt2x00dev, SEC_CSR4, reg); + + /* + * The driver does not support the IV/EIV generation + * in hardware. However it doesn't support the IV/EIV + * inside the ieee80211 frame either, but requires it + * to be provided seperately for the descriptor. + * rt2x00lib will cut the IV/EIV data out of all frames + * given to us by mac80211, but we must tell mac80211 + * to generate the IV/EIV data. + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + + /* + * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + if (key->hw_key_idx < 32) { + mask = 1 << key->hw_key_idx; + + rt2x00pci_register_read(rt2x00dev, SEC_CSR2, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt2x00pci_register_write(rt2x00dev, SEC_CSR2, reg); + } else { + mask = 1 << (key->hw_key_idx - 32); + + rt2x00pci_register_read(rt2x00dev, SEC_CSR3, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt2x00pci_register_write(rt2x00dev, SEC_CSR3, reg); + } + + return 0; +} + static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags) { @@ -440,6 +645,30 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); } + +static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain = 0; + + if (libconf->band == IEEE80211_BAND_2GHZ) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } + + rt2x00dev->lna_gain = lna_gain; +} + static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, const int basic_rate_mask) { @@ -758,6 +987,9 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { + /* Always recalculate LNA gain before changing configuration */ + rt61pci_config_lna_gain(rt2x00dev, libconf); + if (flags & CONFIG_UPDATE_PHYMODE) rt61pci_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) @@ -1246,16 +1478,6 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); - rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, ®); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); - rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg); - - rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, ®); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); - rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); - /* * Clear all beacons * For the Beacon base registers we only need to clear @@ -1533,8 +1755,8 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct txentry_desc *txdesc) + struct sk_buff *skb, + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1548,7 +1770,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); - rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); @@ -1561,6 +1783,11 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 2, word); + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { + _rt2x00_desc_write(txd, 3, skbdesc->iv); + _rt2x00_desc_write(txd, 4, skbdesc->eiv); + } + rt2x00_desc_read(txd, 5, &word); rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid); rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, @@ -1595,11 +1822,15 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, + test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, + test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_BURST, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); rt2x00_desc_write(txd, 0, word); } @@ -1676,40 +1907,27 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, */ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) { - u16 eeprom; - u8 offset; + u8 offset = rt2x00dev->lna_gain; u8 lna; lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); switch (lna) { case 3: - offset = 90; + offset += 90; break; case 2: - offset = 74; + offset += 74; break; case 1: - offset = 64; + offset += 64; break; default: return 0; } if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) - offset += 14; - if (lna == 3 || lna == 2) offset += 10; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } else { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - offset += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; @@ -1718,6 +1936,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) static void rt61pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word1; @@ -1728,6 +1947,38 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + rxdesc->cipher = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG); + rxdesc->cipher_status = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); + } + + if (rxdesc->cipher != CIPHER_NONE) { + _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv); + _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->eiv); + _rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv); + + /* + * Hardware has stripped IV/EIV data from 802.11 frame during + * decryption. It has provided the data seperately but rt2x00lib + * should decide if it should be reinserted. + */ + rxdesc->flags |= RX_FLAG_IV_STRIPPED; + + /* + * FIXME: Legacy driver indicates that the frame does + * contain the Michael Mic. Unfortunately, in rt2x00 + * the MIC seems to be missing completely... + */ + rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; + + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + rxdesc->flags |= RX_FLAG_DECRYPTED; + else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } + /* * Obtain the status about this packet. * When frame was received with an OFDM bitrate, @@ -1735,11 +1986,13 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, * a CCK bitrate the signal is the rate in 100kbit/s. */ rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1); + rxdesc->rssi = rt61pci_agc_to_rssi(rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; } @@ -1860,7 +2113,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) if (!reg && !reg_mcu) return IRQ_NONE; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; /* @@ -2060,10 +2313,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT61PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT61PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Read frequency offset and RF programming sequence. @@ -2121,7 +2374,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * If the eeprom value is invalid, * switch to default led mode. */ -#ifdef CONFIG_RT61PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); @@ -2155,7 +2408,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_RDY_A)); -#endif /* CONFIG_RT61PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ return 0; } @@ -2274,10 +2527,11 @@ static const struct rf_channel rf_vals_seq[] = { { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 }, }; -static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -2294,20 +2548,10 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) EEPROM_MAC_ADDR_0)); /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) { spec->num_channels = 14; @@ -2321,13 +2565,28 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_rf(&rt2x00dev->chip, RF5325)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_seq); + } - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; - spec->tx_power_a = txpower; + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + if (spec->num_channels > 14) { + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); + for (i = 14; i < spec->num_channels; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); } + + return 0; } static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -2348,13 +2607,17 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt61pci_probe_hw_mode(rt2x00dev); + retval = rt61pci_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires firmware and DMA mapped skbs. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); + if (!modparam_nohwcrypt) + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); /* * Set the rssi offset. @@ -2381,6 +2644,63 @@ static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, return 0; } +static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + if (queue_idx < 2) { + field.bit_offset = queue_idx * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + } else if (queue_idx < 4) { + field.bit_offset = (queue_idx - 2) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + } + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, AIFSN_CSR, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt2x00pci_register_write(rt2x00dev, AIFSN_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt2x00pci_register_write(rt2x00dev, CWMIN_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt2x00pci_register_write(rt2x00dev, CWMAX_CSR, reg); + + return 0; +} + static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2404,10 +2724,11 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, - .conf_tx = rt2x00mac_conf_tx, + .conf_tx = rt61pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, }; @@ -2432,6 +2753,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .write_beacon = rt61pci_write_beacon, .kick_tx_queue = rt61pci_kick_tx_queue, .fill_rxdone = rt61pci_fill_rxdone, + .config_shared_key = rt61pci_config_shared_key, + .config_pairwise_key = rt61pci_config_pairwise_key, .config_filter = rt61pci_config_filter, .config_intf = rt61pci_config_intf, .config_erp = rt61pci_config_erp, diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 1004d5b899e..8ec1451308c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -134,6 +134,16 @@ #define PAIRWISE_KEY_TABLE_BASE 0x1200 #define PAIRWISE_TA_TABLE_BASE 0x1a00 +#define SHARED_KEY_ENTRY(__idx) \ + ( SHARED_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry)) ) +#define PAIRWISE_KEY_ENTRY(__idx) \ + ( PAIRWISE_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry)) ) +#define PAIRWISE_TA_ENTRY(__idx) \ + ( PAIRWISE_TA_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_pairwise_ta_entry)) ) + struct hw_key_entry { u8 key[16]; u8 tx_mic[8]; @@ -142,7 +152,8 @@ struct hw_key_entry { struct hw_pairwise_ta_entry { u8 address[6]; - u8 reserved[2]; + u8 cipher; + u8 reserved; } __attribute__ ((packed)); /* @@ -662,6 +673,10 @@ struct hw_pairwise_ta_entry { * SEC_CSR4: Pairwise key table lookup control. */ #define SEC_CSR4 0x30b0 +#define SEC_CSR4_ENABLE_BSS0 FIELD32(0x00000001) +#define SEC_CSR4_ENABLE_BSS1 FIELD32(0x00000002) +#define SEC_CSR4_ENABLE_BSS2 FIELD32(0x00000004) +#define SEC_CSR4_ENABLE_BSS3 FIELD32(0x00000008) /* * SEC_CSR5: shared key table security mode register. @@ -1428,8 +1443,10 @@ struct hw_pairwise_ta_entry { /* * Word4 + * ICV: Received ICV of originally encrypted. + * NOTE: This is a guess, the official definition is "reserved" */ -#define RXD_W4_RESERVED FIELD32(0xffffffff) +#define RXD_W4_ICV FIELD32(0xffffffff) /* * the above 20-byte is called RXINFO and will be DMAed to MAC RX block @@ -1465,17 +1482,10 @@ struct hw_pairwise_ta_entry { #define MAX_TXPOWER 31 #define DEFAULT_TXPOWER 24 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? \ - DEFAULT_TXPOWER : (__txpower); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ - (__txpower)); \ -}) +#define TXPOWER_FROM_DEV(__txpower) \ + (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER) #endif /* RT61PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 9761eaaa08b..934f8e03c5a 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -37,6 +37,13 @@ #include "rt73usb.h" /* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 0; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + +/* * Register access. * All access to the CSR registers will go through the methods * rt73usb_register_read and rt73usb_register_write. @@ -285,7 +292,7 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT73USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt73usb_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -352,11 +359,224 @@ static void rt73usb_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt73usb_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT73USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. */ +static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + struct rt2x00_field32 field; + int timeout; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for shared keys. We have 1 register + * with key valid bits. The goal is simple, read + * the register, if that is full we have no slots + * left. + * Note that each BSS is allowed to have up to 4 + * shared keys, so put a mask over the allowed + * entries. + */ + mask = (0xf << crypto->bssidx); + + rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + reg &= mask; + + if (reg && reg == mask) + return -ENOSPC; + + key->hw_key_idx += reg ? ffz(reg) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + reg = SHARED_KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, reg, + &key_entry, + sizeof(key_entry), + timeout); + + /* + * The cipher types are stored over 2 registers. + * bssidx 0 and 1 keys are stored in SEC_CSR1 and + * bssidx 1 and 2 keys are stored in SEC_CSR5. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ + if (key->hw_key_idx < 8) { + field.bit_offset = (3 * key->hw_key_idx); + field.bit_mask = 0x7 << field.bit_offset; + + rt73usb_register_read(rt2x00dev, SEC_CSR1, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt73usb_register_write(rt2x00dev, SEC_CSR1, reg); + } else { + field.bit_offset = (3 * (key->hw_key_idx - 8)); + field.bit_mask = 0x7 << field.bit_offset; + + rt73usb_register_read(rt2x00dev, SEC_CSR5, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt73usb_register_write(rt2x00dev, SEC_CSR5, reg); + } + + /* + * The driver does not support the IV/EIV generation + * in hardware. However it doesn't support the IV/EIV + * inside the ieee80211 frame either, but requires it + * to be provided seperately for the descriptor. + * rt2x00lib will cut the IV/EIV data out of all frames + * given to us by mac80211, but we must tell mac80211 + * to generate the IV/EIV data. + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + + /* + * SEC_CSR0 contains only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + mask = 1 << key->hw_key_idx; + + rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt73usb_register_write(rt2x00dev, SEC_CSR0, reg); + + return 0; +} + +static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_pairwise_ta_entry addr_entry; + struct hw_key_entry key_entry; + int timeout; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for pairwise keys. We have 2 registers + * with key valid bits. The goal is simple, read + * the first register, if that is full move to + * the next register. + * When both registers are full, we drop the key, + * otherwise we use the first invalid entry. + */ + rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + if (reg && reg == ~0) { + key->hw_key_idx = 32; + rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + if (reg && reg == ~0) + return -ENOSPC; + } + + key->hw_key_idx += reg ? ffz(reg) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, reg, + &key_entry, + sizeof(key_entry), + timeout); + + /* + * Send the address and cipher type to the hardware register. + * This data fits within the CSR cache size, so we can use + * rt73usb_register_multiwrite() directly. + */ + memset(&addr_entry, 0, sizeof(addr_entry)); + memcpy(&addr_entry, crypto->address, ETH_ALEN); + addr_entry.cipher = crypto->cipher; + + reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); + rt73usb_register_multiwrite(rt2x00dev, reg, + &addr_entry, sizeof(addr_entry)); + + /* + * Enable pairwise lookup table for given BSS idx, + * without this received frames will not be decrypted + * by the hardware. + */ + rt73usb_register_read(rt2x00dev, SEC_CSR4, ®); + reg |= (1 << crypto->bssidx); + rt73usb_register_write(rt2x00dev, SEC_CSR4, reg); + + /* + * The driver does not support the IV/EIV generation + * in hardware. However it doesn't support the IV/EIV + * inside the ieee80211 frame either, but requires it + * to be provided seperately for the descriptor. + * rt2x00lib will cut the IV/EIV data out of all frames + * given to us by mac80211, but we must tell mac80211 + * to generate the IV/EIV data. + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + + /* + * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + if (key->hw_key_idx < 32) { + mask = 1 << key->hw_key_idx; + + rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt73usb_register_write(rt2x00dev, SEC_CSR2, reg); + } else { + mask = 1 << (key->hw_key_idx - 32); + + rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt73usb_register_write(rt2x00dev, SEC_CSR3, reg); + } + + return 0; +} + static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags) { @@ -451,6 +671,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); } +static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain = 0; + + if (libconf->band == IEEE80211_BAND_2GHZ) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } + + rt2x00dev->lna_gain = lna_gain; +} + static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, const int basic_rate_mask) { @@ -705,6 +945,9 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { + /* Always recalculate LNA gain before changing configuration */ + rt73usb_config_lna_gain(rt2x00dev, libconf); + if (flags & CONFIG_UPDATE_PHYMODE) rt73usb_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) @@ -1034,16 +1277,6 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); - - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); @@ -1265,8 +1498,8 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct txentry_desc *txdesc) + struct sk_buff *skb, + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1280,7 +1513,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); - rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); rt2x00_desc_write(txd, 1, word); @@ -1292,6 +1525,11 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 2, word); + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { + _rt2x00_desc_write(txd, 3, skbdesc->iv); + _rt2x00_desc_write(txd, 4, skbdesc->eiv); + } + rt2x00_desc_read(txd, 5, &word); rt2x00_set_field32(&word, TXD_W5_TX_POWER, TXPOWER_TO_DEV(rt2x00dev->tx_power)); @@ -1313,12 +1551,15 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, - skb->len - skbdesc->desc_len); + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, + test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, + test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_BURST2, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); rt2x00_desc_write(txd, 0, word); } @@ -1331,7 +1572,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); unsigned int beacon_base; u32 reg; - u32 word, len; /* * Add the descriptor in front of the skb. @@ -1341,17 +1581,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) skbdesc->desc = entry->skb->data; /* - * Adjust the beacon databyte count. The current number is - * calculated before this function gets called, but falsely - * assumes that the descriptor was already present in the SKB. - */ - rt2x00_desc_read(skbdesc->desc, 0, &word); - len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); - len += skbdesc->desc_len; - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); - rt2x00_desc_write(skbdesc->desc, 0, word); - - /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ @@ -1422,20 +1651,19 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, */ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) { - u16 eeprom; - u8 offset; + u8 offset = rt2x00dev->lna_gain; u8 lna; lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); switch (lna) { case 3: - offset = 90; + offset += 90; break; case 2: - offset = 74; + offset += 74; break; case 1: - offset = 64; + offset += 64; break; default: return 0; @@ -1451,15 +1679,6 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) else if (lna == 2) offset += 8; } - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } else { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - offset += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; @@ -1468,6 +1687,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) static void rt73usb_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)entry->skb->data; u32 word0; @@ -1489,6 +1709,38 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + rxdesc->cipher = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG); + rxdesc->cipher_status = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); + } + + if (rxdesc->cipher != CIPHER_NONE) { + _rt2x00_desc_read(rxd, 2, &rxdesc->iv); + _rt2x00_desc_read(rxd, 3, &rxdesc->eiv); + _rt2x00_desc_read(rxd, 4, &rxdesc->icv); + + /* + * Hardware has stripped IV/EIV data from 802.11 frame during + * decryption. It has provided the data seperately but rt2x00lib + * should decide if it should be reinserted. + */ + rxdesc->flags |= RX_FLAG_IV_STRIPPED; + + /* + * FIXME: Legacy driver indicates that the frame does + * contain the Michael Mic. Unfortunately, in rt2x00 + * the MIC seems to be missing completely... + */ + rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; + + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + rxdesc->flags |= RX_FLAG_DECRYPTED; + else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } + /* * Obtain the status about this packet. * When frame was received with an OFDM bitrate, @@ -1496,11 +1748,13 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, * a CCK bitrate the signal is the rate in 100kbit/s. */ rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1); + rxdesc->rssi = rt73usb_agc_to_rssi(rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; @@ -1678,7 +1932,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led settings, for correct led behaviour. */ -#ifdef CONFIG_RT73USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); rt73usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); @@ -1711,7 +1965,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_RDY_A)); -#endif /* CONFIG_RT73USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ return 0; } @@ -1852,10 +2106,11 @@ static const struct rf_channel rf_vals_5225_2527[] = { }; -static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -1872,20 +2127,10 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) EEPROM_MAC_ADDR_0)); /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; if (rt2x00_rf(&rt2x00dev->chip, RF2528)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528); @@ -1903,14 +2148,26 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels = rf_vals_5225_2527; } - if (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF5226)) { - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; - spec->tx_power_a = txpower; + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + if (spec->num_channels > 14) { + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); + for (i = 14; i < spec->num_channels; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); } + + return 0; } static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -1931,13 +2188,17 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt73usb_probe_hw_mode(rt2x00dev); + retval = rt73usb_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); + if (!modparam_nohwcrypt) + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1964,6 +2225,63 @@ static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, return 0; } +static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + if (queue_idx < 2) { + field.bit_offset = queue_idx * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, field, queue->txop); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + } else if (queue_idx < 4) { + field.bit_offset = (queue_idx - 2) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, field, queue->txop); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + } + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AIFSN_CSR, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg); + + rt73usb_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg); + + rt73usb_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg); + + return 0; +} + #if 0 /* * Mac80211 demands get_tsf must be atomic. @@ -1997,10 +2315,11 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, - .conf_tx = rt2x00mac_conf_tx, + .conf_tx = rt73usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, }; @@ -2024,6 +2343,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .get_tx_data_len = rt73usb_get_tx_data_len, .kick_tx_queue = rt73usb_kick_tx_queue, .fill_rxdone = rt73usb_fill_rxdone, + .config_shared_key = rt73usb_config_shared_key, + .config_pairwise_key = rt73usb_config_pairwise_key, .config_filter = rt73usb_config_filter, .config_intf = rt73usb_config_intf, .config_erp = rt73usb_config_erp, diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 14849350101..868386c457f 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -92,6 +92,16 @@ #define PAIRWISE_KEY_TABLE_BASE 0x1200 #define PAIRWISE_TA_TABLE_BASE 0x1a00 +#define SHARED_KEY_ENTRY(__idx) \ + ( SHARED_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry)) ) +#define PAIRWISE_KEY_ENTRY(__idx) \ + ( PAIRWISE_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry)) ) +#define PAIRWISE_TA_ENTRY(__idx) \ + ( PAIRWISE_TA_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_pairwise_ta_entry)) ) + struct hw_key_entry { u8 key[16]; u8 tx_mic[8]; @@ -100,7 +110,8 @@ struct hw_key_entry { struct hw_pairwise_ta_entry { u8 address[6]; - u8 reserved[2]; + u8 cipher; + u8 reserved; } __attribute__ ((packed)); /* @@ -563,6 +574,10 @@ struct hw_pairwise_ta_entry { * SEC_CSR4: Pairwise key table lookup control. */ #define SEC_CSR4 0x30b0 +#define SEC_CSR4_ENABLE_BSS0 FIELD32(0x00000001) +#define SEC_CSR4_ENABLE_BSS1 FIELD32(0x00000002) +#define SEC_CSR4_ENABLE_BSS2 FIELD32(0x00000004) +#define SEC_CSR4_ENABLE_BSS3 FIELD32(0x00000008) /* * SEC_CSR5: shared key table security mode register. @@ -1010,8 +1025,10 @@ struct hw_pairwise_ta_entry { /* * Word4 + * ICV: Received ICV of originally encrypted. + * NOTE: This is a guess, the official definition is "reserved" */ -#define RXD_W4_RESERVED FIELD32(0xffffffff) +#define RXD_W4_ICV FIELD32(0xffffffff) /* * the above 20-byte is called RXINFO and will be DMAed to MAC RX block @@ -1033,17 +1050,10 @@ struct hw_pairwise_ta_entry { #define MAX_TXPOWER 31 #define DEFAULT_TXPOWER 24 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? \ - DEFAULT_TXPOWER : (__txpower); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ - (__txpower)); \ -}) +#define TXPOWER_FROM_DEV(__txpower) \ + (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER) #endif /* RT73USB_H */ diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl8180.h index 082a11f93be..8721282a818 100644 --- a/drivers/net/wireless/rtl8180.h +++ b/drivers/net/wireless/rtl8180.h @@ -24,20 +24,6 @@ #define ANAPARAM_PWR1_SHIFT 20 #define ANAPARAM_PWR1_MASK (0x7F << ANAPARAM_PWR1_SHIFT) -enum rtl8180_tx_desc_flags { - RTL8180_TX_DESC_FLAG_NO_ENC = (1 << 15), - RTL8180_TX_DESC_FLAG_TX_OK = (1 << 15), - RTL8180_TX_DESC_FLAG_SPLCP = (1 << 16), - RTL8180_TX_DESC_FLAG_RX_UNDER = (1 << 16), - RTL8180_TX_DESC_FLAG_MOREFRAG = (1 << 17), - RTL8180_TX_DESC_FLAG_CTS = (1 << 18), - RTL8180_TX_DESC_FLAG_RTS = (1 << 23), - RTL8180_TX_DESC_FLAG_LS = (1 << 28), - RTL8180_TX_DESC_FLAG_FS = (1 << 29), - RTL8180_TX_DESC_FLAG_DMA = (1 << 30), - RTL8180_TX_DESC_FLAG_OWN = (1 << 31) -}; - struct rtl8180_tx_desc { __le32 flags; __le16 rts_duration; @@ -52,23 +38,6 @@ struct rtl8180_tx_desc { u32 reserved[2]; } __attribute__ ((packed)); -enum rtl8180_rx_desc_flags { - RTL8180_RX_DESC_FLAG_ICV_ERR = (1 << 12), - RTL8180_RX_DESC_FLAG_CRC32_ERR = (1 << 13), - RTL8180_RX_DESC_FLAG_PM = (1 << 14), - RTL8180_RX_DESC_FLAG_RX_ERR = (1 << 15), - RTL8180_RX_DESC_FLAG_BCAST = (1 << 16), - RTL8180_RX_DESC_FLAG_PAM = (1 << 17), - RTL8180_RX_DESC_FLAG_MCAST = (1 << 18), - RTL8180_RX_DESC_FLAG_SPLCP = (1 << 25), - RTL8180_RX_DESC_FLAG_FOF = (1 << 26), - RTL8180_RX_DESC_FLAG_DMA_FAIL = (1 << 27), - RTL8180_RX_DESC_FLAG_LS = (1 << 28), - RTL8180_RX_DESC_FLAG_FS = (1 << 29), - RTL8180_RX_DESC_FLAG_EOR = (1 << 30), - RTL8180_RX_DESC_FLAG_OWN = (1 << 31) -}; - struct rtl8180_rx_desc { __le32 flags; __le32 flags2; diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index b7172a12c05..df7e78ee8a8 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -110,12 +110,12 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; u32 flags = le32_to_cpu(entry->flags); - if (flags & RTL8180_RX_DESC_FLAG_OWN) + if (flags & RTL818X_RX_DESC_FLAG_OWN) return; - if (unlikely(flags & (RTL8180_RX_DESC_FLAG_DMA_FAIL | - RTL8180_RX_DESC_FLAG_FOF | - RTL8180_RX_DESC_FLAG_RX_ERR))) + if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL | + RTL818X_RX_DESC_FLAG_FOF | + RTL818X_RX_DESC_FLAG_RX_ERR))) goto done; else { u32 flags2 = le32_to_cpu(entry->flags2); @@ -140,7 +140,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.band = dev->conf.channel->band; rx_status.mactime = le64_to_cpu(entry->tsft); rx_status.flag |= RX_FLAG_TSFT; - if (flags & RTL8180_RX_DESC_FLAG_CRC32_ERR) + if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; ieee80211_rx_irqsafe(dev, skb, &rx_status); @@ -154,10 +154,10 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) done: entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb)); - entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN | + entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | MAX_RX_SIZE); if (priv->rx_idx == 31) - entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR); + entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); priv->rx_idx = (priv->rx_idx + 1) % 32; } } @@ -173,7 +173,7 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) struct ieee80211_tx_info *info; u32 flags = le32_to_cpu(entry->flags); - if (flags & RTL8180_TX_DESC_FLAG_OWN) + if (flags & RTL818X_TX_DESC_FLAG_OWN) return; ring->idx = (ring->idx + 1) % ring->entries; @@ -185,7 +185,7 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) memset(&info->status, 0, sizeof(info->status)); if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (flags & RTL8180_TX_DESC_FLAG_TX_OK) + if (flags & RTL818X_TX_DESC_FLAG_TX_OK) info->flags |= IEEE80211_TX_STAT_ACK; else info->status.excessive_retries = 1; @@ -252,20 +252,20 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | - RTL8180_TX_DESC_FLAG_LS | + tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS | + RTL818X_TX_DESC_FLAG_LS | (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | skb->len; if (priv->r8185) - tx_flags |= RTL8180_TX_DESC_FLAG_DMA | - RTL8180_TX_DESC_FLAG_NO_ENC; + tx_flags |= RTL818X_TX_DESC_FLAG_DMA | + RTL818X_TX_DESC_FLAG_NO_ENC; if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { - tx_flags |= RTL8180_TX_DESC_FLAG_RTS; + tx_flags |= RTL818X_TX_DESC_FLAG_RTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { - tx_flags |= RTL8180_TX_DESC_FLAG_CTS; + tx_flags |= RTL818X_TX_DESC_FLAG_CTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } @@ -292,8 +292,8 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = info->control.alt_retry_rate_idx >= 0 ? - ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0; + entry->flags2 = info->control.retries[0].rate_idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; entry->retry_limit = info->control.retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); @@ -446,10 +446,10 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), MAX_RX_SIZE, PCI_DMA_FROMDEVICE); entry->rx_buf = cpu_to_le32(*mapping); - entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN | + entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | MAX_RX_SIZE); } - entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR); + entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); return 0; } @@ -615,7 +615,7 @@ static int rtl8180_start(struct ieee80211_hw *dev) reg |= RTL818X_CMD_TX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; return 0; err_free_rings: @@ -633,7 +633,7 @@ static void rtl8180_stop(struct ieee80211_hw *dev) u8 reg; int i; - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); @@ -661,11 +661,11 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev, { struct rtl8180_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MNTR) + if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: @@ -688,7 +688,7 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8180_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; priv->vif = NULL; } @@ -855,6 +855,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, priv = dev->priv; priv->pdev = pdev; + dev->max_altrates = 1; SET_IEEE80211_DEV(dev, &pdev->dev); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 5a9515c9996..e82bb4d289e 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -58,12 +58,6 @@ struct rtl8187b_rx_hdr { /* {rtl8187,rtl8187b}_tx_info is in skb */ -/* Tx flags are common between rtl8187 and rtl8187b */ -#define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15) -#define RTL8187_TX_FLAG_MORE_FRAG (1 << 17) -#define RTL8187_TX_FLAG_CTS (1 << 18) -#define RTL8187_TX_FLAG_RTS (1 << 23) - struct rtl8187_tx_hdr { __le32 flags; __le16 rts_duration; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index ca5deb6244e..431e3c78bf2 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -33,10 +33,13 @@ MODULE_LICENSE("GPL"); static struct usb_device_id rtl8187_table[] __devinitdata = { /* Asus */ {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, + /* Belkin */ + {USB_DEVICE(0x050d, 0x705e), .driver_info = DEVICE_RTL8187B}, /* Realtek */ {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, {USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B}, + {USB_DEVICE(0x0bda, 0x8198), .driver_info = DEVICE_RTL8187B}, /* Netgear */ {USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187}, {USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187}, @@ -187,18 +190,18 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) } flags = skb->len; - flags |= RTL8187_TX_FLAG_NO_ENCRYPT; + flags |= RTL818X_TX_DESC_FLAG_NO_ENC; flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) - flags |= RTL8187_TX_FLAG_MORE_FRAG; + flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { - flags |= RTL8187_TX_FLAG_RTS; + flags |= RTL818X_TX_DESC_FLAG_RTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, info); } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { - flags |= RTL8187_TX_FLAG_CTS; + flags |= RTL818X_TX_DESC_FLAG_CTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } @@ -354,7 +357,7 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.freq = dev->conf.channel->center_freq; rx_status.band = dev->conf.channel->band; rx_status.flag |= RX_FLAG_TSFT; - if (flags & (1 << 13)) + if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; ieee80211_rx_irqsafe(dev, skb, &rx_status); @@ -836,11 +839,11 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, struct rtl8187_priv *priv = dev->priv; int i; - if (priv->mode != IEEE80211_IF_TYPE_MNTR) + if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: @@ -865,7 +868,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, { struct rtl8187_priv *priv = dev->priv; mutex_lock(&priv->conf_mutex); - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; priv->vif = NULL; mutex_unlock(&priv->conf_mutex); } @@ -1057,7 +1060,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS; @@ -1184,6 +1187,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->max_signal = 65; } + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) printk(KERN_INFO "rtl8187: inconsistency between id with OEM" " info!\n"); diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h index 00900fe16fc..3538b15211b 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x.h @@ -193,4 +193,39 @@ struct rtl818x_rf_ops { void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); }; +/* Tx/Rx flags are common between RTL818X chips */ + +enum rtl818x_tx_desc_flags { + RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), + RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), + RTL818X_TX_DESC_FLAG_SPLCP = (1 << 16), + RTL818X_TX_DESC_FLAG_RX_UNDER = (1 << 16), + RTL818X_TX_DESC_FLAG_MOREFRAG = (1 << 17), + RTL818X_TX_DESC_FLAG_CTS = (1 << 18), + RTL818X_TX_DESC_FLAG_RTS = (1 << 23), + RTL818X_TX_DESC_FLAG_LS = (1 << 28), + RTL818X_TX_DESC_FLAG_FS = (1 << 29), + RTL818X_TX_DESC_FLAG_DMA = (1 << 30), + RTL818X_TX_DESC_FLAG_OWN = (1 << 31) +}; + +enum rtl818x_rx_desc_flags { + RTL818X_RX_DESC_FLAG_ICV_ERR = (1 << 12), + RTL818X_RX_DESC_FLAG_CRC32_ERR = (1 << 13), + RTL818X_RX_DESC_FLAG_PM = (1 << 14), + RTL818X_RX_DESC_FLAG_RX_ERR = (1 << 15), + RTL818X_RX_DESC_FLAG_BCAST = (1 << 16), + RTL818X_RX_DESC_FLAG_PAM = (1 << 17), + RTL818X_RX_DESC_FLAG_MCAST = (1 << 18), + RTL818X_RX_DESC_FLAG_QOS = (1 << 19), /* RTL8187(B) only */ + RTL818X_RX_DESC_FLAG_TRSW = (1 << 24), /* RTL8187(B) only */ + RTL818X_RX_DESC_FLAG_SPLCP = (1 << 25), + RTL818X_RX_DESC_FLAG_FOF = (1 << 26), + RTL818X_RX_DESC_FLAG_DMA_FAIL = (1 << 27), + RTL818X_RX_DESC_FLAG_LS = (1 << 28), + RTL818X_RX_DESC_FLAG_FS = (1 << 29), + RTL818X_RX_DESC_FLAG_EOR = (1 << 30), + RTL818X_RX_DESC_FLAG_OWN = (1 << 31) +}; + #endif /* RTL818X_H */ diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 98df9bc7836..852789ad34b 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -25,7 +25,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/firmware.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> @@ -34,9 +33,6 @@ #include "orinoco.h" -static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; -static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; - /********************************************************************/ /* Module stuff */ /********************************************************************/ @@ -71,161 +67,11 @@ struct orinoco_pccard { static int spectrum_cs_config(struct pcmcia_device *link); static void spectrum_cs_release(struct pcmcia_device *link); -/********************************************************************/ -/* Firmware downloader */ -/********************************************************************/ - -/* Position of PDA in the adapter memory */ -#define EEPROM_ADDR 0x3000 -#define EEPROM_LEN 0x200 -#define PDA_OFFSET 0x100 - -#define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET) -#define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2) - /* Constants for the CISREG_CCSR register */ #define HCR_RUN 0x07 /* run firmware after reset */ #define HCR_IDLE 0x0E /* don't run firmware after reset */ #define HCR_MEM16 0x10 /* memory width bit, should be preserved */ -/* - * AUX port access. To unlock the AUX port write the access keys to the - * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL - * register. Then read it and make sure it's HERMES_AUX_ENABLED. - */ -#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ -#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ -#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ - -#define HERMES_AUX_PW0 0xFE01 -#define HERMES_AUX_PW1 0xDC23 -#define HERMES_AUX_PW2 0xBA45 - -/* End markers */ -#define PDI_END 0x00000000 /* End of PDA */ -#define BLOCK_END 0xFFFFFFFF /* Last image block */ -#define TEXT_END 0x1A /* End of text header */ - -/* - * The following structures have little-endian fields denoted by - * the leading underscore. Don't access them directly - use inline - * functions defined below. - */ - -/* - * The binary image to be downloaded consists of series of data blocks. - * Each block has the following structure. - */ -struct dblock { - __le32 addr; /* adapter address where to write the block */ - __le16 len; /* length of the data only, in bytes */ - char data[0]; /* data to be written */ -} __attribute__ ((packed)); - -/* - * Plug Data References are located in in the image after the last data - * block. They refer to areas in the adapter memory where the plug data - * items with matching ID should be written. - */ -struct pdr { - __le32 id; /* record ID */ - __le32 addr; /* adapter address where to write the data */ - __le32 len; /* expected length of the data, in bytes */ - char next[0]; /* next PDR starts here */ -} __attribute__ ((packed)); - - -/* - * Plug Data Items are located in the EEPROM read from the adapter by - * primary firmware. They refer to the device-specific data that should - * be plugged into the secondary firmware. - */ -struct pdi { - __le16 len; /* length of ID and data, in words */ - __le16 id; /* record ID */ - char data[0]; /* plug data */ -} __attribute__ ((packed)); - - -/* Functions for access to little-endian data */ -static inline u32 -dblock_addr(const struct dblock *blk) -{ - return le32_to_cpu(blk->addr); -} - -static inline u32 -dblock_len(const struct dblock *blk) -{ - return le16_to_cpu(blk->len); -} - -static inline u32 -pdr_id(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->id); -} - -static inline u32 -pdr_addr(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->addr); -} - -static inline u32 -pdr_len(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->len); -} - -static inline u32 -pdi_id(const struct pdi *pdi) -{ - return le16_to_cpu(pdi->id); -} - -/* Return length of the data only, in bytes */ -static inline u32 -pdi_len(const struct pdi *pdi) -{ - return 2 * (le16_to_cpu(pdi->len) - 1); -} - - -/* Set address of the auxiliary port */ -static inline void -spectrum_aux_setaddr(hermes_t *hw, u32 addr) -{ - hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); - hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); -} - - -/* Open access to the auxiliary port */ -static int -spectrum_aux_open(hermes_t *hw) -{ - int i; - - /* Already open? */ - if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED) - return 0; - - hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); - hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); - hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); - hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE); - - for (i = 0; i < 20; i++) { - udelay(10); - if (hermes_read_reg(hw, HERMES_CONTROL) == - HERMES_AUX_ENABLED) - return 0; - } - - return -EBUSY; -} - #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) @@ -292,275 +138,29 @@ spectrum_reset(struct pcmcia_device *link, int idle) return -ENODEV; } +/********************************************************************/ +/* Device methods */ +/********************************************************************/ -/* - * Scan PDR for the record with the specified RECORD_ID. - * If it's not found, return NULL. - */ -static struct pdr * -spectrum_find_pdr(struct pdr *first_pdr, u32 record_id) -{ - struct pdr *pdr = first_pdr; - - while (pdr_id(pdr) != PDI_END) { - /* - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - return NULL; - - /* If the record ID matches, we are done */ - if (pdr_id(pdr) == record_id) - return pdr; - - pdr = (struct pdr *) pdr->next; - } - return NULL; -} - - -/* Process one Plug Data Item - find corresponding PDR and plug it */ -static int -spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi) -{ - struct pdr *pdr; - - /* Find the PDI corresponding to this PDR */ - pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi)); - - /* No match is found, safe to ignore */ - if (!pdr) - return 0; - - /* Lengths of the data in PDI and PDR must match */ - if (pdi_len(pdi) != pdr_len(pdr)) - return -EINVAL; - - /* do the actual plugging */ - spectrum_aux_setaddr(hw, pdr_addr(pdr)); - hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi)); - - return 0; -} - - -/* Read PDA from the adapter */ -static int -spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len) -{ - int ret; - int pda_size; - - /* Issue command to read EEPROM */ - ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); - if (ret) - return ret; - - /* Open auxiliary port */ - ret = spectrum_aux_open(hw); - if (ret) - return ret; - - /* read PDA from EEPROM */ - spectrum_aux_setaddr(hw, PDA_ADDR); - hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2); - - /* Check PDA length */ - pda_size = le16_to_cpu(pda[0]); - if (pda_size > pda_len) - return -EINVAL; - - return 0; -} - - -/* Parse PDA and write the records into the adapter */ -static int -spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, - __le16 *pda) -{ - int ret; - struct pdi *pdi; - struct pdr *first_pdr; - const struct dblock *blk = first_block; - - /* Skip all blocks to locate Plug Data References */ - while (dblock_addr(blk) != BLOCK_END) - blk = (struct dblock *) &blk->data[dblock_len(blk)]; - - first_pdr = (struct pdr *) blk; - - /* Go through every PDI and plug them into the adapter */ - pdi = (struct pdi *) (pda + 2); - while (pdi_id(pdi) != PDI_END) { - ret = spectrum_plug_pdi(hw, first_pdr, pdi); - if (ret) - return ret; - - /* Increment to the next PDI */ - pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return 0; -} - - -/* Load firmware blocks into the adapter */ -static int -spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block) -{ - const struct dblock *blk; - u32 blkaddr; - u32 blklen; - - blk = first_block; - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - - while (dblock_addr(blk) != BLOCK_END) { - spectrum_aux_setaddr(hw, blkaddr); - hermes_write_bytes(hw, HERMES_AUXDATA, blk->data, - blklen); - - blk = (struct dblock *) &blk->data[blklen]; - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - } - return 0; -} - - -/* - * Process a firmware image - stop the card, load the firmware, reset - * the card and make sure it responds. For the secondary firmware take - * care of the PDA - read it and then write it on top of the firmware. - */ static int -spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, - const unsigned char *image, int secondary) +spectrum_cs_hard_reset(struct orinoco_private *priv) { - int ret; - const unsigned char *ptr; - const struct dblock *first_block; - - /* Plug Data Area (PDA) */ - __le16 pda[PDA_WORDS]; - - /* Binary block begins after the 0x1A marker */ - ptr = image; - while (*ptr++ != TEXT_END); - first_block = (const struct dblock *) ptr; - - /* Read the PDA */ - if (secondary) { - ret = spectrum_read_pda(hw, pda, sizeof(pda)); - if (ret) - return ret; - } - - /* Stop the firmware, so that it can be safely rewritten */ - ret = spectrum_reset(link, 1); - if (ret) - return ret; - - /* Program the adapter with new firmware */ - ret = spectrum_load_blocks(hw, first_block); - if (ret) - return ret; - - /* Write the PDA to the adapter */ - if (secondary) { - ret = spectrum_apply_pda(hw, first_block, pda); - if (ret) - return ret; - } - - /* Run the firmware */ - ret = spectrum_reset(link, 0); - if (ret) - return ret; - - /* Reset hermes chip and make sure it responds */ - ret = hermes_init(hw); - - /* hermes_reset() should return 0 with the secondary firmware */ - if (secondary && ret != 0) - return -ENODEV; + struct orinoco_pccard *card = priv->card; + struct pcmcia_device *link = card->p_dev; - /* And this should work with any firmware */ - if (!hermes_present(hw)) - return -ENODEV; + /* Soft reset using COR and HCR */ + spectrum_reset(link, 0); return 0; } - -/* - * Download the firmware into the card, this also does a PCMCIA soft - * reset on the card, to make sure it's in a sane state. - */ -static int -spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link) -{ - int ret; - const struct firmware *fw_entry; - - if (request_firmware(&fw_entry, primary_fw_name, - &handle_to_dev(link)) != 0) { - printk(KERN_ERR PFX "Cannot find firmware: %s\n", - primary_fw_name); - return -ENOENT; - } - - /* Load primary firmware */ - ret = spectrum_dl_image(hw, link, fw_entry->data, 0); - release_firmware(fw_entry); - if (ret) { - printk(KERN_ERR PFX "Primary firmware download failed\n"); - return ret; - } - - if (request_firmware(&fw_entry, secondary_fw_name, - &handle_to_dev(link)) != 0) { - printk(KERN_ERR PFX "Cannot find firmware: %s\n", - secondary_fw_name); - return -ENOENT; - } - - /* Load secondary firmware */ - ret = spectrum_dl_image(hw, link, fw_entry->data, 1); - release_firmware(fw_entry); - if (ret) { - printk(KERN_ERR PFX "Secondary firmware download failed\n"); - } - - return ret; -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - static int -spectrum_cs_hard_reset(struct orinoco_private *priv) +spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) { struct orinoco_pccard *card = priv->card; struct pcmcia_device *link = card->p_dev; - int err; - if (!hermes_present(&priv->hw)) { - /* The firmware needs to be reloaded */ - if (spectrum_dl_firmware(&priv->hw, link) != 0) { - printk(KERN_ERR PFX "Firmware download failed\n"); - err = -ENODEV; - } - } else { - /* Soft reset using COR and HCR */ - spectrum_reset(link, 0); - } - - return 0; + return spectrum_reset(link, idle); } /********************************************************************/ @@ -582,7 +182,9 @@ spectrum_cs_probe(struct pcmcia_device *link) struct orinoco_private *priv; struct orinoco_pccard *card; - dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset); + dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + spectrum_cs_hard_reset, + spectrum_cs_stop_firmware); if (! dev) return -ENOMEM; priv = netdev_priv(dev); @@ -593,7 +195,7 @@ spectrum_cs_probe(struct pcmcia_device *link) link->priv = dev; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = orinoco_interrupt; link->irq.Instance = dev; @@ -633,6 +235,70 @@ static void spectrum_cs_detach(struct pcmcia_device *link) * device available to the system. */ +static int spectrum_cs_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->index == 0) + goto next_entry; + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* Do we need to allocate an interrupt? */ + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + goto next_entry; + } + return 0; + +next_entry: + pcmcia_disable_device(p_dev); + return -ENODEV; +}; + static int spectrum_cs_config(struct pcmcia_device *link) { @@ -641,16 +307,8 @@ spectrum_cs_config(struct pcmcia_device *link) struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; int last_fn, last_ret; - u_char buf[64]; - config_info_t conf; - tuple_t tuple; - cisparse_t parse; void __iomem *mem; - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link, &conf)); - /* * In this loop, we scan the CIS for configuration table * entries, each of which describes a valid card @@ -665,94 +323,14 @@ spectrum_cs_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - cistpl_cftable_entry_t dflt = { .index = 0 }; - - if ( (pcmcia_get_tuple_data(link, &tuple) != 0) - || (pcmcia_parse_tuple(link, &tuple, &parse) != 0)) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); - if(!ignore_cis_vcc) - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = - (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = - io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = - link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - } - - - /* If we got this far, we're cool! */ - - break; - - next_entry: - pcmcia_disable_device(link); - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret == CS_NO_MORE_ITEMS) { + last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); + if (last_ret) { + if (!ignore_cis_vcc) printk(KERN_ERR PFX "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " "ignore_cis_vcc=1 parameter.\n"); - goto cs_failed; - } + cs_error(link, RequestIO, last_ret); + goto failed; } /* @@ -784,7 +362,7 @@ spectrum_cs_config(struct pcmcia_device *link) dev->irq = link->irq.AssignedIRQ; card->node.major = card->node.minor = 0; - /* Reset card and download firmware */ + /* Reset card */ if (spectrum_cs_hard_reset(priv) != 0) { goto failed; } @@ -848,10 +426,11 @@ spectrum_cs_suspend(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; int err = 0; /* Mark the device as stopped, to block IO until later */ - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); err = __orinoco_down(dev); if (err) @@ -861,7 +440,7 @@ spectrum_cs_suspend(struct pcmcia_device *link) netif_device_detach(dev); priv->hw_unavailable++; - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); return err; } diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 136220b5ca8..e939a73ff79 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -4387,7 +4387,7 @@ MODULE_LICENSE("GPL"); * * Thanks go also to: * James Ashton (jaa101@syseng.anu.edu.au), - * Alan Cox (alan@redhat.com), + * Alan Cox (alan@lxorguk.ukuu.org.uk), * Allan Creighton (allanc@cs.usyd.edu.au), * Matthew Geier (matthew@cs.usyd.edu.au), * Remo di Giovanni (remo@cs.usyd.edu.au), diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index b33ac47dd8d..44d31bbf39e 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -186,7 +186,7 @@ * * Thanks go also to: * James Ashton <jaa101@syseng.anu.edu.au>, - * Alan Cox <alan@redhat.com>, + * Alan Cox <alan@lxorguk.ukuu.org.uk>, * Allan Creighton <allanc@cs.usyd.edu.au>, * Matthew Geier <matthew@cs.usyd.edu.au>, * Remo di Giovanni <remo@cs.usyd.edu.au>, diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 00a3559e5aa..e124b1d6267 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3702,7 +3702,7 @@ wv_pcmcia_reset(struct net_device * dev) #endif i = pcmcia_access_configuration_register(link, ®); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, AccessConfigurationRegister, i); return FALSE; @@ -3716,7 +3716,7 @@ wv_pcmcia_reset(struct net_device * dev) reg.Action = CS_WRITE; reg.Value = reg.Value | COR_SW_RESET; i = pcmcia_access_configuration_register(link, ®); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, AccessConfigurationRegister, i); return FALSE; @@ -3725,7 +3725,7 @@ wv_pcmcia_reset(struct net_device * dev) reg.Action = CS_WRITE; reg.Value = COR_LEVEL_IRQ | COR_CONFIG; i = pcmcia_access_configuration_register(link, ®); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, AccessConfigurationRegister, i); return FALSE; @@ -3903,7 +3903,7 @@ wv_pcmcia_config(struct pcmcia_device * link) do { i = pcmcia_request_io(link, &link->io); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, RequestIO, i); break; @@ -3914,7 +3914,7 @@ wv_pcmcia_config(struct pcmcia_device * link) * actually assign a handler to the interrupt. */ i = pcmcia_request_irq(link, &link->irq); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, RequestIRQ, i); break; @@ -3926,7 +3926,7 @@ wv_pcmcia_config(struct pcmcia_device * link) */ link->conf.ConfigIndex = 1; i = pcmcia_request_configuration(link, &link->conf); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, RequestConfiguration, i); break; @@ -3942,7 +3942,7 @@ wv_pcmcia_config(struct pcmcia_device * link) req.Base = req.Size = 0; req.AccessSpeed = mem_speed; i = pcmcia_request_window(&link, &req, &link->win); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, RequestWindow, i); break; @@ -3954,7 +3954,7 @@ wv_pcmcia_config(struct pcmcia_device * link) mem.CardOffset = 0; mem.Page = 0; i = pcmcia_map_mem_page(link->win, &mem); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, MapMemPage, i); break; @@ -4496,7 +4496,7 @@ wavelan_probe(struct pcmcia_device *p_dev) p_dev->io.IOAddrLines = 3; /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = wavelan_interrupt; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 377141995e3..68789c6e1ce 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -79,7 +79,7 @@ static int pc_debug = PCMCIA_DEBUG; module_param(pc_debug, int, 0); #define dprintk(n, format, args...) \ { if (pc_debug > (n)) \ - printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##args); } + printk(KERN_INFO "%s: " format "\n", __func__ , ##args); } #else #define dprintk(n, format, args...) #endif @@ -470,7 +470,7 @@ static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend) spin_unlock_irqrestore(&this->lock, flags); rc = wait_event_interruptible(this->wait, this->sig_pwr_mgmt_confirm.status != 255); - printk(KERN_INFO "%s: %s status=%d\n", __FUNCTION__, + printk(KERN_INFO "%s: %s status=%d\n", __func__, suspend ? "suspend" : "resume", this->sig_pwr_mgmt_confirm.status); goto out; @@ -1199,7 +1199,7 @@ static int wl3501_reset_board(struct wl3501_card *this) } WL3501_NOPLOOP(10); } - printk(KERN_WARNING "%s: failed to reset the board!\n", __FUNCTION__); + printk(KERN_WARNING "%s: failed to reset the board!\n", __func__); rc = -ENODEV; out: return rc; @@ -1250,7 +1250,7 @@ static int wl3501_init_firmware(struct wl3501_card *this) out: return rc; fail: - printk(KERN_WARNING "%s: failed!\n", __FUNCTION__); + printk(KERN_WARNING "%s: failed!\n", __func__); goto out; } @@ -1917,7 +1917,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev) p_dev->io.IOAddrLines = 5; /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = wl3501_interrupt; @@ -1977,10 +1977,10 @@ static int wl3501_config(struct pcmcia_device *link) link->io.BasePort1 = j; link->io.BasePort2 = link->io.BasePort1 + 0x10; i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) + if (i == 0) break; } - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestIO, i); goto failed; } diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile index cc36126cee8..1907eafb9b1 100644 --- a/drivers/net/wireless/zd1211rw/Makefile +++ b/drivers/net/wireless/zd1211rw/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o -zd1211rw-objs := zd_chip.o zd_ieee80211.o zd_mac.o \ +zd1211rw-objs := zd_chip.o zd_mac.o \ zd_rf_al2230.o zd_rf_rf2959.o \ zd_rf_al7230b.o zd_rf_uw2453.o \ zd_rf.o zd_usb.o diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 0acb5c34573..e0ac58b8ff1 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -28,7 +28,6 @@ #include "zd_def.h" #include "zd_chip.h" -#include "zd_ieee80211.h" #include "zd_mac.h" #include "zd_rf.h" diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c deleted file mode 100644 index d8dc41ec0e5..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c +++ /dev/null @@ -1,100 +0,0 @@ -/* ZD1211 USB-WLAN driver for Linux - * - * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> - * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> - * - * 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; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * In the long term, we'll probably find a better way of handling regulatory - * requirements outside of the driver. - */ - -#include <linux/kernel.h> -#include <net/mac80211.h> - -#include "zd_ieee80211.h" -#include "zd_mac.h" - -struct channel_range { - u8 regdomain; - u8 start; - u8 end; /* exclusive (channel must be less than end) */ -}; - -static const struct channel_range channel_ranges[] = { - { ZD_REGDOMAIN_FCC, 1, 12 }, - { ZD_REGDOMAIN_IC, 1, 12 }, - { ZD_REGDOMAIN_ETSI, 1, 14 }, - { ZD_REGDOMAIN_JAPAN, 1, 14 }, - { ZD_REGDOMAIN_SPAIN, 1, 14 }, - { ZD_REGDOMAIN_FRANCE, 1, 14 }, - - /* Japan originally only had channel 14 available (see CHNL_ID 0x40 in - * 802.11). However, in 2001 the range was extended to include channels - * 1-13. The ZyDAS devices still use the old region code but are - * designed to allow the extra channel access in Japan. */ - { ZD_REGDOMAIN_JAPAN_ADD, 1, 15 }, -}; - -static const struct channel_range *zd_channel_range(u8 regdomain) -{ - int i; - for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) { - const struct channel_range *range = &channel_ranges[i]; - if (range->regdomain == regdomain) - return range; - } - return NULL; -} - -#define CHAN_TO_IDX(chan) ((chan) - 1) - -static void unmask_bg_channels(struct ieee80211_hw *hw, - const struct channel_range *range, - struct ieee80211_supported_band *sband) -{ - u8 channel; - - for (channel = range->start; channel < range->end; channel++) { - struct ieee80211_channel *chan = - &sband->channels[CHAN_TO_IDX(channel)]; - chan->flags = 0; - } -} - -void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain) -{ - struct zd_mac *mac = zd_hw_mac(hw); - const struct channel_range *range; - - dev_dbg(zd_mac_dev(mac), "regdomain %#02x\n", regdomain); - - range = zd_channel_range(regdomain); - if (!range) { - /* The vendor driver overrides the regulatory domain and - * allowed channel registers and unconditionally restricts - * available channels to 1-11 everywhere. Match their - * questionable behaviour only for regdomains which we don't - * recognise. */ - dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: " - "%#02x. Defaulting to FCC.\n", regdomain); - range = zd_channel_range(ZD_REGDOMAIN_FCC); - } - - unmask_bg_channels(hw, range, &mac->band); -} - diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h deleted file mode 100644 index 26b79f19758..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h +++ /dev/null @@ -1,95 +0,0 @@ -/* ZD1211 USB-WLAN driver for Linux - * - * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> - * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> - * - * 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; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ZD_IEEE80211_H -#define _ZD_IEEE80211_H - -#include <net/mac80211.h> - -/* Additional definitions from the standards. - */ - -#define ZD_REGDOMAIN_FCC 0x10 -#define ZD_REGDOMAIN_IC 0x20 -#define ZD_REGDOMAIN_ETSI 0x30 -#define ZD_REGDOMAIN_SPAIN 0x31 -#define ZD_REGDOMAIN_FRANCE 0x32 -#define ZD_REGDOMAIN_JAPAN_ADD 0x40 -#define ZD_REGDOMAIN_JAPAN 0x41 - -enum { - MIN_CHANNEL24 = 1, - MAX_CHANNEL24 = 14, -}; - -void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain); - -#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80 - -struct ofdm_plcp_header { - u8 prefix[3]; - __le16 service; -} __attribute__((packed)); - -static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header) -{ - return header->prefix[0] & 0xf; -} - -/* The following defines give the encoding of the 4-bit rate field in the - * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to - * define the zd-rate values for OFDM. - * - * See the struct zd_ctrlset definition in zd_mac.h. - */ -#define ZD_OFDM_PLCP_RATE_6M 0xb -#define ZD_OFDM_PLCP_RATE_9M 0xf -#define ZD_OFDM_PLCP_RATE_12M 0xa -#define ZD_OFDM_PLCP_RATE_18M 0xe -#define ZD_OFDM_PLCP_RATE_24M 0x9 -#define ZD_OFDM_PLCP_RATE_36M 0xd -#define ZD_OFDM_PLCP_RATE_48M 0x8 -#define ZD_OFDM_PLCP_RATE_54M 0xc - -struct cck_plcp_header { - u8 signal; - u8 service; - __le16 length; - __le16 crc16; -} __attribute__((packed)); - -static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header) -{ - return header->signal; -} - -/* These defines give the encodings of the signal field in the 802.11b PLCP - * header. The signal field gives the bit rate of the following packet. Even - * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s - * rate to stay consistent with Zydas and our use of the term. - * - * Notify that these values are *not* used in the zd-rates. - */ -#define ZD_CCK_PLCP_SIGNAL_1M 0x0a -#define ZD_CCK_PLCP_SIGNAL_2M 0x14 -#define ZD_CCK_PLCP_SIGNAL_5M5 0x37 -#define ZD_CCK_PLCP_SIGNAL_11M 0x6e - -#endif /* _ZD_IEEE80211_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 4d7b98b0503..fe1867b25ff 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -3,7 +3,7 @@ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net> - * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu> + * Copyright (C) 2007-2008 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu> * * 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 @@ -29,9 +29,23 @@ #include "zd_def.h" #include "zd_chip.h" #include "zd_mac.h" -#include "zd_ieee80211.h" #include "zd_rf.h" +struct zd_reg_alpha2_map { + u32 reg; + char alpha2[2]; +}; + +static struct zd_reg_alpha2_map reg_alpha2_map[] = { + { ZD_REGDOMAIN_FCC, "US" }, + { ZD_REGDOMAIN_IC, "CA" }, + { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */ + { ZD_REGDOMAIN_JAPAN, "JP" }, + { ZD_REGDOMAIN_JAPAN_ADD, "JP" }, + { ZD_REGDOMAIN_SPAIN, "ES" }, + { ZD_REGDOMAIN_FRANCE, "FR" }, +}; + /* This table contains the hardware specific values for the modulation rates. */ static const struct ieee80211_rate zd_rates[] = { { .bitrate = 10, @@ -95,6 +109,21 @@ static void housekeeping_init(struct zd_mac *mac); static void housekeeping_enable(struct zd_mac *mac); static void housekeeping_disable(struct zd_mac *mac); +static int zd_reg2alpha2(u8 regdomain, char *alpha2) +{ + unsigned int i; + struct zd_reg_alpha2_map *reg_map; + for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) { + reg_map = ®_alpha2_map[i]; + if (regdomain == reg_map->reg) { + alpha2[0] = reg_map->alpha2[0]; + alpha2[1] = reg_map->alpha2[1]; + return 0; + } + } + return 1; +} + int zd_mac_preinit_hw(struct ieee80211_hw *hw) { int r; @@ -115,6 +144,7 @@ int zd_mac_init_hw(struct ieee80211_hw *hw) int r; struct zd_mac *mac = zd_hw_mac(hw); struct zd_chip *chip = &mac->chip; + char alpha2[2]; u8 default_regdomain; r = zd_chip_enable_int(chip); @@ -139,7 +169,9 @@ int zd_mac_init_hw(struct ieee80211_hw *hw) if (r) goto disable_int; - zd_geo_init(hw, mac->regdomain); + r = zd_reg2alpha2(mac->regdomain, alpha2); + if (!r) + regulatory_hint(hw->wiphy, alpha2, NULL); r = 0; disable_int: @@ -579,7 +611,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, q = &zd_hw_mac(hw)->ack_wait_queue; spin_lock_irqsave(&q->lock, flags); - for (skb = q->next; skb != (struct sk_buff *)q; skb = skb->next) { + skb_queue_walk(q, skb) { struct ieee80211_hdr *tx_hdr; tx_hdr = (struct ieee80211_hdr *)skb->data; @@ -684,15 +716,15 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, { struct zd_mac *mac = zd_hw_mac(hw); - /* using IEEE80211_IF_TYPE_INVALID to indicate no mode selected */ - if (mac->type != IEEE80211_IF_TYPE_INVALID) + /* using NL80211_IFTYPE_UNSPECIFIED to indicate no mode selected */ + if (mac->type != NL80211_IFTYPE_UNSPECIFIED) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_MESH_POINT: - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: mac->type = conf->type; break; default: @@ -706,7 +738,7 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct zd_mac *mac = zd_hw_mac(hw); - mac->type = IEEE80211_IF_TYPE_INVALID; + mac->type = NL80211_IFTYPE_UNSPECIFIED; zd_set_beacon_interval(&mac->chip, 0); zd_write_mac_addr(&mac->chip, NULL); } @@ -725,8 +757,8 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, int associated; int r; - if (mac->type == IEEE80211_IF_TYPE_MESH_POINT || - mac->type == IEEE80211_IF_TYPE_IBSS) { + if (mac->type == NL80211_IFTYPE_MESH_POINT || + mac->type == NL80211_IFTYPE_ADHOC) { associated = true; if (conf->changed & IEEE80211_IFCC_BEACON) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); @@ -753,7 +785,7 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, return 0; } -void zd_process_intr(struct work_struct *work) +static void zd_process_intr(struct work_struct *work) { u16 int_status; struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); @@ -923,7 +955,7 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) spin_lock_init(&mac->lock); mac->hw = hw; - mac->type = IEEE80211_IF_TYPE_INVALID; + mac->type = NL80211_IFTYPE_UNSPECIFIED; memcpy(mac->channels, zd_channels, sizeof(zd_channels)); memcpy(mac->rates, zd_rates, sizeof(zd_rates)); @@ -937,6 +969,11 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DB; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + hw->max_signal = 100; hw->queues = 1; hw->extra_tx_headroom = sizeof(struct zd_ctrlset); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 18c1d56d3dd..4c05d3ee4c3 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -25,7 +25,6 @@ #include <net/mac80211.h> #include "zd_chip.h" -#include "zd_ieee80211.h" struct zd_ctrlset { u8 modulation; @@ -187,6 +186,70 @@ struct zd_mac { unsigned int pass_ctrl:1; }; +#define ZD_REGDOMAIN_FCC 0x10 +#define ZD_REGDOMAIN_IC 0x20 +#define ZD_REGDOMAIN_ETSI 0x30 +#define ZD_REGDOMAIN_SPAIN 0x31 +#define ZD_REGDOMAIN_FRANCE 0x32 +#define ZD_REGDOMAIN_JAPAN_ADD 0x40 +#define ZD_REGDOMAIN_JAPAN 0x41 + +enum { + MIN_CHANNEL24 = 1, + MAX_CHANNEL24 = 14, +}; + +#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80 + +struct ofdm_plcp_header { + u8 prefix[3]; + __le16 service; +} __attribute__((packed)); + +static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header) +{ + return header->prefix[0] & 0xf; +} + +/* The following defines give the encoding of the 4-bit rate field in the + * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to + * define the zd-rate values for OFDM. + * + * See the struct zd_ctrlset definition in zd_mac.h. + */ +#define ZD_OFDM_PLCP_RATE_6M 0xb +#define ZD_OFDM_PLCP_RATE_9M 0xf +#define ZD_OFDM_PLCP_RATE_12M 0xa +#define ZD_OFDM_PLCP_RATE_18M 0xe +#define ZD_OFDM_PLCP_RATE_24M 0x9 +#define ZD_OFDM_PLCP_RATE_36M 0xd +#define ZD_OFDM_PLCP_RATE_48M 0x8 +#define ZD_OFDM_PLCP_RATE_54M 0xc + +struct cck_plcp_header { + u8 signal; + u8 service; + __le16 length; + __le16 crc16; +} __attribute__((packed)); + +static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header) +{ + return header->signal; +} + +/* These defines give the encodings of the signal field in the 802.11b PLCP + * header. The signal field gives the bit rate of the following packet. Even + * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s + * rate to stay consistent with Zydas and our use of the term. + * + * Notify that these values are *not* used in the zd-rates. + */ +#define ZD_CCK_PLCP_SIGNAL_1M 0x0a +#define ZD_CCK_PLCP_SIGNAL_2M 0x14 +#define ZD_CCK_PLCP_SIGNAL_5M5 0x37 +#define ZD_CCK_PLCP_SIGNAL_11M 0x6e + static inline struct zd_mac *zd_hw_mac(struct ieee80211_hw *hw) { return hw->priv; diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c index ec412931281..7207bfd2e6c 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.c +++ b/drivers/net/wireless/zd1211rw/zd_rf.c @@ -23,7 +23,7 @@ #include "zd_def.h" #include "zd_rf.h" -#include "zd_ieee80211.h" +#include "zd_mac.h" #include "zd_chip.h" static const char * const rfs[] = { diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index da8b7433e3a..a60ae86bd5c 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -58,6 +58,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index c749bdba214..c6948d8f53f 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -239,11 +239,14 @@ static void xennet_alloc_rx_buffers(struct net_device *dev) */ batch_target = np->rx_target - (req_prod - np->rx.rsp_cons); for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) { - skb = __netdev_alloc_skb(dev, RX_COPY_THRESHOLD, + skb = __netdev_alloc_skb(dev, RX_COPY_THRESHOLD + NET_IP_ALIGN, GFP_ATOMIC | __GFP_NOWARN); if (unlikely(!skb)) goto no_skb; + /* Align ip header to a 16 bytes boundary */ + skb_reserve(skb, NET_IP_ALIGN); + page = alloc_page(GFP_ATOMIC | __GFP_NOWARN); if (!page) { kfree_skb(skb); @@ -471,7 +474,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int offset = offset_in_page(data); unsigned int len = skb_headlen(skb); - frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE; + frags += DIV_ROUND_UP(offset + len, PAGE_SIZE); if (unlikely(frags > MAX_SKB_FRAGS + 1)) { printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n", frags); @@ -1794,10 +1797,10 @@ static struct xenbus_driver netfront = { static int __init netif_init(void) { - if (!is_running_on_xen()) + if (!xen_domain()) return -ENODEV; - if (is_initial_xendomain()) + if (xen_initial_domain()) return 0; printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n"); @@ -1809,7 +1812,7 @@ module_init(netif_init); static void __exit netif_exit(void) { - if (is_initial_xendomain()) + if (xen_initial_domain()) return; xenbus_unregister_driver(&netfront); |